Checkpoint
This commit is contained in:
131
server/rr/rr-responsibility-centers.js
Normal file
131
server/rr/rr-responsibility-centers.js
Normal file
@@ -0,0 +1,131 @@
|
||||
// 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
|
||||
};
|
||||
Reference in New Issue
Block a user