Compare commits

...

41 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
32217d52c4 include all history 2023-11-15 15:26:21 -05:00
87d2bd39cd vault backup: 2023-11-15 13:47:00 2023-11-15 13:47:00 -05:00
428d73dbbc include get_list definition here 2023-11-13 16:47:35 -05:00
f91beee772 pull in pallet quantity and assign ltp 2023-11-13 13:15:24 -05:00
a5acb798b4 include pallet quantity in product info 2023-11-13 12:59:45 -05:00
7919160ecc only use list if relevance is type 2 exact match 2023-11-13 12:43:44 -05:00
15c60c629d convert to USD 2023-11-13 12:25:41 -05:00
b81261af3f fix bridge pricing 2023-11-13 11:45:47 -05:00
0922862c80 apply groupings to json 2023-11-13 11:02:41 -05:00
96eee9ff5b vault backup: 2023-11-10 16:32:05 2023-11-10 16:32:05 -05:00
16 changed files with 1454 additions and 231 deletions

21
api.ts
View File

@ -34,18 +34,35 @@ const query = await Deno.readTextFile("sql/get.pg.sql");
const query_dseg = await Deno.readTextFile("sql/get_dseg.pg.sql"); const query_dseg = await Deno.readTextFile("sql/get_dseg.pg.sql");
// exact scenario for existing codes // exact scenario for existing codes
router.get('/code_price/:billcode/:shipcode/:partcode/:qty', async (ctx) => { router.get('/code/:billcode/:shipcode/:partcode/:qty', async (ctx) => {
const { billcode, shipcode, partcode, qty } = ctx.params; const { billcode, shipcode, partcode, qty } = ctx.params;
const result = await client.queryObject({args: [billcode, shipcode, partcode, qty], text: query} ); const result = await client.queryObject({args: [billcode, shipcode, partcode, qty], text: query} );
ctx.response.body = apply_guidance(result.rows[0]["doc"]); ctx.response.body = apply_guidance(result.rows[0]["doc"]);
}); });
// specific customres codes but generic style code and data segment to accomodate custom colors and branding
router.get('/dseg/: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} );
ctx.response.body = apply_guidance(result.rows[0]["doc"]);
});
// specific customres codes but generic style code and data segment to accomodate custom colors and branding // specific customres codes but generic style code and data segment to accomodate custom colors and branding
router.get('/dseg_price/:billcode/:shipcode/:stlc/:dseg/:qty', async (ctx) => { 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} );
ctx.response.body = apply_guidance(result.rows[0]["doc"]); const ag = apply_guidance(result.rows[0]["doc"]);
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()); app.use(router.routes());
app.use(router.allowedMethods()); app.use(router.allowedMethods());

View File

