Compare commits

...

31 Commits

Author SHA1 Message Date
86656f6952 example pool record selection 2024-04-29 08:41:01 -04:00
fb5968343a add last several months to price pool 2024-04-25 11:09:15 -04:00
51ba3fe3ca cur standard column name 2024-04-05 09:24:18 -04:00
6d987ee0aa list all quotes 2024-03-14 14:57:35 -04:00
618a744e05 point to itemm 2024-02-29 13:18:33 -05:00
de9ecd5033 point to itemm 2024-02-29 13:07:03 -05:00
5234516dee adjust history function 2024-02-23 12:16:40 -05:00
970968f980 set cap dish prices 2024-01-26 12:42:00 -05:00
3050bbfe7a add floor price for cap dishes 2023-12-11 11:29:16 -05:00
50781c6b2f debug inquirey 2023-12-11 10:58:24 -05:00
229291f9bc pull channel from customer object 2023-12-08 12:32:18 -05:00
e1406f70ab pull target based on modified channel 2023-12-08 11:37:07 -05:00
885a2982ee round after ceiling 2023-12-07 08:29:47 -05:00
eb0c969ec7 add json sort to api, and don't apply LTP charge for dishes or hangers 2023-12-01 13:53:23 -05:00
a2322876e1 include avg cost for inactive items 2023-11-29 08:16:26 -05:00
eca0da084e vault backup: 2023-11-27 11:40:01 2023-11-27 11:40:01 -05:00
a63f176293 vault backup: 2023-11-21 15:39:36 2023-11-21 15:39:36 -05:00
b04f67d9f0 variables are nested in customer json 2023-11-21 15:38:47 -05:00
d6c4d71851 create function that returns all customer related info and integrate to process 2023-11-21 14:37:38 -05:00
764a6f8ebe vault backup: 2023-11-21 10:00:30 2023-11-21 10:00:30 -05:00
062cea58a6 vault backup: 2023-11-20 15:56:18 2023-11-20 15:56:18 -05:00
14ee797b91 vault backup: 2023-11-20 15:46:59 2023-11-20 15:46:59 -05:00
aaa62afb5d vault backup: 2023-11-20 13:53:43 2023-11-20 13:53:43 -05:00
453ec561ee vault backup: 2023-11-16 17:59:02 2023-11-16 17:59:02 -05:00
baeeaccf53 vault backup: 2023-11-16 12:25:02 2023-11-16 12:25:02 -05:00
43e64a1533 move rounding to a function 2023-11-16 11:41:54 -05:00
0219b2d5ce vault backup: 2023-11-16 11:33:14 2023-11-16 11:33:14 -05:00
8a9102dbca vault backup: 2023-11-16 10:35:29 2023-11-16 10:35:29 -05:00
56d139c22d vault backup: 2023-11-16 10:25:41 2023-11-16 10:25:41 -05:00
52e802b389 vault backup: 2023-11-15 17:04:16 2023-11-15 17:04:16 -05:00
dc1f493700 work on simplifying and condensing logic 2023-11-15 16:57:21 -05:00
14 changed files with 875 additions and 176 deletions

10
api.ts
View File

@ -52,7 +52,15 @@ router.get('/dseg_price/:billcode/:shipcode/:stlc/:dseg/:qty', async (ctx) => {
const { billcode, shipcode, stlc, dseg, qty } = ctx.params;
const result = await client.queryObject({args: [billcode, shipcode, stlc, dseg, qty], text: query_dseg} );
const ag = apply_guidance(result.rows[0]["doc"]);
ctx.response.body = ag.guidance.FinalReason;
ctx.response.body = ag.guidance.finalPrice.Snapped;
});
// specific customres codes but generic style code and data segment to accomodate custom colors and branding
router.get('/dseg_reason/:billcode/:shipcode/:stlc/:dseg/:qty', async (ctx) => {
const { billcode, shipcode, stlc, dseg, qty } = ctx.params;
const result = await client.queryObject({args: [billcode, shipcode, stlc, dseg, qty], text: query_dseg} );
const ag = apply_guidance(result.rows[0]["doc"]);
ctx.response.body = ag.guidance.finalPrice.Snapped + ' (' + ag.guidance.finalPrice.Reason + ')';
});
app.use(router.routes());

View File

