feature/IO-3255-simplified-parts-management - Checkpoint
This commit is contained in:
@@ -55,6 +55,34 @@ const parseXml = async (xml, logger) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively strip `xml2js`-style { _: 'value', $: { ... } } nodes into plain strings.
|
||||
* @param {*} obj - Parsed XML object
|
||||
* @returns {*} Normalized object
|
||||
*/
|
||||
const normalizeXmlObject = (obj) => {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(normalizeXmlObject);
|
||||
}
|
||||
|
||||
if (typeof obj === "object" && obj !== null) {
|
||||
if (Object.keys(obj).length === 2 && "_" in obj && "$" in obj) {
|
||||
return normalizeXmlObject(obj._); // unwrap {_:"value",$:{...}} to just "value"
|
||||
}
|
||||
if (Object.keys(obj).length === 1 && "_" in obj) {
|
||||
return normalizeXmlObject(obj._); // unwrap {_:"value"}
|
||||
}
|
||||
|
||||
const normalized = {};
|
||||
for (const key in obj) {
|
||||
normalized[key] = normalizeXmlObject(obj[key]);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches the default order status for a bodyshop.
|
||||
* @param {string} shopId - The bodyshop UUID.
|
||||
@@ -81,7 +109,17 @@ const extractPartsTaxRates = (profile = {}) => {
|
||||
const partsTaxRates = {};
|
||||
|
||||
for (const code of KNOWN_PART_RATE_TYPES) {
|
||||
const rateInfo = rateInfos.find((r) => (r?.RateType || "").toUpperCase() === code);
|
||||
const rateInfo = rateInfos.find((r) => {
|
||||
const rateType =
|
||||
typeof r?.RateType === "string"
|
||||
? r.RateType
|
||||
: typeof r?.RateType === "object" && r?.RateType._ // xml2js sometimes uses _ for text content
|
||||
? r.RateType._
|
||||
: "";
|
||||
|
||||
return rateType.toUpperCase() === code;
|
||||
});
|
||||
|
||||
if (!rateInfo) {
|
||||
partsTaxRates[code] = {};
|
||||
continue;
|
||||
@@ -111,7 +149,6 @@ const extractPartsTaxRates = (profile = {}) => {
|
||||
|
||||
return partsTaxRates;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts job-related data from the XML request.
|
||||
* @param {object} rq - The VehicleDamageEstimateAddRq object.
|
||||
@@ -151,31 +188,44 @@ const extractJobData = (rq) => {
|
||||
* @param {string} shopId - The bodyshop UUID.
|
||||
* @returns {object} Owner data for insertion and inline use.
|
||||
*/
|
||||
/**
|
||||
* Extracts owner data from the XML request.
|
||||
* Falls back to Claimant if Owner is missing.
|
||||
* @param {object} rq - The VehicleDamageEstimateAddRq object.
|
||||
* @param {string} shopId - The bodyshop UUID.
|
||||
* @returns {object} Owner data for insertion and inline use.
|
||||
*/
|
||||
const extractOwnerData = (rq, shopId) => {
|
||||
const ownerParty = rq.AdminInfo?.Owner?.Party || {};
|
||||
const adr = ownerParty.PersonInfo?.Communications?.Address || {};
|
||||
// Prefer Owner, fallback to Claimant
|
||||
const ownerOrClaimant = rq.AdminInfo?.Owner?.Party || rq.AdminInfo?.Claimant?.Party || {};
|
||||
|
||||
const personInfo = ownerOrClaimant.PersonInfo || {};
|
||||
const personName = personInfo.PersonName || {};
|
||||
const address = personInfo.Communications?.Address || {};
|
||||
|
||||
let ownr_ph1, ownr_ph2, ownr_ea;
|
||||
|
||||
(Array.isArray(ownerParty.ContactInfo?.Communications)
|
||||
? ownerParty.ContactInfo.Communications
|
||||
: [ownerParty.ContactInfo?.Communications || {}]
|
||||
).forEach((c) => {
|
||||
const comms = Array.isArray(ownerOrClaimant.ContactInfo?.Communications)
|
||||
? ownerOrClaimant.ContactInfo.Communications
|
||||
: [ownerOrClaimant.ContactInfo?.Communications || {}];
|
||||
|
||||
for (const c of comms) {
|
||||
if (c.CommQualifier === "CP") ownr_ph1 = c.CommPhone;
|
||||
if (c.CommQualifier === "WP") ownr_ph2 = c.CommPhone;
|
||||
if (c.CommQualifier === "EM") ownr_ea = c.CommEmail;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
shopid: shopId,
|
||||
ownr_fn: ownerParty.PersonInfo?.PersonName?.FirstName || null,
|
||||
ownr_ln: ownerParty.PersonInfo?.PersonName?.LastName || null,
|
||||
ownr_co_nm: ownerParty.OrgInfo?.CompanyName || null,
|
||||
ownr_addr1: adr.Address1 || null,
|
||||
ownr_addr2: adr.Address2 || null,
|
||||
ownr_city: adr.City || null,
|
||||
ownr_st: adr.StateProvince || null,
|
||||
ownr_zip: adr.PostalCode || null,
|
||||
ownr_ctry: adr.Country || null,
|
||||
ownr_fn: personName.FirstName || null,
|
||||
ownr_ln: personName.LastName || null,
|
||||
ownr_co_nm: ownerOrClaimant.OrgInfo?.CompanyName || null,
|
||||
ownr_addr1: address.Address1 || null,
|
||||
ownr_addr2: address.Address2 || null,
|
||||
ownr_city: address.City || null,
|
||||
ownr_st: address.StateProvince || null,
|
||||
ownr_zip: address.PostalCode || null,
|
||||
ownr_ctry: address.Country || null,
|
||||
ownr_ph1,
|
||||
ownr_ph2,
|
||||
ownr_ea
|
||||
@@ -341,9 +391,9 @@ const extractVehicleData = (rq, shopId) => {
|
||||
v_mldgcode: desc.MldgCode || null,
|
||||
v_makecode: desc.MakeCode || null,
|
||||
trim_color: interior.ColorName || desc.TrimColor || null,
|
||||
db_v_code: desc.DatabaseCode || null,
|
||||
v_model_num: desc.ModelNum || null,
|
||||
v_odo: desc.OdometerInfo?.OdometerReading || null
|
||||
db_v_code: desc.DatabaseCode || null
|
||||
// v_model_num: desc.ModelNum || null
|
||||
// v_odo: desc.OdometerInfo?.OdometerReading || null
|
||||
};
|
||||
};
|
||||
|
||||
@@ -436,7 +486,7 @@ const partsManagementVehicleDamageEstimateAddRq = async (req, res) => {
|
||||
try {
|
||||
// Parse XML
|
||||
const payload = await parseXml(req.body, logger);
|
||||
const rq = payload.VehicleDamageEstimateAddRq;
|
||||
const rq = normalizeXmlObject(payload.VehicleDamageEstimateAddRq);
|
||||
if (!rq) {
|
||||
logger.log("parts-missing-root", "error");
|
||||
return res.status(400).send("Missing <VehicleDamageEstimateAddRq>");
|
||||
@@ -534,6 +584,7 @@ const partsManagementVehicleDamageEstimateAddRq = async (req, res) => {
|
||||
return res.status(200).json({ success: true, jobId: newJob.id });
|
||||
} catch (err) {
|
||||
logger.log("parts-route-error", "error", null, null, { error: err });
|
||||
console.dir({ err });
|
||||
return res.status(err.status || 500).json({ error: err.message || "Internal error" });
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user