@ -1,167 +1,165 @@
export function apply_guidance(doc: any) { export function apply_guidance(doc: any) {
let mostRelevantMarketPrice = null;
let mostRelevantMarketPriceEarly = null;
let mostRelevantMarketKey = null;
let mostRelevantMarketSeason = null;
let mostRelevantMarketSeasonEarly = null;
let highestMarketRelevanceLevel = 0;
let mostRelevantMarketSource = null;
let mostRelevantCustomerPriceEarly = null; function sortObjectKeys(obj) {
let mostRelevantCustomerPriceRecent = null; // If the object is not an actual object or is an array, return it as is
let mostRelevantCustomerKey = null; if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
let mostRelevantCustomerSeasonEarly = null; return obj;
let mostRelevantCustomerSeasonRecent = null;
let highestCustomerRelevanceLevel = 0;
let mostRelevantCustomerSource = null;
// Function to update price and assign relevance indicator
function setAnchors(items, channelFirstChar, v1ds, v0ds, histKey) {
for (let item of items) {
// Update the last_price with the most recent price
const years = Object.keys(item.season).map(Number).filter(year => year >= 2020);
if (years.length > 0) {
const recentYear = Math.max(...years.map(Number));
const earlyYear = Math.min(...years.map(Number));
const lastPrice = item.season[recentYear].price_usd;
const earlyPrice = item.season[earlyYear].price_usd;
item.last_price = lastPrice;
item.early_price = earlyPrice;
item.last_season = recentYear;
item.early_season = earlyYear;
} else {
item.last_price = null; // or some default value as appropriate
} }
// Initialize relevance as numeric value // Create a new object and sort the keys
let marketRelevance = 0; // Assume 0 is 'not relevant' const sortedObj = {};
let customerRelevance = 0; // Assume 0 is 'not relevant' Object.keys(obj).sort().forEach(key => {
// Recursively apply the function for nested objects
sortedObj[key] = sortObjectKeys(obj[key]);
});
return sortedObj;
}
// Check if the first character of the item's channel matches the first character of the document's channel function getAdjValue(number) {
if (item.chan.charAt(0) === channelFirstChar) { const data = [
marketRelevance = 1; // 'relevant' {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-------------------------------
// Further refine relevance based on v1ds and v0ds function getFloor(stlc) {
if (item.v1ds === v1ds) { switch (stlc) {
marketRelevance = 2; // 'most relevant' because v1ds matches case "SDD10000":
return 0.045;
// Check for customer relevance if 'cust' key exists case "SDD10001":
customerRelevance = item.cust ? 3 : 0; return 0.045;
} else if (item.v0ds === v0ds) { case "SDD12000":
marketRelevance = marketRelevance === 2 ? 2 : 1; // Keep relevance as is if v1ds was matched, otherwise it's just 'relevant' return 0.065;
customerRelevance = item.cust ? 2 : 0; default:
} else if (item.cust) { return null;
customerRelevance = item.v1ds ? 2 : item.v0ds ? 1 : 0;
} }
} }
// Assign the calculated relevance to the item function lowestPrice(priceObject) {
item.marketRelevance = marketRelevance; let Price = Infinity;
item.customerRelevance = customerRelevance; let Reason = '';
let Source = '';
let Snapped = Infinity;
// Update the most relevant market price if this item's relevance is higher and it doesn't have a 'cust' key //console.log(priceObject["targ"][0]);
if (marketRelevance > highestMarketRelevanceLevel) { // Iterate over each property in the object
highestMarketRelevanceLevel = marketRelevance; for (let key in priceObject) {
mostRelevantMarketPrice = item.last_price; // Ignore markPrice unless targPrice is null
mostRelevantMarketPriceEarly = item.early_price; if (key === "mark" && priceObject["targ"][0] !== null) {
mostRelevantMarketKey = histKey; continue;
mostRelevantMarketSource = item;
delete mostRelevantMarketSource.season;
mostRelevantMarketSeason = item.last_season; // Assuming 'season' is the key where the season info is stored
mostRelevantMarketSeasonEarly = item.early_season;
} }
if (priceObject.hasOwnProperty(key)) {
// Update the most relevant customer price if this item's relevance is higher and it has a 'cust' key let [cprice, creason, csource, csnap] = priceObject[key];
if (customerRelevance > highestCustomerRelevanceLevel) { // Check if the current price is lower than the found so far
highestCustomerRelevanceLevel = customerRelevance; if (cprice && cprice < Price) {
mostRelevantCustomerPriceRecent = item.last_price; Price = cprice;
mostRelevantCustomerPriceEarly = item.early_price; Reason = creason;
mostRelevantCustomerKey = histKey; Source = csource;
mostRelevantCustomerSource = item; Snapped = csnap;
delete mostRelevantCustomerSource.season;
mostRelevantCustomerSeasonRecent = item.last_season; // Assuming 'season' is the key where the season info is stored
mostRelevantCustomerSeasonEarly = item.early_season; // Assuming 'season' is the key where the season info is stored
} }
} }
} }
return {Reason, Price, Source, Snapped};
//// Iterate over each key in the "hist" object
//for (let key of Object.keys(doc.hist)) {
// // Update price and relevance for each item in the current key
// setAnchors(doc.hist[key], doc.chan[0], doc.v1ds, doc.v0ds, key);
//}
//// Assign the most relevant market price and key to the top level of the document
//if (mostRelevantMarketPrice !== null) {
// doc.mostRelevantMarketPriceInfo = {
// price: mostRelevantMarketPrice,
// price_early: mostRelevantMarketPriceEarly,
// source: mostRelevantMarketSource,
// season: mostRelevantMarketSeason,
// season_early: mostRelevantMarketSeasonEarly,
// relevance: highestMarketRelevanceLevel
// };
//}
//// Assign the most relevant customer price and key to the top level of the document
//if (mostRelevantCustomerPriceRecent !== null) {
// doc.mostRelevantCustomerPriceInfo = {
// price: mostRelevantCustomerPriceRecent,
// price_early: mostRelevantCustomerPriceEarly,
// source: mostRelevantCustomerSource,
// season: mostRelevantCustomerSeasonRecent,
// season_early: mostRelevantCustomerSeasonEarly,
// relevance: highestCustomerRelevanceLevel
// };
//}
const targetPrice = doc.v1tp ?? doc.v0tp;
const earlyPrice = doc.hist?.cust?.early_price;
let anchorPrice = null;
let anchorSource = null;
let bridgePremium = doc.bridgePremium ?? 1.00000;
if (!targetPrice) {
anchorSource = "No target pricing setup";
doc.finalReason = "No target pricing setup";
} else {
// Determine the anchor price and source
if (earlyPrice) {
// translate alternate product history to current product quoted
anchorPrice = Number((earlyPrice * bridgePremium).toFixed(5));
// after the early price is translated see if target is still less
if (targetPrice < anchorPrice) {
anchorSource = `Target Price ${targetPrice}`;
anchorPrice = targetPrice;
} else {
anchorSource = doc.hist.cust.early_season + ' Similar (' + doc.hist.cust.ds + ') Customer Price ' + earlyPrice + ' x ' + doc.bridgePremium + ' = ' + anchorPrice;
}
} else {
anchorPrice = targetPrice;
anchorSource = `Target Price ${targetPrice}`;
} }
const inflation = Math.max(...Object.keys(doc.iidx).map(Number)); function ceiling(value, significance) {
const inflationFactor = doc.iidx[inflation] + 1; return Math.ceil(value / significance) * significance;
var calcPrice = parseFloat((anchorPrice * inflationFactor).toFixed(5));
let finalReason = "";
if (calcPrice >= doc.list && doc.list) {
doc.calcCeiling = "Cap At List";
doc.finalPrice = doc.list;
finalReason = `${anchorSource} x ${inflationFactor} = ${calcPrice} but cap at list ${doc.list}`;
} else {
doc.finalPrice = calcPrice;
finalReason = `${anchorSource} x ${inflationFactor} = ${calcPrice}`;
}
doc.anchorPrice = anchorPrice;
doc.anchorSource = anchorSource;
doc.inflationFactor = inflationFactor;
doc.finalReason = finalReason;
doc.bridgePremium = bridgePremium;
doc.targetPrice = targetPrice;
} }
return doc; 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
}
doc.guidance = guidance;
//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;