@ -1,5 +1,21 @@
export function apply_guidance(doc: any) {
function sortObjectKeys(obj) {
// If the object is not an actual object or is an array, return it as is
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
return obj;
}
// Create a new object and sort the keys
const sortedObj = {};
Object.keys(obj).sort().forEach(key => {
// Recursively apply the function for nested objects
sortedObj[key] = sortObjectKeys(obj[key]);
});
return sortedObj;
}
function getAdjValue(number) {
const data = [
{f: 2.001, t: 1000, snap: 3, adj: 0 },
@ -14,110 +30,136 @@ export function apply_guidance(doc: any) {
return match ? match.adj : null;
}
//let custPrice null;
//let custReason null;
//let cvolPrice null;
//let cvolReason null;
//let markPrice null;
//let markReason null;
//let targPrice null;
//let targReason null;
const targetPrice = doc.pricing?.v1tp ?? doc.pricing?.v0tp;
const priceBand = doc.pricing?.v1stdv ?? doc.pricing?.v0stdv;
const earlyPrice = doc.hist?.cust?.early_price;
const earlySeason = doc.hist?.cust?.early_season;
const bridgePremium = doc.pricing?.bridgePremium ?? 1.00000;
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;
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 inflationFactor = iidx[inflation] + 1;
const list = doc.pricing?.list && doc.product?.itemrel === "2" ? doc.pricing?.list : null;
//-------set basic customer pricing--------------
custPrice = Number((earlyPrice * bridgePremium).toFixed(5));
anchorPrice = custPrice;
let anchor_sd = priceBand ? ((anchorPrice - targetPrice) / priceBand).toFixed(2) : 0
let optimization = getAdjValue(anchor_sd);
// ------if there is not target price just exit---------------
if (!targetPrice) {
anchorSource = "No target pricing setup";
guidance.FinalReason = "No target pricing setup";
} else {
// if there is no customer anchor price use target
if (earlyPrice) {
// translate alternate product history to current product quoted
// --------if the price needs bridged, add the details to the description--------
if (bridgePremium === 1) {
anchorSource = earlySeason + ' Price ' + earlyPrice;
custSource = anchorSource;
} else {
anchorSource = earlySeason + ' Similar (' + altHist + ') Price ' + earlyPrice + ' x ' + bridgePremium + ' = ' + anchorPrice;
custSource = anchorSource;
}
// --------after the early price is translated see if target is still less-------
if (targetPrice < anchorPrice) {
anchorSource = `Target Price ${targetPrice}`;
anchorPrice = targetPrice;
}
} 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}`;
}
}
//-------------------------------set flor prices-------------------------------
function getFloor(stlc) {
switch (stlc) {
case "SDD10000":
return 0.045;
case "SDD10001":
return 0.045;
case "SDD12000":
return 0.065;
default:
return 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});
}
// --------------------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;
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;
const stlc = doc.inputs.stlc;
// ------------------calculate price adders------------------------------------------------------
let ltp = stlc.includes("SDD") || stlc.includes("HZP") ? 0 : (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}`;
let floor = getFloor(stlc);
// ------------------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)}` : `list ${pp(list)} CAD ${pp(listUSD)} USD`;
let prices = {
cust: [custPrice, custReason, "cust", r5(ceiling(custPrice,snap))],
mark: [markPrice, markReason, "mark", r5(ceiling(markPrice,snap))],
targ: [targPrice, targReason, "targ", r5(ceiling(targPrice,snap))],
list: [listPrice, listReason, "list", r5(ceiling(listPrice,snap))]
}
let finalPrice = lowestPrice(prices);
if (floor && floor > finalPrice.Price) {
finalPrice.Price = floor;
finalPrice.Snapped = floor;
finalPrice.Reason = `${finalPrice.Reason} floor at ${floor}`;
}
let guidance = {
prices
,finalPrice
,targetPrice
,listUSD
,ltp
,inflationFactor
,optimization
}
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;
return doc;
//return doc;
return sortObjectKeys(doc);
}

70
live_quote_mv.pg.sql Normal file
View File

@ -0,0 +1,70 @@
set work_mem TO '4GB';
DROP TABLE IF EXISTS rlarp.live_quotes_review_mv;
CREATE TABLE rlarp.live_quotes_review_mv AS
WITH
lq AS MATERIALIZED (
SELECT
lq.*
,substring(lq.part,1,8) mold
FROM
pricequote.live_quotes lq
)
,lqg AS (
SELECT
lq.*
,pricing->'product'->>'mold' part_group
,substring(pricing->'customer'->>'chan',1,1) qchan
,pricing->'customer'->>'cust' qcust
,pricing->'product'->>'itemrel' item_fit
,(pricing->'product'->>'pltq')::numeric pltq
,(pricing->'guidance'->'finalPrice'->>'Price')::numeric guidance
,pricing->'guidance'->'finalPrice'->>'Reason' reason
,(pricing->'product'->>'cstd_usd_ina')::numeric fstd_usd
,(pricing->'guidance'->>'ltp')::numeric ltp
,(pricing->'guidance'->>'optimization')::numeric optimization
,(pricing->'guidance'->>'inflationFactor')::numeric inflation
,jsonb_pretty(pricing) pricing
FROM
lq
LEFT 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
WHERE
lq.qstat ~ 'Submitted'
)
,hist AS (
SELECT
g.*
,gset.chan
--,gset.mold moldh
,gset.v1ds v1dsh
,gset.cust
,gset.vers
,je.k
,seas.*
FROM
lqg g
LEFT OUTER JOIN rlarp.price_pool_dev p ON
p.gset @> jsonb_build_object('mold',g.part_group)
AND p.gset ? 'cust'
AND p.gset ? 'v1ds'
LEFT JOIN LATERAL jsonb_to_record(p.gset) AS gset(
chan text
,mold text
,v1ds text
,v0ds text
,cust text
,vers text
--,nurs text
--,ghse text
) ON TRUE
LEFT JOIN LATERAL jsonb_each(p.season) je(k,v) on true
LEFT JOIN Lateral jsonb_to_record(je.v) as seas(
units numeric
,sales_usd numeric
,price_usd numeric
) ON TRUE
)
SELECT * FROM hist;

152
sql/apply_guidance.pg.sql Normal file
View File

@ -0,0 +1,152 @@
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;
}
//-------------------------------set flor prices-------------------------------
function getFloor(stlc) {
switch (stlc) {
case "SDD10000":
return 0.045;
case "SDD10001":
return 0.045;
case "SDD12000":
return 0.065;
default:
return 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});
}
// --------------------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;
const inflation = iidx ? Math.max(...Object.keys(iidx).map(Number)) : null;
const inflationFactor = iidx ? iidx[inflation] : 0;
const list = doc.pricing?.list && doc.product?.itemrel === "2" ? doc.pricing?.list : null;
const listUSD = list ? list * fxrate :null;
const stlc = doc.inputs.stlc;
// ------------------calculate price adders------------------------------------------------------
let ltp = stlc.includes("SDD") || stlc.includes("HZP") ? 0 : (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}`;
let floor = getFloor(stlc);
// ------------------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)}` : `list ${pp(list)} CAD ${pp(listUSD)} USD`;
let prices = {
cust: [custPrice, custReason, "cust", r5(ceiling(custPrice,snap))],
mark: [markPrice, markReason, "mark", r5(ceiling(markPrice,snap))],
targ: [targPrice, targReason, "targ", r5(ceiling(targPrice,snap))],
list: [listPrice, listReason, "list", r5(ceiling(listPrice,snap))]
}
let finalPrice = lowestPrice(prices);
if (floor && floor > finalPrice.Price) {
finalPrice.Price = floor;
finalPrice.Snapped = floor;
finalPrice.Reason = `${finalPrice.Reason} floor at ${floor}`;
}
let guidance = {
prices
,finalPrice
,targetPrice
,listUSD
,ltp
,inflationFactor
,optimization
}
doc.guidance = guidance;
return doc;
$function$;

