Files
bodyshop/server/rr/rr-responsibility-centers.js
2025-11-17 17:30:52 -05:00

132 lines
4.3 KiB
JavaScript

// Helpers to use md_responsibility_centers (including RR GOG metadata)
// to build the data needed for ROLABOR + ROGOG lines.
/**
* Extracts responsibility center configuration into a convenient structure.
*
* Expects bodyshop.md_responsibility_centers to look like:
*
* {
* costs: [{ name, ... }],
* profits: [{ name, rr_gogcode, rr_item_type, rr_cust_txbl_flag, ... }],
* dms_defaults: {
* costs: { LAB: "Body Labor Cost", ... },
* profits: { LAB: "Body Labor Sales", ... }
* },
* defaults: {
* costs: { LAB: "Some Cost Center", ... },
* profits: { LAB: "Some Profit Center", ... }
* }
* }
*/
function extractRrResponsibilityCenters(bodyshop = {}) {
const centers = bodyshop.md_responsibility_centers || {};
const { costs = [], profits = [], dms_defaults = {}, defaults = {} } = centers;
const indexByName = (arr = []) =>
(arr || []).reduce((acc, center) => {
if (center && center.name) {
acc[center.name] = center;
}
return acc;
}, {});
return {
costsByName: indexByName(costs),
profitsByName: indexByName(profits),
dmsCostDefaults: (dms_defaults && dms_defaults.costs) || {},
dmsProfitDefaults: (dms_defaults && dms_defaults.profits) || {},
defaultCosts: defaults.costs || {},
defaultProfits: defaults.profits || {}
};
}
/**
* Resolve cost + profit centers for a given internal code (ATS/LAB/etc.).
* Prioritizes dms_defaults, then defaults.
*
* @param {string} code
* @param {ReturnType<typeof extractRrResponsibilityCenters>} cfg
* @returns {{ costCenter: object|null, profitCenter: object|null }}
*/
function resolveCentersForCode(code, cfg) {
if (!code || !cfg) return { costCenter: null, profitCenter: null };
const costCenterName = cfg.dmsCostDefaults[code] || cfg.defaultCosts[code] || null;
const profitCenterName = cfg.dmsProfitDefaults[code] || cfg.defaultProfits[code] || null;
const costCenter = costCenterName && cfg.costsByName[costCenterName] ? cfg.costsByName[costCenterName] : null;
const profitCenter =
profitCenterName && cfg.profitsByName[profitCenterName] ? cfg.profitsByName[profitCenterName] : null;
return { costCenter, profitCenter };
}
/**
* Build a single RR GOG line payload from a jobline + code.
*
* NOTE: This returns a neutral JS object. You still need to map it into
* the exact Mustache / XML shape used for AllGogLineItmInfo.
*
* @param {Object} params
* @param {Object} params.jobline // jobline record from Hasura
* @param {string} params.code // e.g. "LAB", "ATS", ...
* @param {object} params.centersConfig // result of extractRrResponsibilityCenters()
* @param {number} params.sale // CustPrice
* @param {number} params.cost // DollarCost
*/
function buildRrGogLine({ jobline, code, centersConfig, sale, cost }) {
const { profitCenter } = resolveCentersForCode(code, centersConfig);
if (!profitCenter || !profitCenter.rr_gogcode) {
throw new Error('RR: missing rr_gogcode for profit center mapping of code "' + code + '"');
}
return {
// For your own reference:
code,
joblineId: jobline && jobline.id,
// Fields you ultimately care about for ROGOG:
BreakOut: profitCenter.rr_gogcode, // GOG code / BreakOut
ItemType: profitCenter.rr_item_type || "G", // P / G / F / ...
CustTxblNTxblFlag: profitCenter.rr_cust_txbl_flag || "T", // T/N
CustPrice: Number(sale || 0),
DollarCost: Number(cost || 0),
// Surface full profit center in case templates / logs need it:
profitCenter
};
}
/**
* Build a minimal RR labor (ROLABOR) line "shell".
* Amounts are zero if all financials are in GOG.
*
* @param {Object} params
* @param {Object} params.job // job record (for RO header context)
* @param {string} params.opCode // global opcode (already resolved)
* @param {Object} [params.profitCenter] // optional profit center for context
*/
function buildRrLaborLine({ job, opCode, profitCenter }) {
if (!opCode) {
throw new Error("RR: opCode is required to build ROLABOR line");
}
return {
jobId: job && job.id,
OpCode: opCode,
PayType: "Cust", // always Cust per your notes
CustPrice: 0,
DollarCost: 0,
profitCenter
};
}
module.exports = {
extractRrResponsibilityCenters,
resolveCentersForCode,
buildRrGogLine,
buildRrLaborLine
};