118
set_anchors.ts Normal file
View File

@ -0,0 +1,118 @@
let mostRelevantMarketPrice = null;
let mostRelevantMarketPriceEarly = null;
let mostRelevantMarketKey = null;
let mostRelevantMarketSeason = null;
let mostRelevantMarketSeasonEarly = null;
let highestMarketRelevanceLevel = 0;
let mostRelevantMarketSource = null;
let mostRelevantCustomerPriceEarly = null;
let mostRelevantCustomerPriceRecent = null;
let mostRelevantCustomerKey = null;
let mostRelevantCustomerSeasonEarly = null;
let mostRelevantCustomerSeasonRecent = null;
let highestCustomerRelevanceLevel = 0;
let mostRelevantCustomerSource = null;
// Function to update price and assign relevance indicator
function setAnchors(items, channelFirstChar, v1ds, v0ds, histKey) {
for (let item of items) {
// Update the last_price with the most recent price
const years = Object.keys(item.season).map(Number).filter(year => year >= 2020);
if (years.length > 0) {
const recentYear = Math.max(...years.map(Number));
const earlyYear = Math.min(...years.map(Number));
const lastPrice = item.season[recentYear].price_usd;
const earlyPrice = item.season[earlyYear].price_usd;
item.last_price = lastPrice;
item.early_price = earlyPrice;
item.last_season = recentYear;
item.early_season = earlyYear;
} else {
item.last_price = null; // or some default value as appropriate
}
// Initialize relevance as numeric value
let marketRelevance = 0; // Assume 0 is 'not relevant'
let customerRelevance = 0; // Assume 0 is 'not relevant'
// Check if the first character of the item's channel matches the first character of the document's channel
if (item.chan.charAt(0) === channelFirstChar) {
marketRelevance = 1; // 'relevant'
// Further refine relevance based on v1ds and v0ds
if (item.v1ds === v1ds) {
marketRelevance = 2; // 'most relevant' because v1ds matches
// Check for customer relevance if 'cust' key exists
customerRelevance = item.cust ? 3 : 0;
} else if (item.v0ds === v0ds) {
marketRelevance = marketRelevance === 2 ? 2 : 1; // Keep relevance as is if v1ds was matched, otherwise it's just 'relevant'
customerRelevance = item.cust ? 2 : 0;
} else if (item.cust) {
customerRelevance = item.v1ds ? 2 : item.v0ds ? 1 : 0;
}
}
// Assign the calculated relevance to the item
item.marketRelevance = marketRelevance;
item.customerRelevance = customerRelevance;
// Update the most relevant market price if this item's relevance is higher and it doesn't have a 'cust' key
if (marketRelevance > highestMarketRelevanceLevel) {
highestMarketRelevanceLevel = marketRelevance;
mostRelevantMarketPrice = item.last_price;
mostRelevantMarketPriceEarly = item.early_price;
mostRelevantMarketKey = histKey;
mostRelevantMarketSource = item;
delete mostRelevantMarketSource.season;
mostRelevantMarketSeason = item.last_season; // Assuming 'season' is the key where the season info is stored
mostRelevantMarketSeasonEarly = item.early_season;
}
// Update the most relevant customer price if this item's relevance is higher and it has a 'cust' key
if (customerRelevance > highestCustomerRelevanceLevel) {
highestCustomerRelevanceLevel = customerRelevance;
mostRelevantCustomerPriceRecent = item.last_price;
mostRelevantCustomerPriceEarly = item.early_price;
mostRelevantCustomerKey = histKey;
mostRelevantCustomerSource = item;
delete mostRelevantCustomerSource.season;
mostRelevantCustomerSeasonRecent = item.last_season; // Assuming 'season' is the key where the season info is stored
mostRelevantCustomerSeasonEarly = item.early_season; // Assuming 'season' is the key where the season info is stored
}
}
}
//// Iterate over each key in the "hist" object
//for (let key of Object.keys(doc.hist)) {
// // Update price and relevance for each item in the current key
// setAnchors(doc.hist[key], doc.chan[0], doc.v1ds, doc.v0ds, key);
//}
//// Assign the most relevant market price and key to the top level of the document
//if (mostRelevantMarketPrice !== null) {
// doc.mostRelevantMarketPriceInfo = {
// price: mostRelevantMarketPrice,
// price_early: mostRelevantMarketPriceEarly,
// source: mostRelevantMarketSource,
// season: mostRelevantMarketSeason,
// season_early: mostRelevantMarketSeasonEarly,
// relevance: highestMarketRelevanceLevel
// };
//}
//// Assign the most relevant customer price and key to the top level of the document
//if (mostRelevantCustomerPriceRecent !== null) {
// doc.mostRelevantCustomerPriceInfo = {
// price: mostRelevantCustomerPriceRecent,
// price_early: mostRelevantCustomerPriceEarly,
// source: mostRelevantCustomerSource,
// season: mostRelevantCustomerSeasonRecent,
// season_early: mostRelevantCustomerSeasonEarly,
// relevance: highestCustomerRelevanceLevel
// };
//}

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 INTO
_mold,_stlc,_v1ds , _v0ds, _iidx _mold,_stlc,_v1ds , _v0ds, _iidx
FROM FROM
"CMS.CUSLG".itemmv i "CMS.CUSLG".itemm i
INNER JOIN rlarp.molds m ON INNER JOIN rlarp.molds m ON
m.stlc = i.stlc m.stlc = i.stlc
WHERE 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) CREATE OR REPLACE FUNCTION rlarp.get_guidance_dseg(_bill text, _ship text, _stlc text, _dseg text, _qty numeric, _seas int)
RETURNS jsonb RETURNS jsonb
LANGUAGE plpgsql AS LANGUAGE plpgsql AS
@ -13,6 +13,12 @@ DECLARE
_prem jsonb; _prem jsonb;
_mold text; _mold text;
_item text; _item text;
_unti text;
_pltq numeric;
_cstd numeric;
_cstdina numeric;
_fstd numeric;
_fstdina numeric;
_cust text; _cust text;
_curr text; _curr text;
_rate numeric; _rate numeric;
@ -27,6 +33,11 @@ DECLARE
_list jsonb; _list jsonb;
_iidx jsonb; _iidx jsonb;
_itemr text; _itemr text;
_input jsonb;
_product jsonb;
_customer jsonb;
_hist jsonb;
_pricing jsonb;
BEGIN BEGIN
--_item := 'AMK06000G18B054'; --_item := 'AMK06000G18B054';
@ -38,90 +49,141 @@ BEGIN
_v0ds := CASE split_part(substring(_dseg,4,100), '.',1) WHEN 'B' THEN 'BASE' ELSE 'COLOR' END || CASE split_part(substring(_dseg,4,100), '.',2) WHEN 'L' THEN ' LABELED' WHEN 'P' THEN ' PRINTED' ELSE '' END; _v0ds := CASE split_part(substring(_dseg,4,100), '.',1) WHEN 'B' THEN 'BASE' ELSE 'COLOR' END || CASE split_part(substring(_dseg,4,100), '.',2) WHEN 'L' THEN ' LABELED' WHEN 'P' THEN ' PRINTED' ELSE '' END;
_v1ds := _dseg; _v1ds := _dseg;
_input := jsonb_build_object(
'inputs'
,jsonb_build_object(
'dseg',_dseg,
'v0ds',_v0ds,
'v1ds',_v1ds,
'bill',_bill,
'ship',_ship,
'stlc',_stlc,
'qty',_qty,
'season',_seas
));
----------------base product-------------------------------- ----------------base product--------------------------------
SELECT SELECT
part_group part_group
,item ,item
,stlc
,idxk ,idxk
,prefer ,prefer
,pltq
,curstdus
,curstdus_ina
,futstdus
,futstdus_ina
INTO INTO
_mold _mold
,_item ,_item
,_stlc
,_iidx ,_iidx
,_itemr ,_itemr
,_pltq
,_cstd
,_cstdina
,_fstd
,_fstdina
FROM FROM
( (
SELECT SELECT
m.part_group i.partgroup part_group
,min(i.item) item ,min(i.item) item
,i.stlc ,i.stlc
,i.v1ds ,i.v1ds
,i.v0ds ,_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 ,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 FROM
"CMS.CUSLG".itemmv i "CMS.CUSLG".itemm i
INNER JOIN rlarp.molds m ON LEFT OUTER JOIN _ds ON
m.stlc = i.stlc _ds.colgrp = i.colgrp
AND _ds.brand = SUBSTRING(i.branding,1,1)
--INNER JOIN rlarp.molds m ON
-- m.stlc = i.stlc
WHERE WHERE
i.stlc = _stlc i.stlc = _stlc
GROUP BY GROUP BY
m.part_group i.partgroup
,i.stlc ,i.stlc
,i.v1ds ,i.v1ds
,i.v0ds ,_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)) ,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 ) best
ORDER BY ORDER BY
prefer DESC prefer DESC
LIMIT 1; LIMIT 1;
_rslt := jsonb_build_object('mold',_mold,'v1ds',_v1ds,'v0ds',_v0ds,'stlc',_stlc,'item',_item,'item rel',_itemr,'desg',_dseg)||_iidx; _product :=
RAISE NOTICE 'item data %', _iidx; jsonb_build_object(
'product'
,jsonb_build_object(
'mold',_mold
,'item',_item
,'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------------------------------------- ----------------channel-------------------------------------
SELECT rlarp.channel_code(_bill, _ship) INTO _chan; SELECT rlarp.get_cust(_bill, _ship) INTO _customer;
_rslt := _rslt||jsonb_build_object('chan',_chan); --_customer := jsonb_build_object('chan',_chan);
RAISE NOTICE 'chan %', _chan;
----------------customer------------------------------------ ----------------customer------------------------------------
SELECT dba INTO _cust FROM rlarp.cust WHERE code = CASE WHEN _chan = 'DRP' THEN _ship ELSE _bill END ; --SELECT dba INTO _cust FROM rlarp.cust WHERE code = CASE WHEN _chan = 'DRP' THEN _ship ELSE _bill END ;
SELECT --SELECT
currency, -- currency,
(SELECT -- (SELECT
x.rate -- x.rate
FROM -- FROM
rlarp.ffcret x -- rlarp.ffcret x
WHERE -- WHERE
x.perd = (select fspr from rlarp.gld where drange @> current_date) -- x.perd = (select fspr from rlarp.gld where drange @> current_date)
AND x.rtyp = 'MA' -- AND x.rtyp = 'MA'
and x.fcur = currency -- and x.fcur = currency
AND x.tcur = 'US' -- AND x.tcur = 'US'
) -- )
INTO --INTO
_curr -- _curr
,_rate -- ,_rate
FROM --FROM
rlarp.cust -- rlarp.cust
WHERE --WHERE
code = _bill; -- code = _bill;
_rslt = _rslt||jsonb_build_object('cust',_cust,'curr',_curr,'fxrate',_rate); --_customer := jsonb_build_object(
RAISE NOTICE 'cust %', _cust; -- 'customer',
-- _customer||jsonb_build_object(
-- 'cust',_cust
-- ,'curr',_curr
-- ,'fxrate',_rate
-- )
--);
--RAISE NOTICE 'cust %', jsonb_pretty(_customer);
----------------price history------------------------------- ----------------price history-------------------------------
SELECT _rslt||jsonb_build_object('hist',rlarp.get_hist(_mold, _v1ds, _cust, substring(_chan,1,1))) INTO _rslt ; --RAISE NOTICE 'varb %', _customer;
RAISE NOTICE 'result %', _rslt; 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------------------------------ ----------------target pricing------------------------------
SELECT SELECT
jsonb_build_object( jsonb_build_object(
'v0tp', 'v0tp',
target_price, target_price,
'stdv', 'v0stdv',
stdev_price stdev_price
) )
INTO INTO
@ -132,14 +194,14 @@ BEGIN
mold = _stlc mold = _stlc
AND season = _seas AND season = _seas
AND data_segment = _v0ds AND data_segment = _v0ds
AND region = 'ALL'; AND region = 'ALL'
_rslt := _rslt||COALESCE(_v0tp,'{}'::jsonb); AND chan = _customer->'customer'->>'chantp';
----------------target pricing------------------------------ ----------------target pricing------------------------------
SELECT SELECT
jsonb_build_object( jsonb_build_object(
'v1tp', 'v1tp',
target_price, target_price,
'stdv', 'v1stdv',
stdev_price stdev_price
) )
INTO INTO
@ -150,12 +212,12 @@ BEGIN
mold = _stlc mold = _stlc
AND season = _seas AND season = _seas
AND data_segment = _dseg AND data_segment = _dseg
AND region = 'ALL'; AND region = 'ALL'
AND chan = _customer->'customer'->>'chantp';
--RAISE NOTICE 'target: %', jsonb_pretty(_targ); --RAISE NOTICE 'target: %', jsonb_pretty(_targ);
_rslt := _rslt||COALESCE(_v1tp,'{}'::jsonb); _pricing := (COALESCE(_v0tp,'{}'::jsonb)||COALESCE(_v1tp,'{}'::jsonb));
----------------inflation index----------------------------- ----------------inflation index-----------------------------
RAISE NOTICE 'infaltion : %', jsonb_pretty(_iidx);
SELECT SELECT
jsonb_build_object( jsonb_build_object(
'iidx' 'iidx'
@ -176,17 +238,21 @@ BEGIN
) )
GROUP BY GROUP BY
priority; priority;
_rslt := _rslt||COALESCE(_iidx,'{}'::jsonb); _pricing := _pricing||COALESCE(_iidx,'{}'::jsonb);
--RAISE NOTICE 'add targets: %', jsonb_pretty(_pricing);
----------------list pricing--------------------------------- ----------------list pricing---------------------------------
SELECT coalesce(rlarp.get_list(_bill, _ship, _item, _qty),'{}'::jsonb) INTO _list; SELECT coalesce(rlarp.get_list(_bill, _ship, _item, _qty),'{}'::jsonb) INTO _list;
_rslt := _rslt||_list; _pricing := _pricing||_list;
--RAISE NOTICE 'list: %', jsonb_pretty(_list); --RAISE NOTICE 'add list: %', jsonb_pretty(_pricing);
----------------get premium for quote hist gap-------------- ----------------get premium for quote hist gap--------------
SELECT coalesce(rlarp.get_premium(_stlc, _seas, (SELECT xchan FROM _chx WHERE chan = _chan),_rslt->'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;
_rslt := _rslt||_prem; _pricing := jsonb_build_object('pricing',_pricing||_prem);
--RAISE NOTICE 'list: %', jsonb_pretty(_list); --RAISE NOTICE 'add bridge: %', jsonb_pretty(_pricing);
_rslt := _input||_product||_customer||_pricing||_hist;
RETURN _rslt; RETURN _rslt;

View File

@ -16,6 +16,7 @@ sort AS (
,gset.* ,gset.*
,row_number() OVER (PARTITION BY p.agglevel ORDER BY avgunits DESC) rn ,row_number() OVER (PARTITION BY p.agglevel ORDER BY avgunits DESC) rn
,stats.* ,stats.*
,season
FROM FROM
rlarp.price_pool_dev p rlarp.price_pool_dev p
JOIN LATERAL jsonb_to_record(gset) AS gset( JOIN LATERAL jsonb_to_record(gset) AS gset(
@ -37,6 +38,8 @@ sort AS (
,early_price numeric ,early_price numeric
,recent_season int ,recent_season int
,recent_price numeric ,recent_price numeric
,last_season int
,last_price numeric
) ON TRUE ) ON TRUE
WHERE WHERE
gset @> jsonb_build_object( gset @> jsonb_build_object(
@ -95,6 +98,9 @@ SELECT
,early_price ,early_price
,recent_season ,recent_season
,recent_price ,recent_price
,last_season
,last_price
,season
FROM FROM
sort sort
) )
@ -104,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) ,('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 exact' ,4)
,('market v0ds other' ,9) ,('market v0ds other' ,9)
,('market v0ds vol' ,5) ,('market v0ds vol' ,5)
@ -130,13 +136,16 @@ FROM
,'early_price' ,early_price ,'early_price' ,early_price
,'recent_season' ,recent_season ,'recent_season' ,recent_season
,'recent_price' ,recent_price ,'recent_price' ,recent_price
,'last_season' ,last_season
,'last_price' ,last_price
,'ds' ,COALESCE(v1ds,v0ds) ,'ds' ,COALESCE(v1ds,v0ds)
,'rank' ,'rank' ,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC)
,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC) ,'pricinghistory' ,season
) )
) )
) doc ) doc
,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC) rnk ,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC) rnk
,season
FROM FROM
flag flag
LEFT OUTER JOIN rel ON LEFT OUTER JOIN rel ON