View File

@ -0,0 +1,33 @@
SELECT
gset.cust
,gset.vers
,gset.chan
,gset.nurs
,gset.ghse
,gset.mold
,gset.v1ds
,gset.v0ds
,je.k
,seas.*
FROM
rlarp.price_pool_dev p
LEFT JOIN LATERAL jsonb_to_record(p.gset) AS gset(
chan text
,mold text
,v1ds text
,v0ds text
,cust text
,vers text
,nurs text
,ghse text
) ON TRUE
LEFT JOIN LATERAL jsonb_each(p.season) je(k,v) on true
LEFT JOIN Lateral jsonb_to_record(je.v) as seas(
units numeric
,sales_usd numeric
,price_usd numeric
) ON TRUE
WHERE
gset @> '{"mold":"TFR001G0","v0ds":"BASE"}'
AND agglevel ?| array['chan', 'mold', 'v0ds']
AND NOT agglevel ?| array['cust','ghse'];

79
sql/get_cust.pg.sql Normal file
View File

@ -0,0 +1,79 @@
----takes 2 DBA's and returns the channel----------
CREATE OR REPLACE FUNCTION rlarp.get_cust(billcode text, shipcode text)
RETURNS jsonb
LANGUAGE plpgsql AS
$func$
DECLARE
_chan text;
_chantp text;
_bill_class text;
_ship_class text;
_bill_dba text;
_ship_dba text;
_cust text;
_bill_curr text;
_bill_rate numeric;
_crec jsonb;
_ret jsonb;
_record jsonb;
BEGIN
SELECT jsonb_agg(row_to_json(c)::jsonb) INTO _crec FROM rlarp.cust c WHERE code IN (billcode, shipcode);
--RAISE NOTICE '%', jsonb_pretty(_crec);
FOR _record IN SELECT * FROM jsonb_array_elements(_crec)
LOOP
-- Check if the record is for billcode or shipcode and assign values accordingly
IF (_record->>'code')::text = billcode THEN
_bill_dba := (_record->>'dba')::text;
_bill_class := (_record->>'cclass')::text;
_bill_curr := (_record->>'currency')::text;
_bill_rate := (_record->>'fxcurr')::text;
-- Add other billcode related assignments here
END IF;
IF (_record->>'code')::text = shipcode THEN
_ship_dba := (_record->>'dba')::text;
_ship_class := (_record->>'cclass')::text;
-- Add other shipcode related assignments here
END IF;
END LOOP;
SELECT
CASE WHEN SUBSTRING(_bill_class,2,3) = 'DIS'
THEN CASE WHEN SUBSTRING(_ship_class,2,3) = 'DIS' THEN 'WHS' ELSE 'DRP' END
ELSE 'DIR'
END
INTO
_chan;
SELECT
CASE WHEN SUBSTRING(_bill_class,2,3) = 'DIS'
THEN CASE WHEN SUBSTRING(_ship_class,2,3) = 'DIS' THEN 'DISTRIBUTOR' ELSE 'DISTRIB DROP SHIP' END
ELSE 'DIRECT'
END
INTO
_chantp;
SELECT
CASE WHEN _chan = 'DRP' THEN _ship_dba ELSE _bill_dba END
INTO
_cust;
_ret := jsonb_build_object('customer',
jsonb_build_object(
'cust',_cust,
'chan',_chan,
'chantp',_chantp,
'curr',_bill_curr,
'fxrate',_bill_rate,
'bill_dba',_bill_dba,
'ship_dba',_ship_dba
)
);
RETURN _ret;
END
$func$;

