From 453ec561eee27a36ce108a2ff6183918f1bd4f3a Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 16 Nov 2023 17:59:02 -0500 Subject: [PATCH] vault backup: 2023-11-16 17:59:02 --- sql/apply_guidance.pg.sql | 129 ++++++++++++++++++++++++++++++++++++++ sql/livequotes.pg.sql | 10 +++ 2 files changed, 139 insertions(+) create mode 100644 sql/apply_guidance.pg.sql create mode 100644 sql/livequotes.pg.sql diff --git a/sql/apply_guidance.pg.sql b/sql/apply_guidance.pg.sql new file mode 100644 index 0000000..71cd69e --- /dev/null +++ b/sql/apply_guidance.pg.sql @@ -0,0 +1,129 @@ +CREATE OR REPLACE FUNCTION rlarp.guidance_r1(doc jsonb) +RETURNS jsonb +LANGUAGE plv8 +AS $function$ + + function getAdjValue(number) { + const data = [ + {f: 2.001, t: 1000, snap: 3, adj: 0 }, + {f: 1.001, t: 2, snap: 2, adj: 0 }, + {f: 0.1, t: 1, snap: 1, adj: 0 }, + {f: 0, t: 0.1, snap: 0, adj: 0 }, + {f: -1, t: -0.00001, snap: -1, adj: 0.05}, + {f: -2, t: -0.999999, snap: -2, adj: 0.05}, + {f: -1000, t: -2.001, snap: -3, adj: 0.10}, + ]; + const match = data.find(row => number >= row.f && number <= row.t); + return match ? match.adj : null; + } + + function lowestPrice(priceObject) { + let Price = Infinity; + let Reason = ''; + let Source = ''; + let Snapped = Infinity; + + //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}); + } + + console.log(doc); + + // --------------------extract incoming data------------------------------------------------------ + const targetPrice = doc.pricing?.v1tp ?? doc.pricing?.v0tp; + const priceBand = doc.pricing?.v1stdv ?? doc.pricing?.v0stdv; + const earlyCustPrice = doc.hist?.cust?.early_price; + const earlyCustSeason = doc.hist?.cust?.early_season; + const earlyMarkPrice = doc.hist?.market?.early_price; + 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 iidx = doc.pricing?.iidx; + const curr = doc.customer?.curr; + const fxrate = doc.customer?.fxrate ?? 1.0; + const qty = doc.inputs?.qty; + const pltq = doc.product?.pltq; + console.log(iidx); + const inflation = Math.max(...Object.keys(iidx).map(Number)); + const inflationFactor = iidx[inflation]; + const list = doc.pricing?.list && doc.product?.itemrel === "2" ? doc.pricing?.list : null; + const listUSD = list ? list * fxrate :null; + + // ------------------calculate price adders------------------------------------------------------ + let ltp = qty < pltq ? 0.15 : null; + let anchor_sd = priceBand ? ((bridgedPrice - targetPrice) / priceBand).toFixed(2) : 0 + 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; + + let custPrice = r5(bridgedPrice * (1 + custAdder)); + let custSeason = earlyCustSeason; + let custReason = bridgePremium + ? `${custSeason} (similar ${altHist} price ${pp(earlyCustPrice)} x ${bridgePremium} = ${pp(bridgedPrice)})${custAddReason}` + : `${custSeason} price ${pp(bridgedPrice)}${custAddReason}`; + let markPrice = r5(earlyMarkPrice * (1 + markAdder)); + let markReason = `${earlyMarkSeason} ASP ${pp(earlyMarkPrice)}${markAddReason}`; + let targPrice = targetPrice ? r5(targetPrice * (1 + markAdder)) : null; + let targReason = `Target price ${pp(targetPrice)}${markAddReason}`; + let listPrice = listUSD; + let listReason = fxrate === 1 ? "" : `list ${pp(list)} CAD ${pp(listUSD)} USD` + + let prices = { + 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)] + } + + let finalPrice = lowestPrice(prices); + let guidance = { + prices + ,finalPrice + } + doc.guidance = guidance; + return doc; + +$function$; diff --git a/sql/livequotes.pg.sql b/sql/livequotes.pg.sql new file mode 100644 index 0000000..3a99280 --- /dev/null +++ b/sql/livequotes.pg.sql @@ -0,0 +1,10 @@ +SELECT + lq.* + ,pricing->'guidance'->'finalPrice'->>'Price' + ,pricing->'guidance'->'finalPrice'->>'Reason' +FROM + pricequote.live_quotes lq + JOIN LATERAL rlarp.guidance_r1( + rlarp.get_guidance_dseg(lq.billto,lq.shipto,substring(lq.part,1,8),lq.v1ds,lq.units_each,2024) + ) pricing ON TRUE +LIMIT 1000