173
sql/get_hist_debug.pg.sql Normal file
View File

@ -0,0 +1,173 @@
WITH
sel AS (select 'v1:T..PLT..' _v1ds, 'KAWAHARA NURSERY' _cust, 'AZE10001' _mold, 'D' _chan)
,sort AS (
SELECT
p.agglevel
,CASE WHEN p.agglevel ? 'cust' THEN 'cust' ELSE 'market' END source
,COALESCE(gset.v1ds = _v1ds,false) v1ds_match
,gset.chan = _chan chan_match
,gset.*
,row_number() OVER (PARTITION BY p.agglevel ORDER BY avgunits DESC) rn
,stats.*
,season
FROM
rlarp.price_pool_dev p
CROSS JOIN sel
JOIN LATERAL jsonb_to_record(gset) AS gset(
chan text
,mold text
,v1ds text
,v0ds text
,cust text
,vers text
--,nurs text
--,ghse text
) ON TRUE
JOIN LATERAL jsonb_to_record(stats) AS stats(
avgunits numeric
,avgtargetprice numeric
,avgordcount numeric
,avgcustcount numeric
,early_season int
,early_price numeric
,recent_season int
,recent_price numeric
,last_season int
,last_price numeric
) ON TRUE
WHERE
gset @> jsonb_build_object(
'mold', _mold
,'vers', 'A'
)
AND (
gset @> jsonb_build_object(
'cust', _cust
)
OR NOT gset ? 'cust'
)
AND COALESCE(stats.early_season,stats.recent_season) IS NOT NULL
AND NOT p.agglevel ? 'nurs'
AND NOT p.agglevel ? 'ghse'
ORDER BY
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
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 relevance
,source
,v1ds_match
,chan_match
,chan
,mold
,v1ds
,v0ds
,cust
,vers
,rn
,row_number() OVER (PARTITION BY source ORDER BY rel.prefer ASC) rnk
,avgunits
,avgordcount
,avgcustcount
,avgtargetprice
,early_season
,early_price
,recent_season
,recent_price
,last_season
,last_price
,season
FROM
sort
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
-- flag.relevance
--,flag.source
--,rel.prefer
--,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC) best
jsonb_strip_nulls(
jsonb_build_object(
flag.source
,jsonb_build_object(
'relevance' ,relevance
,'avgunits' ,avgunits
,'avgordcount' ,avgordcount
,'avgcustcount' ,avgcustcount
,'avgtargetprice' ,avgtargetprice
,'early_season' ,early_season
,'early_price' ,early_price
,'recent_season' ,recent_season
,'recent_price' ,recent_price
,'last_season' ,last_season
,'last_price' ,last_price
,'ds' ,COALESCE(v1ds,v0ds)
,'rank' ,rnk
,'pricinghistory' ,season
)
)
) doc
,rnk
,season
FROM
flag
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 flag
--SELECT jsonb_obj_aggc(doc) FROM rel_sort WHERE rnk = 1;