View File

@ -42,7 +42,7 @@ BEGIN
INTO
_mold,_stlc,_v1ds , _v0ds, _iidx
FROM
"CMS.CUSLG".itemmv i
"CMS.CUSLG".itemm i
INNER JOIN rlarp.molds m ON
m.stlc = i.stlc
WHERE

View File

@ -1,4 +1,4 @@
DROP FUNCTION rlarp.get_guidance_dseg;
DROP FUNCTION rlarp.get_guidance_dseg CASCADE;
CREATE OR REPLACE FUNCTION rlarp.get_guidance_dseg(_bill text, _ship text, _stlc text, _dseg text, _qty numeric, _seas int)
RETURNS jsonb
LANGUAGE plpgsql AS
@ -15,6 +15,10 @@ DECLARE
_item text;
_unti text;
_pltq numeric;
_cstd numeric;
_cstdina numeric;
_fstd numeric;
_fstdina numeric;
_cust text;
_curr text;
_rate numeric;
@ -65,37 +69,52 @@ BEGIN
,idxk
,prefer
,pltq
,curstdus
,curstdus_ina
,futstdus
,futstdus_ina
INTO
_mold
,_item
,_iidx
,_itemr
,_pltq
,_cstd
,_cstdina
,_fstd
,_fstdina
FROM
(
SELECT
m.part_group
i.partgroup part_group
,min(i.item) item
,i.stlc
,i.v1ds
,i.v0ds
,i.pltq
,_ds.dataseg v0ds
,i.mpck pltq
,avg(i.curstdus) FILTER (WHERE aplnt <> 'I') curstdus
,avg(i.curstdus) curstdus_ina
,avg(i.futstdus) FILTER (WHERE aplnt <> 'I') futstdus
,avg(i.futstdus) futstdus_ina
,jsonb_strip_nulls(jsonb_build_object('assc',CASE WHEN i.assc <> '' THEN i.assc ELSE null::text END,'majg',i.majg::int,'coltier',i.coltier)) idxk
,CASE WHEN i.v1ds = _v1ds THEN 2 ELSE CASE WHEN i.v0ds = _v0ds THEN 1 ELSE 0 END END prefer
,CASE WHEN i.v1ds = _v1ds THEN 2 ELSE CASE WHEN _ds.dataseg = _v0ds THEN 1 ELSE 0 END END prefer
FROM
"CMS.CUSLG".itemmv i
INNER JOIN rlarp.molds m ON
m.stlc = i.stlc
"CMS.CUSLG".itemm i
LEFT OUTER JOIN _ds ON
_ds.colgrp = i.colgrp
AND _ds.brand = SUBSTRING(i.branding,1,1)
--INNER JOIN rlarp.molds m ON
-- m.stlc = i.stlc
WHERE
i.stlc = _stlc
GROUP BY
m.part_group
i.partgroup
,i.stlc
,i.v1ds
,i.v0ds
,i.pltq
,_ds.dataseg
,i.mpck
,jsonb_strip_nulls(jsonb_build_object('assc',CASE WHEN i.assc <> '' THEN i.assc ELSE null::text END,'majg',i.majg::int,'coltier',i.coltier))
,CASE WHEN i.v1ds = _v1ds THEN 2 ELSE CASE WHEN i.v0ds = _v0ds THEN 1 ELSE 0 END END
,CASE WHEN i.v1ds = _v1ds THEN 2 ELSE CASE WHEN _ds.dataseg = _v0ds THEN 1 ELSE 0 END END
) best
ORDER BY
prefer DESC
@ -109,49 +128,54 @@ BEGIN
,'itemrel',_itemr
,'iidx',_iidx
,'pltq',_pltq
,'cstd_usd',_cstd
,'cstd_usd_ina',_cstdina
,'fstd_usd',_fstd
,'fstd_usd_ina',_fstdina
)
);
--RAISE NOTICE 'item data %', jsonb_pretty(_product||_input);
----------------channel-------------------------------------
SELECT rlarp.channel_code(_bill, _ship) INTO _chan;
_customer := jsonb_build_object('chan',_chan);
SELECT rlarp.get_cust(_bill, _ship) INTO _customer;
--_customer := jsonb_build_object('chan',_chan);
----------------customer------------------------------------
SELECT dba INTO _cust FROM rlarp.cust WHERE code = CASE WHEN _chan = 'DRP' THEN _ship ELSE _bill END ;
SELECT
currency,
(SELECT
x.rate
FROM
rlarp.ffcret x
WHERE
x.perd = (select fspr from rlarp.gld where drange @> current_date)
AND x.rtyp = 'MA'
and x.fcur = currency
AND x.tcur = 'US'
)
INTO
_curr
,_rate
FROM
rlarp.cust
WHERE
code = _bill;
--SELECT dba INTO _cust FROM rlarp.cust WHERE code = CASE WHEN _chan = 'DRP' THEN _ship ELSE _bill END ;
--SELECT
-- currency,
-- (SELECT
-- x.rate
-- FROM
-- rlarp.ffcret x
-- WHERE
-- x.perd = (select fspr from rlarp.gld where drange @> current_date)
-- AND x.rtyp = 'MA'
-- and x.fcur = currency
-- AND x.tcur = 'US'
-- )
--INTO
-- _curr
-- ,_rate
--FROM
-- rlarp.cust
--WHERE
-- code = _bill;
_customer := jsonb_build_object(
'customer',
_customer||jsonb_build_object(
'cust',_cust
,'curr',_curr
,'fxrate',_rate
)
);
--_customer := jsonb_build_object(
-- 'customer',
-- _customer||jsonb_build_object(
-- 'cust',_cust
-- ,'curr',_curr
-- ,'fxrate',_rate
-- )
--);
--RAISE NOTICE 'cust %', jsonb_pretty(_customer);
----------------price history-------------------------------
SELECT jsonb_build_object('hist',rlarp.get_hist(_mold, _v1ds, _cust, substring(_chan,1,1))) INTO _hist;
--RAISE NOTICE 'varb %', _customer;
SELECT jsonb_build_object('hist',rlarp.get_hist(_mold, _v1ds, _customer->'customer'->>'cust', substring(_customer->'customer'->>'chan',1,1))) INTO _hist;
--RAISE NOTICE 'history %', jsonb_pretty(_hist);
----------------target pricing------------------------------
@ -170,7 +194,8 @@ BEGIN
mold = _stlc
AND season = _seas
AND data_segment = _v0ds
AND region = 'ALL';
AND region = 'ALL'
AND chan = _customer->'customer'->>'chantp';
----------------target pricing------------------------------
SELECT
jsonb_build_object(
@ -187,7 +212,8 @@ BEGIN
mold = _stlc
AND season = _seas
AND data_segment = _dseg
AND region = 'ALL';
AND region = 'ALL'
AND chan = _customer->'customer'->>'chantp';
--RAISE NOTICE 'target: %', jsonb_pretty(_targ);
_pricing := (COALESCE(_v0tp,'{}'::jsonb)||COALESCE(_v1tp,'{}'::jsonb));
@ -221,7 +247,7 @@ BEGIN
--RAISE NOTICE 'add list: %', jsonb_pretty(_pricing);
----------------get premium for quote hist gap--------------
SELECT coalesce(rlarp.get_premium(_stlc, _seas, (SELECT xchan FROM _chx WHERE chan = _chan),_hist->'hist'->'cust'->>'ds', _v1ds),'{}'::jsonb) INTO _prem;
SELECT coalesce(rlarp.get_premium(_stlc, _seas, _customer->'customer'->>'chantp',_hist->'hist'->'cust'->>'ds', _v1ds),'{}'::jsonb) INTO _prem;
_pricing := jsonb_build_object('pricing',_pricing||_prem);
--RAISE NOTICE 'add bridge: %', jsonb_pretty(_pricing);

View File

@ -110,7 +110,7 @@ FROM
,('customer v0ds other',7)
,('customer v0ds vol' ,3)
,('customer v1ds other',6)
,('customer v1ds vol' ,2)
,('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
,('market exact' ,4)
,('market v0ds other' ,9)
,('market v0ds vol' ,5)

View File

@ -1,5 +1,5 @@
WITH
sel AS (select 'v1:P.P.PLT..' _v1ds, 'ALTMAN PLANTS' _cust, 'XNS0T1G3' _mold, 'D' _chan)
sel AS (select 'v1:T..PLT..' _v1ds, 'KAWAHARA NURSERY' _cust, 'AZE10001' _mold, 'D' _chan)
,sort AS (
SELECT
p.agglevel
@ -53,6 +53,19 @@ sel AS (select 'v1:P.P.PLT..' _v1ds, 'ALTMAN PLANTS' _cust, 'XNS0T1G3' _mold, 'D
source ASC
,rn ASC
)
,rel AS (
SELECT * FROM (values
('customer exact' ,1)
,('customer v0ds other',7)
,('customer v0ds vol' ,3)
,('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
,('market exact' ,4)
,('market v0ds other' ,9)
,('market v0ds vol' ,5)
,('market v1ds other' ,8)
) x (flag,prefer)
)
,flag AS (
SELECT
--agglevel
@ -84,6 +97,7 @@ SELECT
,cust
,vers
,rn
,row_number() OVER (PARTITION BY source ORDER BY rel.prefer ASC) rnk
,avgunits
,avgordcount
,avgcustcount
@ -97,19 +111,25 @@ SELECT
,season
FROM
sort
)
,rel AS (
SELECT * FROM (values
('customer exact' ,1)
,('customer v0ds other',7)
,('customer v0ds vol' ,3)
,('customer v1ds other',6)
,('customer v1ds vol' ,2)
,('market exact' ,4)
,('market v0ds other' ,9)
,('market v0ds vol' ,5)
,('market v1ds other' ,8)
) x (flag,prefer)
LEFT OUTER JOIN rel ON
rel.flag = CASE source
WHEN 'cust' THEN
CASE WHEN v1ds IS NOT NULL THEN
CASE WHEN v1ds_match THEN 'customer exact' ELSE
CASE WHEN rn = 1 THEN 'customer v1ds vol' ELSE 'customer v1ds other' END
END
ELSE
CASE WHEN rn = 1 THEN 'customer v0ds vol' ELSE 'customer v0ds other' END
END
ELSE
CASE WHEN v1ds IS NOT NULL THEN
CASE WHEN v1ds_match THEN 'market exact' ELSE
CASE WHEN rn = 1 THEN 'market v1ds vol' ELSE 'market v1ds other' END
END
ELSE
CASE WHEN rn = 1 THEN 'market v0ds vol' ELSE 'market v0ds other' END
END
END
)
,rel_sort AS (
SELECT
@ -133,21 +153,21 @@ FROM
,'last_season' ,last_season
,'last_price' ,last_price
,'ds' ,COALESCE(v1ds,v0ds)
,'rank' ,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC)
,'rank' ,rnk
,'pricinghistory' ,season
)
)
) doc
,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC) rnk
,rnk
,season
FROM
flag
LEFT OUTER JOIN rel ON
rel.flag = flag.relevance
WHERE
relevance ~ 'vol|exact'
)
--SELECT rnk, jsonb_pretty(doc) doc, jsonb_pretty(season) season FROM rel_sort
--SELECT jsonb_pretty(jsonb_agg(doc)) FROM rel_sort
--SELECT jsonb_pretty(jsonb_obj_aggc(doc)) FROM rel_sort--INTO _result FROM rel_sort WHERE rnk = 1;
SELECT * FROM rel_sort;
--SELECT * FROM rel_sort;
SELECT * FROM flag
--SELECT jsonb_obj_aggc(doc) FROM rel_sort WHERE rnk = 1;

