Compare commits
41 Commits
javascript
...
master
Author | SHA1 | Date | |
---|---|---|---|
86656f6952 | |||
fb5968343a | |||
51ba3fe3ca | |||
6d987ee0aa | |||
618a744e05 | |||
de9ecd5033 | |||
5234516dee | |||
970968f980 | |||
3050bbfe7a | |||
50781c6b2f | |||
229291f9bc | |||
e1406f70ab | |||
885a2982ee | |||
eb0c969ec7 | |||
a2322876e1 | |||
eca0da084e | |||
a63f176293 | |||
b04f67d9f0 | |||
d6c4d71851 | |||
764a6f8ebe | |||
062cea58a6 | |||
14ee797b91 | |||
aaa62afb5d | |||
453ec561ee | |||
baeeaccf53 | |||
43e64a1533 | |||
0219b2d5ce | |||
8a9102dbca | |||
56d139c22d | |||
52e802b389 | |||
dc1f493700 | |||
32217d52c4 | |||
87d2bd39cd | |||
428d73dbbc | |||
f91beee772 | |||
a5acb798b4 | |||
7919160ecc | |||
15c60c629d | |||
b81261af3f | |||
0922862c80 | |||
96eee9ff5b |
21
api.ts
21
api.ts
@ -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());
|
||||||
|
|
||||||
|
@ -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
|
// Create a new object and sort the keys
|
||||||
function setAnchors(items, channelFirstChar, v1ds, v0ds, histKey) {
|
const sortedObj = {};
|
||||||
for (let item of items) {
|
Object.keys(obj).sort().forEach(key => {
|
||||||
// Update the last_price with the most recent price
|
// Recursively apply the function for nested objects
|
||||||
const years = Object.keys(item.season).map(Number).filter(year => year >= 2020);
|
sortedObj[key] = sortObjectKeys(obj[key]);
|
||||||
if (years.length > 0) {
|
});
|
||||||
const recentYear = Math.max(...years.map(Number));
|
|
||||||
const earlyYear = Math.min(...years.map(Number));
|
return sortedObj;
|
||||||
const lastPrice = item.season[recentYear].price_usd;
|
}
|
||||||
const earlyPrice = item.season[earlyYear].price_usd;
|
|
||||||
item.last_price = lastPrice;
|
function getAdjValue(number) {
|
||||||
item.early_price = earlyPrice;
|
const data = [
|
||||||
item.last_season = recentYear;
|
{f: 2.001, t: 1000, snap: 3, adj: 0 },
|
||||||
item.early_season = earlyYear;
|
{f: 1.001, t: 2, snap: 2, adj: 0 },
|
||||||
} else {
|
{f: 0.1, t: 1, snap: 1, adj: 0 },
|
||||||
item.last_price = null; // or some default value as appropriate
|
{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)) {
|
||||||
// Initialize relevance as numeric value
|
let [cprice, creason, csource, csnap] = priceObject[key];
|
||||||
let marketRelevance = 0; // Assume 0 is 'not relevant'
|
// Check if the current price is lower than the found so far
|
||||||
let customerRelevance = 0; // Assume 0 is 'not relevant'
|
if (cprice && cprice < Price) {
|
||||||
|
Price = cprice;
|
||||||
|
Reason = creason;
|
||||||
// Check if the first character of the item's channel matches the first character of the document's channel
|
Source = csource;
|
||||||
if (item.chan.charAt(0) === channelFirstChar) {
|
Snapped = csnap;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return {Reason, Price, Source, Snapped};
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Iterate over each key in the "hist" object
|
function ceiling(value, significance) {
|
||||||
//for (let key of Object.keys(doc.hist)) {
|
return Math.ceil(value / significance) * significance;
|
||||||
// // 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
|
function r5(value) {
|
||||||
//if (mostRelevantMarketPrice !== null) {
|
return Number(value.toFixed(5));
|
||||||
// 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
|
function pp(value) {
|
||||||
//if (mostRelevantCustomerPriceRecent !== null) {
|
// Multiplies by 1000 and rounds to the nearest 2 decimals
|
||||||
// doc.mostRelevantCustomerPriceInfo = {
|
var result = Math.round(value * 1000 * 100) / 100;
|
||||||
// price: mostRelevantCustomerPriceRecent,
|
|
||||||
// price_early: mostRelevantCustomerPriceEarly,
|
|
||||||
// source: mostRelevantCustomerSource,
|
|
||||||
// season: mostRelevantCustomerSeasonRecent,
|
|
||||||
// season_early: mostRelevantCustomerSeasonEarly,
|
|
||||||
// relevance: highestCustomerRelevanceLevel
|
|
||||||
// };
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
// 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------------------------------------------------
|
||||||
|
|
||||||
const targetPrice = doc.v1tp ?? doc.v0tp;
|
let snap = .0005;
|
||||||
const earlyPrice = doc.hist?.cust?.early_price;
|
|
||||||
let anchorPrice = null;
|
let custPrice = r5(bridgedPrice * (1 + custAdder));
|
||||||
let anchorSource = null;
|
let custSeason = earlyCustSeason;
|
||||||
let bridgePremium = doc.bridgePremium ?? 1.00000;
|
let custReason = bridgePremium
|
||||||
if (!targetPrice) {
|
? `${custSeason} (similar ${altHist} price ${pp(earlyCustPrice)} x ${bridgePremium} = ${pp(bridgedPrice)})${custAddReason}`
|
||||||
anchorSource = "No target pricing setup";
|
: `${custSeason} price ${pp(bridgedPrice)}${custAddReason}`;
|
||||||
doc.finalReason = "No target pricing setup";
|
let markPrice = r5(earlyMarkPrice * (1 + markAdder));
|
||||||
} else {
|
let markReason = `${earlyMarkSeason} ASP ${pp(earlyMarkPrice)}${markAddReason}`;
|
||||||
// Determine the anchor price and source
|
let targPrice = targetPrice ? r5(targetPrice * (1 + markAdder)) : null;
|
||||||
if (earlyPrice) {
|
let targReason = `Target price ${pp(targetPrice)}${markAddReason}`;
|
||||||
// translate alternate product history to current product quoted
|
let listPrice = listUSD;
|
||||||
anchorPrice = Number((earlyPrice * bridgePremium).toFixed(5));
|
let listReason = fxrate === 1 ? `list ${pp(list)}` : `list ${pp(list)} CAD ${pp(listUSD)} USD`;
|
||||||
// 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));
|
let prices = {
|
||||||
const inflationFactor = doc.iidx[inflation] + 1;
|
cust: [custPrice, custReason, "cust", r5(ceiling(custPrice,snap))],
|
||||||
var calcPrice = parseFloat((anchorPrice * inflationFactor).toFixed(5));
|
mark: [markPrice, markReason, "mark", r5(ceiling(markPrice,snap))],
|
||||||
let finalReason = "";
|
targ: [targPrice, targReason, "targ", r5(ceiling(targPrice,snap))],
|
||||||
if (calcPrice >= doc.list && doc.list) {
|
list: [listPrice, listReason, "list", r5(ceiling(listPrice,snap))]
|
||||||
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;
|
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
70
live_quote_mv.pg.sql
Normal 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
118
set_anchors.ts
Normal 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
152
sql/apply_guidance.pg.sql
Normal 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$;
|
33
sql/consume_pricepool.pg.sql
Normal file
33
sql/consume_pricepool.pg.sql
Normal 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
79
sql/get_cust.pg.sql
Normal 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$;
|
@ -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
|
||||||
|
@ -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
|
||||||
@ -10,23 +10,34 @@ DECLARE
|
|||||||
--_ship text;
|
--_ship text;
|
||||||
--_qty numeric;
|
--_qty numeric;
|
||||||
--_seas int;
|
--_seas int;
|
||||||
_prem jsonb;
|
_prem jsonb;
|
||||||
_mold text;
|
_mold text;
|
||||||
_item text;
|
_item text;
|
||||||
_cust text;
|
_unti text;
|
||||||
_curr text;
|
_pltq numeric;
|
||||||
_rate numeric;
|
_cstd numeric;
|
||||||
_v1ds text;
|
_cstdina numeric;
|
||||||
_v0ds text;
|
_fstd numeric;
|
||||||
_v1tp jsonb;
|
_fstdina numeric;
|
||||||
_v0tp jsonb;
|
_cust text;
|
||||||
_chan text;
|
_curr text;
|
||||||
_regn text;
|
_rate numeric;
|
||||||
_rslt jsonb;
|
_v1ds text;
|
||||||
_targ jsonb;
|
_v0ds text;
|
||||||
_list jsonb;
|
_v1tp jsonb;
|
||||||
_iidx jsonb;
|
_v0tp jsonb;
|
||||||
_itemr text;
|
_chan text;
|
||||||
|
_regn text;
|
||||||
|
_rslt jsonb;
|
||||||
|
_targ jsonb;
|
||||||
|
_list jsonb;
|
||||||
|
_iidx jsonb;
|
||||||
|
_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;
|
||||||
|
|
||||||
|
@ -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
173
sql/get_hist_debug.pg.sql
Normal 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
233
sql/get_list.pg.sql
Normal 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$;
|
||||||
|
|
69
sql/live_quote_nohist.pg.sql
Normal file
69
sql/live_quote_nohist.pg.sql
Normal 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
70
sql/livequotes.pg.sql
Normal 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
59
sql/livequotes_dev.pg.sql
Normal 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
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user