233
sql/get_list.pg.sql Normal file
View File

@ -0,0 +1,233 @@
CREATE OR REPLACE FUNCTION rlarp.get_list(_billto text, _shipto text, _item text, _qty numeric)
RETURNS jsonb
LANGUAGE plpgsql AS
--DO
$func$
DECLARE
-- _billto text;
-- _shipto text;
-- _item text;
-- _qty numeric;
_rslt jsonb;
BEGIN
--_billto := 'DIAM0004';
--_shipto := 'DIAM0004';
--_item := 'AMK06000G18B054';
--_qty := 5400;
CREATE TEMP TABLE IF NOT EXISTS cp AS (
--every unqiue price list scenario
SELECT
s.bill_cust
,s.ship_cust
,s.part
,i.unti unit
,s.qtyord
,i.uomp
,CASE WHEN COALESCE(sc.plevel,'') = '' THEN bc.plevel ELSE sc.plevel END plvl
FROM
(SELECT _billto bill_cust, _shipto ship_cust, _item part, _qty qtyord) s
LEFT OUTER JOIN "CMS.CUSLG".itemm i ON
i.item = s.part
LEFT OUTER JOIN rlarp.cust sc ON
sc.code = s.ship_cust
LEFT OUTER JOIN rlarp.cust bc ON
bc.code = s.bill_cust
WHERE
CASE WHEN COALESCE(sc.plevel,'') = '' THEN bc.plevel ELSE sc.plevel END <> ''
GROUP BY
s.bill_cust
,s.ship_cust
,s.part
,i.unti
,s.qtyord
,i.uomp
,CASE WHEN COALESCE(sc.plevel,'') = '' THEN bc.plevel ELSE sc.plevel END
) WITH DATA;
--drop table cp
--SELECT * FROM cp WHERE bill_cust = 'DIST0008' and part = 'TCF06SG0G18C050' and ship_cust = 'DIST0007'
CREATE TEMP TABLE IF NOT EXISTS plfull AS (
--all all rows for relevant part/price levels
WITH
----------unique price points-----------------------
lvl AS (
SELECT DISTINCT
plvl
,part
,unit
FROM
cp
)
------------join prices for price level------------
,plj AS (
SELECT
lvl.plvl
,lvl.part
,lvl.unit
,i.jcplcd
,i.jcunit
,i.jcvoll
,i.jcpric
FROM
lvl
INNER JOIN "CMS.CUSLG".iprcbhc hc ON
hc.jbplvl = lvl.plvl
AND current_date BETWEEN hc.jbfdat AND hc.jbtdat
INNER JOIN lgdat.iprcc i ON
i.jcplcd = hc.jbplcd
AND i.jcpart = lvl.part
)
-----------uom conversions-------------------
,uom AS (
SELECT
uom.p part
,uom.f
,uom.t
,uom.nm/uom.dm rate
FROM
(
SELECT
jsonb_agg(row_to_json(d)::jsonb) jdoc
FROM
(
SELECT DISTINCT
part partn
,jcunit fu
,unit tu
FROM
plj
WHERE
part <> ''
) d
) c
JOIN LATERAL rlarp.uom_array(c.jdoc) uom ON TRUE
)
------price list sorted---------------------
SELECT
plj.plvl
,plj.part
,plj.unit
,plj.jcplcd
--,plj.jcunit
,round(plj.jcvoll * uom.rate,5) vol
,round(plj.jcpric / uom.rate,5) price
--,uom.rate
--dont partition by list code becuase there could be duplicate assignments
,row_number() OVER (PARTITION BY plj.plvl, plj.part, plj.unit ORDER BY round(plj.jcvoll * uom.rate,5) ASC) rn
FROM
plj
INNER JOIN uom ON
uom.part = plj.part
AND uom.f = plj.jcunit
AND uom.t = plj.unit
) WITH DATA;
--select * from plfull
CREATE TEMP TABLE IF NOT EXISTS pl AS (
--create from-to volume range for price list
WITH RECURSIVE
pl(plvl, listcode, part, unit, volf, volt, price1, price2, rn, lvl) AS (
SELECT
p1.plvl
,p1.jcplcd as listcode
,p1.part
,p1.unit
,0::numeric volf
,p1.vol volt
,null::numeric price1
,p1.price price2
,p1.rn
,0 lvl
FROM
plfull p1
WHERE
p1.rn = 1
UNION ALL
SELECT
pl.plvl
,COALESCE(f.jcplcd,pl.listcode) listcode
,pl.part
,pl.unit
,pl.volt volf
,COALESCE(f.vol,999999999) volt
,pl.price2 price1
,f.price price2
,f.rn
,pl.lvl + 1
FROM
pl
LEFT OUTER JOIN plfull f ON
f.plvl = pl.plvl
AND f.part = pl.part
AND f.unit = pl.unit
AND f.rn = pl.rn + 1
WHERE
pl.price2 IS NOT NULL
) SEARCH DEPTH FIRST BY part, plvl, unit SET ordercol
SELECT
plvl
,listcode
,part
,unit
,volf
,volt
,numrange(volf, volt) vrange
,price1 price
--,price2
--,rn
--,lvl
--,ordercol
FROM
pl
ORDER BY
ordercol
) WITH DATA;
--select * from pl
--add primary key to test if there are any price level that overlap the same part number
--alter table pl add primary key (plvl, part, unit, vrange);
CREATE TEMP TABLE IF NOT EXISTS cpj AS (
--go back to every unique scenario and join to modified list with volum range
SELECT
cp.*
,pl.price
,pl.listcode
FROM
cp
INNER JOIN pl ON
pl.part = cp.part
AND pl.plvl = cp.plvl
AND pl.unit = cp.unit
WHERE
pl.vrange @> cp.qtyord
) WITH DATA;
--select * from cpj where part = 'TCF06SG0G18C050'
SELECT
jsonb_build_object('list',cpj.price)
||jsonb_build_object('listcode',cpj.listcode)
||jsonb_build_object('plvl',cpj.plvl)
INTO
_rslt
FROM
cpj;
--RAISE NOTICE 'list: %' ,_rslt;
DROP TABLE IF EXISTS cp;
DROP TABLE IF EXISTS plfull;
DROP TABLE IF EXISTS pl;
DROP TABLE IF EXISTS cpj;
RETURN _rslt;
END;
$func$;

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() --CREATE OR REPLACE PROCEDURE rlarp.price_pool()
--LANGUAGE plpgsql AS --LANGUAGE plpgsql AS
--$func$ --$func$
--BEGIN --BEGIN;
DROP TABLE IF EXISTS rlarp.price_pool_dev; DROP MATERIALIZED VIEW IF EXISTS rlarp.price_pool_dev CASCADE;
CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS ( --CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
CREATE MATERIALIZED VIEW rlarp.price_pool_dev AS (
WITH WITH
agg AS ( agg AS (
SELECT SELECT
@ -75,6 +76,76 @@ CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
HAVING HAVING
round(sum(o.qty),0) > 0 round(sum(o.qty),0) > 0
AND round(sum(o.sales_usd)/sum(o.qty),5) > 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 ( ,gsets AS (
SELECT SELECT
@ -124,8 +195,9 @@ CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
,round(avg(ordcount) ,1) avgordcount ,round(avg(ordcount) ,1) avgordcount
,round(avg(units) ,0) avgunits ,round(avg(units) ,0) avgunits
,round(avg(target_price),5) avgtargetprice ,round(avg(target_price),5) avgtargetprice
,min(oseas) FILTER (WHERE oseas BETWEEN 2020 AND 2022)::text early_season ,min(oseas) FILTER (WHERE oseas BETWEEN 2020 AND 2023)::text early_season
,min(oseas) FILTER (WHERE oseas >= 2024)::text recent_season ,min(oseas) FILTER (WHERE oseas >= 2024)::text recent_season
,max(oseas) FILTER (WHERE oseas >= 2020)::text last_season
--,oseas --,oseas
--,units --,units
--,sales_usd --,sales_usd
@ -159,6 +231,10 @@ CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
,recent_season::int ,recent_season::int
,'recent_price' ,'recent_price'
,(season->recent_season->>'price_usd')::numeric ,(season->recent_season->>'price_usd')::numeric
,'last_season'
,last_season::int
,'last_price'
,(season->last_season->>'price_usd')::numeric
) stats ) stats
FROM FROM
find_stats find_stats
@ -166,3 +242,4 @@ CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
) WITH DATA; ) WITH DATA;
create index ppd_gset on rlarp.price_pool_dev using gin (gset); create index ppd_gset on rlarp.price_pool_dev using gin (gset);
--END;