View File

@ -0,0 +1,69 @@
DROP TABLE IF EXISTS rlarp.live_quotes_nohist;
CREATE TABLE rlarp.live_quotes_nohist AS
WITH
lq AS MATERIALIZED (
SELECT
lq.*
,substring(lq.part,1,8) mold
FROM
pricequote.live_quotes lq
)
,lqg AS (
SELECT
lq.*
,pricing->'product'->>'mold' part_group
,substring(pricing->'customer'->>'chan',1,1) qchan
,pricing->'customer'->>'cust' qcust
,pricing->'product'->>'itemrel' item_fit
,(pricing->'product'->>'pltq')::numeric pltq
,(pricing->'guidance'->'finalPrice'->>'Price')::numeric guidance
,pricing->'guidance'->'finalPrice'->>'Reason' reason
,(pricing->'product'->>'cstd_usd_ina')::numeric fstd_usd
,(pricing->'guidance'->>'ltp')::numeric ltp
,(pricing->'guidance'->>'optimization')::numeric optimization
,(pricing->'guidance'->>'inflationFactor')::numeric inflation
,jsonb_pretty(pricing) pricing
FROM
lq
LEFT 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
WHERE
TRUE
--lq.qstat ~ 'Submitted'
)
--,hist AS (
-- SELECT
-- g.*
-- ,gset.chan
-- --,gset.mold moldh
-- ,gset.v1ds v1dsh
-- ,gset.cust
-- ,gset.vers
-- ,je.k
-- ,seas.*
-- FROM
-- lqg g
-- LEFT OUTER JOIN rlarp.price_pool_dev p ON
-- p.gset @> jsonb_build_object('mold',g.part_group)
-- AND p.gset ? 'cust'
-- AND p.gset ? 'v1ds'
-- LEFT JOIN LATERAL jsonb_to_record(p.gset) AS gset(
-- chan text
-- ,mold text
-- ,v1ds text
-- ,v0ds text
-- ,cust text
-- ,vers text
-- --,nurs text
-- --,ghse text
-- ) ON TRUE
-- LEFT JOIN LATERAL jsonb_each(p.season) je(k,v) on true
-- LEFT JOIN Lateral jsonb_to_record(je.v) as seas(
-- units numeric
-- ,sales_usd numeric
-- ,price_usd numeric
-- ) ON TRUE
--)
SELECT * FROM lqg;

