Compare commits
No commits in common. "43e64a1533a1f6aaa76455fc8115353cf1e6ed04" and "32217d52c4a7e4e5353989ebb20b79afd5afc767" have entirely different histories.
43e64a1533
...
32217d52c4
2
api.ts
2
api.ts
@ -52,7 +52,7 @@ router.get('/dseg_price/:billcode/:shipcode/:stlc/:dseg/:qty', async (ctx) => {
|
|||||||
const { billcode, shipcode, stlc, dseg, qty } = ctx.params;
|
const { billcode, shipcode, stlc, dseg, qty } = ctx.params;
|
||||||
const result = await client.queryObject({args: [billcode, shipcode, stlc, dseg, qty], text: query_dseg} );
|
const result = await client.queryObject({args: [billcode, shipcode, stlc, dseg, qty], text: query_dseg} );
|
||||||
const ag = apply_guidance(result.rows[0]["doc"]);
|
const ag = apply_guidance(result.rows[0]["doc"]);
|
||||||
ctx.response.body = ag.guidance.finalPrice.Snapped;
|
ctx.response.body = ag.guidance.FinalReason;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(router.routes());
|
app.use(router.routes());
|
||||||
|
@ -14,109 +14,110 @@ export function apply_guidance(doc: any) {
|
|||||||
return match ? match.adj : null;
|
return match ? match.adj : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function lowestPrice(priceObject) {
|
//let custPrice null;
|
||||||
let Price = Infinity;
|
//let custReason null;
|
||||||
let Reason = '';
|
//let cvolPrice null;
|
||||||
let Source = '';
|
//let cvolReason null;
|
||||||
let Snapped = Infinity;
|
//let markPrice null;
|
||||||
|
//let markReason null;
|
||||||
|
//let targPrice null;
|
||||||
|
//let targReason null;
|
||||||
|
|
||||||
//console.log(priceObject["targ"][0]);
|
|
||||||
// Iterate over each property in the object
|
|
||||||
for (let key in priceObject) {
|
|
||||||
// Ignore markPrice unless targPrice is null
|
|
||||||
if (key === "mark" && priceObject["targ"][0] !== null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (priceObject.hasOwnProperty(key)) {
|
|
||||||
let [cprice, creason, csource, csnap] = priceObject[key];
|
|
||||||
// Check if the current price is lower than the found so far
|
|
||||||
if (cprice && cprice < Price) {
|
|
||||||
Price = cprice;
|
|
||||||
Reason = creason;
|
|
||||||
Source = csource;
|
|
||||||
Snapped = csnap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {Reason, Price, Source, Snapped};
|
|
||||||
}
|
|
||||||
|
|
||||||
function ceiling(value, significance) {
|
|
||||||
return Math.ceil(value / significance) * significance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function r5(value) {
|
|
||||||
return Number(value.toFixed(5));
|
|
||||||
}
|
|
||||||
|
|
||||||
function pp(value) {
|
|
||||||
// Multiplies by 1000 and rounds to the nearest 2 decimals
|
|
||||||
var result = Math.round(value * 1000 * 100) / 100;
|
|
||||||
|
|
||||||
// Converts the number to a string with commas for thousand separators
|
|
||||||
return result.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------extract incoming data------------------------------------------------------
|
|
||||||
const targetPrice = doc.pricing?.v1tp ?? doc.pricing?.v0tp;
|
const targetPrice = doc.pricing?.v1tp ?? doc.pricing?.v0tp;
|
||||||
const priceBand = doc.pricing?.v1stdv ?? doc.pricing?.v0stdv;
|
const priceBand = doc.pricing?.v1stdv ?? doc.pricing?.v0stdv;
|
||||||
const earlyCustPrice = doc.hist?.cust?.early_price;
|
const earlyPrice = doc.hist?.cust?.early_price;
|
||||||
const earlyCustSeason = doc.hist?.cust?.early_season;
|
const earlySeason = doc.hist?.cust?.early_season;
|
||||||
const earlyMarkPrice = doc.hist?.market?.early_price;
|
const bridgePremium = doc.pricing?.bridgePremium ?? 1.00000;
|
||||||
const earlyMarkSeason = doc.hist?.market?.early_season;
|
|
||||||
const bridgePremium = doc.pricing?.bridgePremium;
|
|
||||||
const bridgedPrice = Number((earlyCustPrice * (bridgePremium ?? 1.00)).toFixed(5));
|
|
||||||
const altHist = doc.hist?.cust?.ds;
|
const altHist = doc.hist?.cust?.ds;
|
||||||
const iidx = doc.pricing?.iidx;
|
const iidx = doc.pricing?.iidx;
|
||||||
const curr = doc.customer?.curr;
|
const curr = doc.customer?.curr;
|
||||||
const fxrate = doc.customer?.fxrate ?? 1.0;
|
const fxrate = doc.customer?.fxrate ?? 1.0;
|
||||||
const qty = doc.inputs?.qty;
|
const qty = doc.inputs?.qty;
|
||||||
const pltq = doc.product?.pltq;
|
const pltq = doc.product?.pltq;
|
||||||
|
let anchorPrice = null;
|
||||||
|
let anchorSource = null;
|
||||||
|
let custPrice = null;
|
||||||
|
let custSource = null;
|
||||||
|
let guidance = {};
|
||||||
|
let calcCeiling = null;
|
||||||
|
let finalReasonUSD = "";
|
||||||
|
let finalPriceUSD = null;
|
||||||
|
let finalReason = "";
|
||||||
|
let finalPrice = null;
|
||||||
|
let ltp = qty < pltq ? 1.15 : null;
|
||||||
|
let increase = null;
|
||||||
const inflation = Math.max(...Object.keys(iidx).map(Number));
|
const inflation = Math.max(...Object.keys(iidx).map(Number));
|
||||||
const inflationFactor = iidx[inflation];
|
const inflationFactor = iidx[inflation] + 1;
|
||||||
const list = doc.pricing?.list && doc.product?.itemrel === "2" ? doc.pricing?.list : null;
|
const list = doc.pricing?.list && doc.product?.itemrel === "2" ? doc.pricing?.list : null;
|
||||||
const listUSD = list ? list * fxrate :null;
|
|
||||||
|
|
||||||
// ------------------calculate price adders------------------------------------------------------
|
//-------set basic customer pricing--------------
|
||||||
let ltp = qty < pltq ? 0.15 : null;
|
custPrice = Number((earlyPrice * bridgePremium).toFixed(5));
|
||||||
let anchor_sd = priceBand ? ((bridgedPrice - targetPrice) / priceBand).toFixed(2) : 0
|
anchorPrice = custPrice;
|
||||||
|
let anchor_sd = priceBand ? ((anchorPrice - targetPrice) / priceBand).toFixed(2) : 0
|
||||||
let optimization = getAdjValue(anchor_sd);
|
let optimization = getAdjValue(anchor_sd);
|
||||||
let custAdder = (ltp ?? 0) + optimization + inflationFactor;
|
|
||||||
let markAdder = (ltp ?? 0) + inflationFactor;
|
|
||||||
let inflReason = (inflationFactor ?? 0) !== 0 ? ` + ${(inflationFactor * 100).toFixed(1)}% infl`: "";
|
|
||||||
let ltpReason = ltp ? ` + ${(ltp * 100).toFixed(1)}% ltp` : "";
|
|
||||||
let optReason = (optimization ?? 0) !== 0 ? ` + ${(optimization * 100).toFixed(1)}% opt`: "";
|
|
||||||
let custAddReason = `${inflReason}${ltpReason}${optReason}`;
|
|
||||||
let markAddReason = `${inflReason}${ltpReason}`;
|
|
||||||
|
|
||||||
// ------------------start building price options------------------------------------------------
|
|
||||||
|
|
||||||
let snap = .0005;
|
// ------if there is not target price just exit---------------
|
||||||
|
if (!targetPrice) {
|
||||||
let custPrice = r5(bridgedPrice * (1 + custAdder));
|
anchorSource = "No target pricing setup";
|
||||||
let custSeason = earlyCustSeason;
|
guidance.FinalReason = "No target pricing setup";
|
||||||
let custReason = bridgePremium
|
} else {
|
||||||
? `${custSeason} (similar ${altHist} price ${pp(earlyCustPrice)} x ${bridgePremium} = ${pp(bridgedPrice)})${custAddReason}`
|
// if there is no customer anchor price use target
|
||||||
: `${custSeason} price ${pp(bridgedPrice)}${custAddReason}`;
|
if (earlyPrice) {
|
||||||
let markPrice = r5(earlyMarkPrice * (1 + markAdder));
|
// translate alternate product history to current product quoted
|
||||||
let markReason = `${earlyMarkSeason} ASP ${pp(earlyMarkPrice)}${markAddReason}`;
|
// --------if the price needs bridged, add the details to the description--------
|
||||||
let targPrice = targetPrice ? r5(targetPrice * (1 + markAdder)) : null;
|
if (bridgePremium === 1) {
|
||||||
let targReason = `Target price ${pp(targetPrice)}${markAddReason}`;
|
anchorSource = earlySeason + ' Price ' + earlyPrice;
|
||||||
let listPrice = listUSD;
|
custSource = anchorSource;
|
||||||
let listReason = fxrate === 1 ? "" : `list ${pp(list)} CAD ${pp(listUSD)} USD`
|
} else {
|
||||||
|
anchorSource = earlySeason + ' Similar (' + altHist + ') Price ' + earlyPrice + ' x ' + bridgePremium + ' = ' + anchorPrice;
|
||||||
let prices = {
|
custSource = anchorSource;
|
||||||
cust: [custPrice, custReason, "cust", ceiling(custPrice,snap)],
|
|
||||||
mark: [markPrice, markReason, "mark", ceiling(markPrice,snap)],
|
|
||||||
targ: [targPrice, targReason, "targ", ceiling(targPrice,snap)],
|
|
||||||
list: [listPrice, listReason, "list", ceiling(listPrice,snap)]
|
|
||||||
}
|
}
|
||||||
|
// --------after the early price is translated see if target is still less-------
|
||||||
let finalPrice = lowestPrice(prices);
|
if (targetPrice < anchorPrice) {
|
||||||
let guidance = {
|
anchorSource = `Target Price ${targetPrice}`;
|
||||||
prices
|
anchorPrice = targetPrice;
|
||||||
,finalPrice
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
anchorPrice = targetPrice;
|
||||||
|
anchorSource = `Target Price ${targetPrice}`;
|
||||||
|
}
|
||||||
|
//------get the most relevant inflation factor number---------------------------------
|
||||||
|
//------anchor x inflation / fxrate---------------------------------------------------
|
||||||
|
let calcPriceUSD = parseFloat((anchorPrice * inflationFactor).toFixed(5));
|
||||||
|
let calcPrice = parseFloat((calcPriceUSD / fxrate).toFixed(5));
|
||||||
|
if (calcPrice >= list && list) {
|
||||||
|
calcCeiling = "Cap At List";
|
||||||
|
//multiply list by FX to get to USD if in CAD
|
||||||
|
finalPrice = list;
|
||||||
|
if (curr === "CA") {
|
||||||
|
finalReason = `${anchorSource} x ${inflationFactor} / ${fxrate} FX = ${calcPrice} CAD, cap at list ${list} CAD`;
|
||||||
|
} else {
|
||||||
|
finalReason = `${anchorSource} x ${inflationFactor} = ${calcPrice}, cap at list ${list}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalPrice = calcPrice;
|
||||||
|
finalPriceUSD = calcPriceUSD;
|
||||||
|
if (curr === "CA") {
|
||||||
|
finalReason = `${anchorSource} x ${inflationFactor} / ${fxrate} FX = ${calcPrice} CAD`;
|
||||||
|
} else {
|
||||||
|
finalReason = `${anchorSource} x ${inflationFactor} = ${calcPrice}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guidance.AnchorPrice = anchorPrice;
|
||||||
|
guidance.AnchorSource = anchorSource;
|
||||||
|
guidance.CustAnchorPrice = custPrice;
|
||||||
|
guidance.CustAnchorSource = custSource;
|
||||||
|
guidance.InflationFactor = inflationFactor;
|
||||||
|
guidance.Ceiling = calcCeiling;
|
||||||
|
guidance.FinalPriceUSD = finalPriceUSD;
|
||||||
|
guidance.FinalReasonUSD = finalReasonUSD;
|
||||||
|
guidance.FinalPrice = finalPrice;
|
||||||
|
guidance.FinalReason = finalReason;
|
||||||
|
guidance.BridgePremium = bridgePremium;
|
||||||
|
guidance.TargetPrice = targetPrice;
|
||||||
|
guidance.ListPrice = list;
|
||||||
doc.guidance = guidance;
|
doc.guidance = guidance;
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ FROM
|
|||||||
,('customer v0ds other',7)
|
,('customer v0ds other',7)
|
||||||
,('customer v0ds vol' ,3)
|
,('customer v0ds vol' ,3)
|
||||||
,('customer v1ds other',6)
|
,('customer v1ds other',6)
|
||||||
,('customer v1ds vol' ,2) --this will always sort to the top, v0ds will never sort to the top. you will always be getting the highest volume base price
|
,('customer v1ds vol' ,2)
|
||||||
,('market exact' ,4)
|
,('market exact' ,4)
|
||||||
,('market v0ds other' ,9)
|
,('market v0ds other' ,9)
|
||||||
,('market v0ds vol' ,5)
|
,('market v0ds vol' ,5)
|
||||||
|
@ -104,7 +104,7 @@ FROM
|
|||||||
,('customer v0ds other',7)
|
,('customer v0ds other',7)
|
||||||
,('customer v0ds vol' ,3)
|
,('customer v0ds vol' ,3)
|
||||||
,('customer v1ds other',6)
|
,('customer v1ds other',6)
|
||||||
,('customer v1ds vol' ,2) --this will always sort to the top, v0ds will never sort to the top. you will always be getting the highest volume base price
|
,('customer v1ds vol' ,2)
|
||||||
,('market exact' ,4)
|
,('market exact' ,4)
|
||||||
,('market v0ds other' ,9)
|
,('market v0ds other' ,9)
|
||||||
,('market v0ds vol' ,5)
|
,('market v0ds vol' ,5)
|
||||||
|
Loading…
Reference in New Issue
Block a user