Fortellis logic deduplication

This commit is contained in:
Patrick Fic
2025-12-16 14:30:29 -08:00
parent 7ea81465ee
commit faf00ca845
6 changed files with 131 additions and 30 deletions

2
.gitignore vendored
View File

@@ -114,7 +114,7 @@ firebase/.env
!.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml !.elasticbeanstalk/*.global.yml
logs/oAuthClient-log.log logs/oAuthClient-log.log
logs/*
.node-persist/** .node-persist/**

View File

@@ -1,4 +1,4 @@
import { Button } from "antd"; import { Button, Space } from "antd";
import axios from "axios"; import axios from "axios";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -42,9 +42,29 @@ export function DmsCdkMakesRefetch({ currentUser, bodyshop }) {
setLoading(false); setLoading(false);
}; };
const handleGetCOA = async () => {
try {
setLoading(true);
await axios.post(`cdk/fortellis/getCOA`, {
cdk_dealerid: bodyshop.cdk_dealerid,
bodyshopid: bodyshop.id
});
} catch (error) {
console.error(error);
}
setLoading(false);
};
return ( return (
<Button loading={loading} onClick={handleRefetch}> <Space>
{t("jobs.actions.dms.refetchmakesmodels")} <Button loading={loading} onClick={handleRefetch}>
</Button> {t("jobs.actions.dms.refetchmakesmodels")}
</Button>
<Button loading={loading} onClick={handleGetCOA}>
Get COA
</Button>
</Space>
); );
} }

View File

@@ -131,6 +131,7 @@ async function GetFortellisMakes(req, cdk_dealerid) {
socket: { emit: () => null }, socket: { emit: () => null },
jobid: null, jobid: null,
body: {}, body: {},
debug: true,
SubscriptionObject: { SubscriptionObject: {
SubscriptionID: cdk_dealerid SubscriptionID: cdk_dealerid
} }
@@ -147,6 +148,45 @@ async function GetFortellisMakes(req, cdk_dealerid) {
} }
} }
async function GetFortellisCOA(req) {
const { cdk_dealerid } = req.body;
try {
logger.log("fortellis-get-COA", "DEBUG", req.user?.email, null, {
cdk_dealerid
});
const result = await MakeFortellisCall({
...FortellisActions.GetCOA,
headers: {},
redisHelpers: {
setSessionTransactionData: () => {
return null;
},
getSessionTransactionData: () => {
return null;
}
},
socket: { emit: () => null },
jobid: null,
body: {},
debug: true,
SubscriptionObject: {
SubscriptionID: cdk_dealerid
}
});
return result.data?.data;
} catch (error) {
logger.log("fortellis-get-COA-error", "ERROR", req.user?.email, null, {
cdk_dealerid,
error: error.message,
stack: error.stack
});
throw new Error(error);
}
}
exports.fortellisCOA = GetFortellisCOA
exports.fortellis = async function ReloadFortellisMakes(req, res) { exports.fortellis = async function ReloadFortellisMakes(req, res) {
const { bodyshopid, cdk_dealerid } = req.body; const { bodyshopid, cdk_dealerid } = req.body;
try { try {

View File

@@ -312,6 +312,27 @@ function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
async function writeFortellisLogToFile(logObject) {
try {
const logsDir = path.join(process.cwd(), 'logs');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `fortellis-${timestamp}.json`;
const filepath = path.join(logsDir, filename);
console.log(`[writeFortellisLogToFile] Writing to: ${filepath}`);
console.log(`[writeFortellisLogToFile] process.cwd(): ${process.cwd()}`);
// Ensure logs directory exists
await fs.mkdir(logsDir, { recursive: true });
// Write log object to file
await fs.writeFile(filepath, JSON.stringify(logObject, null, 2), 'utf8');
console.log(`Fortellis log written to: ${filepath}`,);
} catch (err) {
console.error('Failed to write Fortellis log to file:', err);
}
}
async function WriteToIOEventLog({ apiName, type, fullUrl, bodyshopid, useremail, logger, socket }) { async function WriteToIOEventLog({ apiName, type, fullUrl, bodyshopid, useremail, logger, socket }) {
try { try {
@@ -351,6 +372,7 @@ async function WriteToIOEventLog({ apiName, type, fullUrl, bodyshopid, useremail
} }
} }
const isProduction = process.env.NODE_ENV === "production"; const isProduction = process.env.NODE_ENV === "production";
//Get requests should have the trailing slash as they are used that way in the calls. //Get requests should have the trailing slash as they are used that way in the calls.
@@ -427,8 +449,10 @@ const FortellisActions = {
}, },
GetCOA: { GetCOA: {
type: "get", type: "get",
apiName: "CDK Drive Post Accounts GL WIP", apiName: "CDK Drive Get Chart of Accounts",
url: `https://api.fortellis.io/cdk-test/drive/chartofaccounts/v2/bulk/`, url: isProduction
? "https://api.fortellis.io/cdk/drive/chartofaccounts/v2/bulk"
: "https://api.fortellis.io/cdk-test/drive/chartofaccounts/v2/bulk",
waitForResult: true waitForResult: true
}, },
StartWip: { StartWip: {

View File

@@ -189,7 +189,17 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
let DMSCust; let DMSCust;
if (selectedCustomerId) { if (selectedCustomerId) {
CreateFortellisLogEvent(socket, "DEBUG", `{3.1} Querying the Customer using Customer ID: ${selectedCustomerId}`); CreateFortellisLogEvent(socket, "DEBUG", `{3.1} Querying the Customer using Customer ID: ${selectedCustomerId}`);
DMSCust = await QueryDmsCustomerById({ socket, redisHelpers, JobData, CustomerId: selectedCustomerId }); //TODO: Optimize here - if selected ID, we already have the customer information. Prevent an extra call to Fortellis.
//Get cust list from Redis. Return the item
const DMSCustList = await getSessionTransactionData(
socket.id,
getTransactionType(jobid),
FortellisCacheEnums.DMSCustList
);
const existingCustomerInDMSCustList = DMSCustList.find((c) => c.customerId === selectedCustomerId);
DMSCust = existingCustomerInDMSCustList || {
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),
@@ -197,6 +207,8 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
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 });
@@ -215,26 +227,32 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
CreateFortellisLogEvent(socket, "DEBUG", `{4.1} Inserting new vehicle with ID: ID ${DMSVid.vehiclesVehId}`); CreateFortellisLogEvent(socket, "DEBUG", `{4.1} Inserting new vehicle with ID: ID ${DMSVid.vehiclesVehId}`);
DMSVeh = await InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMSVid, DMSCust }); DMSVeh = await InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMSVid, DMSCust });
} else { } else {
CreateFortellisLogEvent(socket, "DEBUG", `{4.2} Querying Existing Vehicle using ID ${DMSVid.vehiclesVehId}`); DMSVeh = await getSessionTransactionData(
DMSVeh = await QueryDmsVehicleById({ socket, redisHelpers, JobData, DMSVid });
CreateFortellisLogEvent(socket, "DEBUG", `{4.3} Updating Existing Vehicle to associate to owner.`);
DMSVeh = await UpdateDmsVehicle({
socket,
redisHelpers,
JobData,
DMSVeh,
DMSCust,
selectedCustomerId,
txEnvelope
});
await setSessionTransactionData(
socket.id, socket.id,
getTransactionType(jobid), getTransactionType(jobid),
FortellisCacheEnums.DMSVeh, FortellisCacheEnums.DMSVeh
DMSVeh, )
defaultFortellisTTL CreateFortellisLogEvent(socket, "DEBUG", `{4.3} Updating Existing Vehicle to associate to owner.`);
); //TODO: This should be immutable probably.F
//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")) {
DMSVeh = await UpdateDmsVehicle({
socket,
redisHelpers,
JobData,
DMSVeh,
DMSCust,
selectedCustomerId,
txEnvelope
});
await setSessionTransactionData(
socket.id,
getTransactionType(jobid),
FortellisCacheEnums.DMSVeh,
DMSVeh,
defaultFortellisTTL
);
}
} }
// const DMSVehHistory = await InsertServiceVehicleHistory({ socket, redisHelpers, JobData }); // const DMSVehHistory = await InsertServiceVehicleHistory({ socket, redisHelpers, JobData });
// await setSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSVehHistory, DMSVehHistory, defaultFortellisTTL); // await setSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSVehHistory, DMSVehHistory, defaultFortellisTTL);
@@ -293,7 +311,6 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
// //Get the error code // //Get the error code
CreateFortellisLogEvent(socket, "DEBUG", `{6.1} Getting errors for Transaction ID ${DMSTransHeader.transID}`); CreateFortellisLogEvent(socket, "DEBUG", `{6.1} Getting errors for Transaction ID ${DMSTransHeader.transID}`);
await QueryDmsErrWip({ socket, redisHelpers, JobData });
const DmsError = await QueryDmsErrWip({ socket, redisHelpers, JobData }); const DmsError = await QueryDmsErrWip({ socket, redisHelpers, JobData });
// //Delete the transaction // //Delete the transaction
@@ -301,7 +318,7 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
await DeleteDmsWip({ socket, redisHelpers, JobData }); await DeleteDmsWip({ socket, redisHelpers, JobData });
DmsError.errLine.map( DmsError.errMsg.map(
(e) => (e) =>
e !== null && e !== null &&
e !== "" && e !== "" &&
@@ -310,7 +327,7 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
await InsertFailedExportLog({ await InsertFailedExportLog({
socket, socket,
JobData, JobData,
error: DmsError.errLine error: DmsError.errMsg
}); });
} }
} }
@@ -1027,7 +1044,6 @@ async function InsertDmsStartWip({ socket, redisHelpers, JobData }) {
// userID: "partprgm", // userID: "partprgm",
// userName: "PROGRAM, PARTNER" // userName: "PROGRAM, PARTNER"
}, },
//overrideDepartmentId: "D100152198" //TODO: REMOVE AFTER TESTING
}); });
return result; return result;
} catch (error) { } catch (error) {

View File

@@ -9,6 +9,7 @@ router.use(validateFirebaseIdTokenMiddleware);
router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default); router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default);
router.post("/fortellis/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.fortellis); router.post("/fortellis/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.fortellis);
router.post("/fortellis/getCOA", withUserGraphQLClientMiddleware, cdkGetMake.fortellisCOA);
router.post("/calculate-allocations", withUserGraphQLClientMiddleware, cdkCalculateAllocations.defaultRoute); router.post("/calculate-allocations", withUserGraphQLClientMiddleware, cdkCalculateAllocations.defaultRoute);
module.exports = router; module.exports = router;