70
sql/livequotes.pg.sql Normal file
View File

@ -0,0 +1,70 @@
set work_mem TO '4GB';
DROP VIEW IF EXISTS rlarp.live_quotes_review;
CREATE VIEW rlarp.live_quotes_review AS
WITH
lq AS MATERIALIZED (
SELECT
lq.*
,substring(lq.part,1,8) mold
FROM
pricequote.live_quotes lq
)
,lqg AS (
SELECT
lq.*
,pricing->'product'->>'mold' part_group
,substring(pricing->'customer'->>'chan',1,1) qchan
,pricing->'customer'->>'cust' qcust
,pricing->'product'->>'itemrel' item_fit
,(pricing->'product'->>'pltq')::numeric pltq
,(pricing->'guidance'->'finalPrice'->>'Price')::numeric guidance
,pricing->'guidance'->'finalPrice'->>'Reason' reason
,(pricing->'product'->>'cstd_usd_ina')::numeric cstd_usd
,(pricing->'product'->>'fstd_usd_ina')::numeric fstd_usd
,(pricing->'guidance'->>'ltp')::numeric ltp
,(pricing->'guidance'->>'optimization')::numeric optimization
,(pricing->'guidance'->>'inflationFactor')::numeric inflation
,jsonb_pretty(pricing) pricing
FROM
lq
LEFT 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
WHERE
lq.qstat ~ 'Submitted'
)
,hist AS (
SELECT
g.*
,gset.chan
--,gset.mold moldh
,gset.v1ds v1dsh
,gset.cust
,gset.vers
,je.k
,seas.*
FROM
lqg g
LEFT OUTER JOIN rlarp.price_pool_dev p ON
p.gset @> jsonb_build_object('mold',g.part_group)
AND p.gset ? 'cust'
AND p.gset ? 'v1ds'
LEFT JOIN LATERAL jsonb_to_record(p.gset) AS gset(
chan text
,mold text
,v1ds text
,v0ds text
,cust text
,vers text
--,nurs text
--,ghse text
) ON TRUE
LEFT JOIN LATERAL jsonb_each(p.season) je(k,v) on true
LEFT JOIN Lateral jsonb_to_record(je.v) as seas(
units numeric
,sales_usd numeric
,price_usd numeric
) ON TRUE
)
SELECT * FROM hist

59
sql/livequotes_dev.pg.sql Normal file
View File

@ -0,0 +1,59 @@
WITH
lq AS MATERIALIZED (
SELECT
lq.*
,substring(lq.part,1,8) mold
FROM
pricequote.live_quotes lq
)
,lqg AS (
SELECT
lq.*
,m.part_group
,(pricing->'guidance'->'finalPrice'->>'Price')::numeric guidance
,pricing->'guidance'->'finalPrice'->>'Reason' reason
,jsonb_pretty(pricing) pricing
FROM
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
LEFT OUTER JOIN rlarp.molds m ON
m.stlc = lq.mold
WHERE
lq.qstat ~ 'Submitted'
)
,hist AS (
SELECT
g.*
,gset.chan
--,gset.mold moldh
,gset.v1ds v1dsh
,gset.cust
,gset.vers
,je.k
,seas.*
FROM
lqg g
LEFT OUTER JOIN rlarp.price_pool_dev p ON
p.gset @> jsonb_build_object('mold',g.part_group)
AND p.gset ? 'cust'
AND p.gset ? 'v1ds'
LEFT JOIN LATERAL jsonb_to_record(p.gset) AS gset(
chan text
,mold text
,v1ds text
,v0ds text
,cust text
,vers text
--,nurs text
--,ghse text
) ON TRUE
LEFT JOIN LATERAL jsonb_each(p.season) je(k,v) on true
LEFT JOIN Lateral jsonb_to_record(je.v) as seas(
units numeric
,sales_usd numeric
,price_usd numeric
) ON TRUE
)
SELECT * FROM hist WHERE qid = 73059

View File

@ -1,9 +1,10 @@
--CREATE OR REPLACE PROCEDURE rlarp.price_pool()
--LANGUAGE plpgsql AS
--$func$
BEGIN;
DROP TABLE IF EXISTS rlarp.price_pool_dev;
CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
--BEGIN;
DROP MATERIALIZED VIEW IF EXISTS rlarp.price_pool_dev CASCADE;
--CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
CREATE MATERIALIZED VIEW rlarp.price_pool_dev AS (
WITH
agg AS (
SELECT
@ -75,6 +76,76 @@ CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
HAVING
round(sum(o.qty),0) > 0
AND round(sum(o.sales_usd)/sum(o.qty),5) > 0
UNION ALL
SELECT
o.customer
,substring(o.version,1,1) version
,o.chanwide
,o.nursery_region
,c.greenhouse_region
,m.part_group baseitem
,m.majg
,m.assc
,i.coltier
,'v1:' || rtrim(COALESCE(i.coltier, ''))|| '.' || rtrim(substring(COALESCE(i.branding, ''), 1, 1))|| '.' || rtrim(COALESCE(i.uomp, ''))|| '.' || rtrim(COALESCE(i.suffix, ''))|| '.' || rtrim(COALESCE(i.accs_ps, '')) v1dataseg
,_ds.dataseg v0dataseg
,0 oseas
,round(sum(o.qty),0) units
,round(sum(o.sales_usd),0) sales_usd
,round(sum(COALESCE(tp.target_price,tq.target_price) * o.qty),2) target_price
,count(DISTINCT o.ordnum) ordcount
FROM
rlarp.osm_stack o
INNER JOIN "CMS.CUSLG".itemm i ON
i.item = o.part
LEFT OUTER JOIN rlarp.molds m ON
m.stlc = i.stlc
LEFT OUTER JOIN _ds ON
_ds.colgrp = o.colgrp
AND _ds.brand = substring(i.branding,1,1)
LEFT OUTER JOIN pricequote.market_setavgprice tp ON
tp.season = (SELECT ssyr FROM rlarp.gld where drange @> current_date)
AND tp.country = 'ALL'
AND tp.geo = 'ALL'
AND tp.region = 'ALL'
AND tp.mold = i.stlc
AND tp.chan = 'DISTRIB DROP SHIP'
AND tp.data_segment = 'v1:' || rtrim(COALESCE(i.coltier, ''))|| '.' || rtrim(substring(COALESCE(i.branding, ''), 1, 1))|| '.' || rtrim(COALESCE(i.uomp, ''))|| '.' || rtrim(COALESCE(i.suffix, ''))|| '.' || rtrim(COALESCE(i.accs_ps, ''))
LEFT OUTER JOIN pricequote.market_setavgprice tq ON
tq.season = (SELECT ssyr FROM rlarp.gld where drange @> current_date)
AND tq.country = 'ALL'
AND tq.geo = 'ALL'
AND tq.region = 'ALL'
AND tq.mold = i.stlc
AND tq.chan = 'DISTRIB DROP SHIP'
AND tq.data_segment = _ds.dataseg
LEFT OUTER JOIN rlarp.cust c ON
c.code = CASE o.chan WHEN 'DIR' THEN o.bill_cust ELSE o.ship_cust END
WHERE
o.version IN ('Actual','Quotes')
AND o.odate >= current_date - '4 months'::interval
AND o.dsm <> 'PW'
--AND o.part like 'SQL035%'
--AND o.calc_status <> 'CANCELED'
--AND o.fs_line = '41010'
--AND o.dsm <> 'PW'
--AND i.coltier <> 'C'
GROUP BY
o.customer
,substring(o.version,1,1)
,o.chanwide
,o.nursery_region
,c.greenhouse_region
,m.part_group
,m.majg
,m.assc
,i.coltier
,'v1:' || rtrim(COALESCE(i.coltier, ''))|| '.' || rtrim(substring(COALESCE(i.branding, ''), 1, 1))|| '.' || rtrim(COALESCE(i.uomp, ''))|| '.' || rtrim(COALESCE(i.suffix, ''))|| '.' || rtrim(COALESCE(i.accs_ps, ''))
,_ds.dataseg
,o.oseas
HAVING
round(sum(o.qty),0) > 0
AND round(sum(o.sales_usd)/sum(o.qty),5) > 0
)
,gsets AS (
SELECT
@ -171,4 +242,4 @@ CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
) WITH DATA;
create index ppd_gset on rlarp.price_pool_dev using gin (gset);
END;
--END;