Compare commits
No commits in common. "master" and "javascript_relevance_logic" have entirely different histories.
master
...
javascript
17
.gitignore
vendored
17
.gitignore
vendored
@ -1,17 +1,2 @@
|
||||
.env
|
||||
.vscode/
|
||||
.idea/hc_ubm.iml
|
||||
.idea/modules.xml
|
||||
.idea/workspace.xml
|
||||
.project
|
||||
.dbeaver-data-sources.xml
|
||||
Diagrams/
|
||||
.vs/
|
||||
*.swp
|
||||
*.swo
|
||||
.settings/org.eclipse.core.resources.prefs
|
||||
.vscode/*
|
||||
.dbeaver/
|
||||
.env
|
||||
.obsidian/
|
||||
|
||||
.vscode/
|
21
api.ts
21
api.ts
@ -34,35 +34,18 @@ const query = await Deno.readTextFile("sql/get.pg.sql");
|
||||
const query_dseg = await Deno.readTextFile("sql/get_dseg.pg.sql");
|
||||
|
||||
// exact scenario for existing codes
|
||||
router.get('/code/:billcode/:shipcode/:partcode/:qty', async (ctx) => {
|
||||
router.get('/code_price/:billcode/:shipcode/:partcode/:qty', async (ctx) => {
|
||||
const { billcode, shipcode, partcode, qty } = ctx.params;
|
||||
const result = await client.queryObject({args: [billcode, shipcode, partcode, qty], text: query} );
|
||||
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
|
||||
router.get('/dseg_price/:billcode/:shipcode/:stlc/:dseg/:qty', async (ctx) => {
|
||||
const { billcode, shipcode, stlc, dseg, qty } = ctx.params;
|
||||
const result = await client.queryObject({args: [billcode, shipcode, stlc, dseg, qty], text: query_dseg} );
|
||||
const ag = apply_guidance(result.rows[0]["doc"]);
|
||||
ctx.response.body = ag.guidance.finalPrice.Snapped;
|
||||
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_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.allowedMethods());
|
||||
|
||||
|
@ -1,165 +1,167 @@
|
||||
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;
|
||||
|
||||
function sortObjectKeys(obj) {
|
||||
// If the object is not an actual object or is an array, return it as is
|
||||
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
||||
return obj;
|
||||
}
|
||||
let mostRelevantCustomerPriceEarly = null;
|
||||
let mostRelevantCustomerPriceRecent = null;
|
||||
let mostRelevantCustomerKey = null;
|
||||
let mostRelevantCustomerSeasonEarly = null;
|
||||
let mostRelevantCustomerSeasonRecent = null;
|
||||
let highestCustomerRelevanceLevel = 0;
|
||||
let mostRelevantCustomerSource = null;
|
||||
|
||||
// Create a new object and sort the keys
|
||||
const sortedObj = {};
|
||||
Object.keys(obj).sort().forEach(key => {
|
||||
// Recursively apply the function for nested objects
|
||||
sortedObj[key] = sortObjectKeys(obj[key]);
|
||||
});
|
||||
|
||||
return sortedObj;
|
||||
}
|
||||
|
||||
function getAdjValue(number) {
|
||||
const data = [
|
||||
{f: 2.001, t: 1000, snap: 3, adj: 0 },
|
||||
{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;
|
||||
// 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
|
||||
}
|
||||
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;
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
return {Reason, Price, Source, Snapped};
|
||||
}
|
||||
|
||||
function ceiling(value, significance) {
|
||||
return Math.ceil(value / significance) * significance;
|
||||
}
|
||||
//// 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);
|
||||
//}
|
||||
|
||||
function r5(value) {
|
||||
return Number(value.toFixed(5));
|
||||
}
|
||||
//// 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
|
||||
// };
|
||||
//}
|
||||
|
||||
function pp(value) {
|
||||
// Multiplies by 1000 and rounds to the nearest 2 decimals
|
||||
var result = Math.round(value * 1000 * 100) / 100;
|
||||
//// 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
|
||||
// };
|
||||
//}
|
||||
|
||||
// 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`;
|
||||
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}`;
|
||||
}
|
||||
|
||||
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))]
|
||||
const inflation = Math.max(...Object.keys(doc.iidx).map(Number));
|
||||
const inflationFactor = doc.iidx[inflation] + 1;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return doc;
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
-- FAnalysis.PRICING.lastprice definition
|
||||
|
||||
-- Drop table
|
||||
|
||||
-- DROP TABLE FAnalysis.PRICING.lastprice;
|
||||
|
||||
CREATE TABLE pricing.lastprice (
|
||||
customer varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
mold varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
part_stats nvarchar(MAX) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE NONCLUSTERED INDEX lastprice_cust_mold ON FAnalysis.PRICING.lastprice (customer ASC, mold ASC) ;
|
@ -1,59 +0,0 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Rebuild last price history at sales matrix refresh time
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
DELETE FROM pricing.lastprice;
|
||||
|
||||
WITH srt AS (
|
||||
SELECT
|
||||
customer,
|
||||
mold,
|
||||
part,
|
||||
version,
|
||||
qty,
|
||||
ROUND(sales_usd / qty, 5) AS price,
|
||||
odate,
|
||||
oseas,
|
||||
ordnum,
|
||||
quoten,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY customer, mold, part, version
|
||||
ORDER BY odate DESC
|
||||
) AS rn
|
||||
FROM rlarp.osm_stack
|
||||
WHERE
|
||||
--quotes can't be integrated until we have datasegment or correct part code
|
||||
version IN ('Actual'/*,'Quotes'*/) AND
|
||||
customer IS NOT NULL AND
|
||||
fs_line = '41010' AND
|
||||
calc_status <> 'CANCELLED' AND
|
||||
qty <> 0 AND
|
||||
mold <> ''
|
||||
),
|
||||
json_rows AS (
|
||||
SELECT
|
||||
customer,
|
||||
mold,
|
||||
part,
|
||||
version,
|
||||
CONCAT(
|
||||
'"', part, '":',
|
||||
(
|
||||
SELECT version, qty, price, odate, ordnum, quoten
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
)
|
||||
) AS part_json
|
||||
FROM srt
|
||||
WHERE rn = 1
|
||||
)
|
||||
,onerow AS (
|
||||
SELECT
|
||||
customer,
|
||||
mold,
|
||||
CONCAT('{', STRING_AGG(part_json, ','), '}') AS part_stats
|
||||
FROM json_rows
|
||||
GROUP BY customer, mold
|
||||
)
|
||||
INSERT INTO pricing.lastprice SELECT * FROM onerow;
|
||||
|
||||
--CREATE UNIQUE INDEX lastprice_cust_mold ON pricing.lastprice(customer, mold);
|
@ -1,26 +0,0 @@
|
||||
minimal setup to run a single pricing call:
|
||||
```sql
|
||||
EXEC pricing.single_price_call
|
||||
@bill = 'GRIF0001',
|
||||
@ship = 'GRIF0001',
|
||||
@part = 'XNS0T1G3G18B096',
|
||||
@stlc = 'XNS0T1G3',
|
||||
@v1ds = 'v1:T..PLT..',
|
||||
@vol = 9600;
|
||||
```
|
||||
|
||||
make sure pricing schema is setup
|
||||
|
||||
Target Prices
|
||||
----------------------
|
||||
1. create target table: `target_prices.ms.sql`
|
||||
2. populate targets: `target_prices_copy.ms.sql`
|
||||
|
||||
Price History
|
||||
----------------------
|
||||
1. create history table: `lastprice.ms.sql`
|
||||
2. populate history: `make_hist.ms.sql`
|
||||
|
||||
Proc Definitions
|
||||
----------------------
|
||||
1. create proc: `single_price_call.ms.sql`
|
@ -1,162 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.single_price_call
|
||||
@bill VARCHAR(100),
|
||||
@ship VARCHAR(100),
|
||||
@part VARCHAR(100),
|
||||
@stlc VARCHAR(100),
|
||||
@v1ds VARCHAR(100),
|
||||
@vol NUMERIC(18,6)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @phist NVARCHAR(MAX);
|
||||
|
||||
-- Declare table variable for the input row
|
||||
DECLARE @queue TABLE (
|
||||
bill VARCHAR(100),
|
||||
ship VARCHAR(100),
|
||||
part VARCHAR(100),
|
||||
stlc VARCHAR(100),
|
||||
v1ds VARCHAR(100),
|
||||
vol NUMERIC(18,6),
|
||||
chan VARCHAR(50),
|
||||
cust VARCHAR(100),
|
||||
tier VARCHAR(50),
|
||||
pltq NUMERIC(18,6),
|
||||
price NUMERIC(18,6),
|
||||
expl NVARCHAR(MAX),
|
||||
hist NVARCHAR(MAX),
|
||||
LAST nvarchar(max)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Insert input row into queue
|
||||
--------------------------------------------------------------------------------
|
||||
INSERT INTO @queue (bill, ship, part, stlc, v1ds, vol)
|
||||
VALUES (@bill, @ship, @part, @stlc, @v1ds, @vol);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 2: Enrich the row with chan, tier, cust, pltq
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
chan =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END,
|
||||
tier =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE ISNULL(sc.tier, bc.tier)
|
||||
END,
|
||||
cust =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN bc.dba
|
||||
ELSE sc.dba
|
||||
END
|
||||
ELSE q.bill
|
||||
END,
|
||||
pltq = i.mpck
|
||||
FROM @queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN CMSInterfaceIn.[CMS.CUSLG].itemm i ON i.item = q.part;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 3: Get last price info directly into @queue columns
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
q.hist = (
|
||||
SELECT TOP 1
|
||||
j.qty,
|
||||
j.price,
|
||||
j.odate,
|
||||
j.ordnum,
|
||||
j.quoten
|
||||
FROM pricing.lastprice lp
|
||||
OUTER APPLY OPENJSON(lp.part_stats) AS p
|
||||
OUTER APPLY OPENJSON(p.value)
|
||||
WITH (
|
||||
qty NUMERIC(20,5),
|
||||
price NUMERIC(20,5),
|
||||
odate DATE,
|
||||
ordnum INT,
|
||||
quoten INT
|
||||
) AS j
|
||||
WHERE
|
||||
lp.customer = q.cust
|
||||
AND lp.mold = SUBSTRING(q.part,1,8)
|
||||
AND p.[key] COLLATE SQL_Latin1_General_CP1_CI_AS = q.part
|
||||
ORDER BY j.odate DESC
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
),
|
||||
q.last = (
|
||||
SELECT TOP 1
|
||||
CAST(ROUND(j.price, 5) AS NVARCHAR(50)) -- must be string to store in NVARCHAR column
|
||||
FROM pricing.lastprice lp
|
||||
OUTER APPLY OPENJSON(lp.part_stats) AS p
|
||||
OUTER APPLY OPENJSON(p.value)
|
||||
WITH (
|
||||
qty NUMERIC(20,5),
|
||||
price NUMERIC(20,5),
|
||||
odate DATE,
|
||||
ordnum INT,
|
||||
quoten INT
|
||||
) AS j
|
||||
WHERE
|
||||
lp.customer = q.cust
|
||||
AND lp.mold = SUBSTRING(q.part,1,8)
|
||||
AND p.[key] COLLATE SQL_Latin1_General_CP1_CI_AS = q.part
|
||||
ORDER BY j.odate DESC
|
||||
)
|
||||
FROM @queue q;
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 4: Apply pricing and embed price history + last price from queue columns
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
price = tp.price,
|
||||
expl = (
|
||||
SELECT
|
||||
'target price' AS [source],
|
||||
tp.price AS [target_price],
|
||||
CAST(q.last AS NUMERIC(20,5)) AS [last_price],
|
||||
FLOOR(q.vol / NULLIF(q.pltq, 0)) AS [calculated_pallets],
|
||||
ROUND(q.vol / NULLIF(q.pltq, 0), 5) AS [exact_pallets],
|
||||
CONCAT(tp.lower_bound, '-', ISNULL(CAST(tp.upper_bound AS VARCHAR), '∞')) AS [volume range],
|
||||
q.cust AS [customer],
|
||||
q.chan AS [channel],
|
||||
q.tier AS [tier],
|
||||
JSON_QUERY(tp.math) AS [target math],
|
||||
JSON_QUERY(q.hist) AS [price history]
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
)
|
||||
FROM @queue q
|
||||
INNER JOIN pricing.target_prices tp ON
|
||||
q.stlc = tp.stlc
|
||||
AND q.v1ds = tp.ds
|
||||
AND q.chan = tp.chan
|
||||
AND q.tier = tp.tier
|
||||
AND FLOOR(q.vol / NULLIF(q.pltq, 0)) >= tp.lower_bound
|
||||
AND (
|
||||
tp.upper_bound IS NULL OR FLOOR(q.vol / NULLIF(q.pltq, 0)) < tp.upper_bound
|
||||
);
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step Last: Return just the enriched row
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT price, expl FROM @queue;
|
||||
END;
|
@ -1,18 +0,0 @@
|
||||
DROP TABLE pricing.target_prices;
|
||||
|
||||
CREATE TABLE pricing.target_prices (
|
||||
stlc nvarchar(8) NOT NULL,
|
||||
ds nvarchar(20) NOT NULL,
|
||||
chan nvarchar(3) NOT NULL,
|
||||
tier nvarchar(1) NOT NULL,
|
||||
vol nvarchar(20) NOT NULL,
|
||||
lower_bound int NOT NULL,
|
||||
upper_bound int NULL,
|
||||
price numeric(28,6) NOT NULL,
|
||||
math nvarchar(MAX) NULL
|
||||
);
|
||||
|
||||
ALTER TABLE pricing.target_prices
|
||||
ADD CONSTRAINT uq_target_prices_unique_combo
|
||||
UNIQUE (stlc, ds, chan, tier, vol, lower_bound);
|
||||
|
@ -1,23 +0,0 @@
|
||||
DELETE FROM pricing.target_prices;
|
||||
|
||||
INSERT INTO
|
||||
pricing.target_prices
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
-- Extract lower bound: text between '[' and ','
|
||||
TRY_CAST(SUBSTRING(vol, 2, CHARINDEX(',', vol) - 2) AS INT) AS lower_bound,
|
||||
-- Extract upper bound: text between ',' and ')'
|
||||
CASE
|
||||
WHEN RIGHT(vol, 2) = ',)' THEN NULL
|
||||
ELSE TRY_CAST(SUBSTRING(vol, CHARINDEX(',', vol) + 1, LEN(vol) - CHARINDEX(',', vol) - 1) AS INT)
|
||||
END AS upper_bound,
|
||||
price,
|
||||
math
|
||||
FROM
|
||||
usmidsap02.ubm.pricequote.target_prices_view;
|
||||
|
||||
--SELECT COUNT(*) FROM pricing.target_prices
|
@ -1,17 +0,0 @@
|
||||
DROP TABLE pricing.price_queue
|
||||
|
||||
CREATE TABLE pricing.price_queue (
|
||||
id BIGINT IDENTITY(1,1) PRIMARY KEY,
|
||||
bill VARCHAR(100),
|
||||
ship VARCHAR(100),
|
||||
part VARCHAR(100),
|
||||
stlc VARCHAR(100),
|
||||
v1ds VARCHAR(100),
|
||||
vol NUMERIC(18,6),
|
||||
chan VARCHAR(50),
|
||||
cust VARCHAR(100),
|
||||
tier VARCHAR(50),
|
||||
pltq NUMERIC(18,6),
|
||||
price NUMERIC(18,6),
|
||||
expl NVARCHAR(MAX) -- if storing JSON-like data
|
||||
);
|
@ -1,19 +0,0 @@
|
||||
DROP TABLE pricequote.price_queue CASCADE;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pricequote.price_queue (
|
||||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
|
||||
,bill TEXT
|
||||
,ship TEXT
|
||||
,part TEXT
|
||||
,stlc TEXT
|
||||
,v1ds TEXT
|
||||
,vol NUMERIC
|
||||
,cust TEXT
|
||||
,chan TEXT
|
||||
,tier TEXT
|
||||
,pltq NUMERIC
|
||||
,price NUMERIC
|
||||
,expl JSONB
|
||||
);
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON pricequote.price_queue TO PUBLIC;
|
@ -1,72 +0,0 @@
|
||||
DELETE FROM pricing.price_queue;
|
||||
|
||||
INSERT INTO pricing.price_queue (bill, ship, part, stlc, v1ds, vol) SELECT 'GRIF0001','GRIF0001','XNS0T1G3G18B096','XNS0T1G3','v1:L..PLT..',9600;
|
||||
|
||||
SELECT * FROM pricing.price_queue
|
||||
|
||||
EXEC pricing.process_queue
|
||||
|
||||
|
||||
EXEC pricing.single_price_call
|
||||
@bill = 'GRIF0001',
|
||||
@ship = 'JRSG0001',
|
||||
@part = 'XNS0T1G3G18B096',
|
||||
@stlc = 'XNS0T1G3',
|
||||
@v1ds = 'v1:B..PLT..',
|
||||
@vol = 9600;
|
||||
|
||||
|
||||
SELECT
|
||||
*
|
||||
FROM pricing.single_price_call_fn(
|
||||
'GRIF0001',
|
||||
'GRIF0001',
|
||||
'XNS0T1G3G18B096',
|
||||
'XNS0T1G3',
|
||||
'v1:B..PLT..',
|
||||
9600
|
||||
) f
|
||||
|
||||
|
||||
SELECT * INTO #result FROM pricing.price_queue WHERE 0=1
|
||||
|
||||
INSERT INTO #result
|
||||
EXEC pricing.single_price_call_nowrite
|
||||
@bill = 'GRIF0001',
|
||||
@ship = 'JRSG0001',
|
||||
@part = 'XNS0T1G3G18B096',
|
||||
@stlc = 'XNS0T1G3',
|
||||
@v1ds = 'v1:T..PLT..',
|
||||
@vol = 19200;
|
||||
|
||||
SELECT * FROM #RESULT
|
||||
|
||||
|
||||
SELECT
|
||||
q.qid,
|
||||
q.qrn,
|
||||
q.qcustomer,
|
||||
q.part,
|
||||
q.v1ds,
|
||||
q.units_each,
|
||||
q.price,
|
||||
q.targetp,
|
||||
q.lastsalesprice,
|
||||
q.finalrecommendedprice,
|
||||
q.lowerpricelimit,
|
||||
q.upperpricelimit,
|
||||
q.curstdus,
|
||||
p.price guidance,
|
||||
p.expl
|
||||
FROM
|
||||
rlarp.live_quotes q
|
||||
OUTER APPLY pricing.single_price_call_fn(
|
||||
q.billto
|
||||
,q.shipto
|
||||
,q.part
|
||||
,substring(q.part,1,8)
|
||||
,q.v1ds
|
||||
,q.units_each
|
||||
) p
|
||||
WHERE
|
||||
qstat LIKE 'Submitted%'
|
@ -1,9 +0,0 @@
|
||||
SELECT * FROM
|
||||
pricequote.single_price_call(
|
||||
'GRIF0001' ,
|
||||
'GRIF0001' ,
|
||||
'XNS0T1G3G18B096' ,
|
||||
'XNS0T1G3',
|
||||
'v1:B.L.PLT..',
|
||||
9600
|
||||
)
|
@ -1,109 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.process_queue
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Insert input row into real queue table
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 2: Enrich the row with chan, tier, cust, pltq
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
q.chan =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END,
|
||||
q.tier =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE ISNULL(sc.tier, bc.tier)
|
||||
END,
|
||||
q.cust =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN q.ship
|
||||
ELSE q.ship
|
||||
END
|
||||
ELSE q.bill
|
||||
END,
|
||||
q.pltq = i.mpck
|
||||
FROM
|
||||
pricing.price_queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN CMSInterfaceIn.[CMS.CUSLG].itemm i ON i.item = q.part;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 3: Apply pricing from target_prices
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
DECLARE @updated TABLE (
|
||||
id BIGINT,
|
||||
bill VARCHAR(100),
|
||||
ship VARCHAR(100),
|
||||
part VARCHAR(100),
|
||||
stlc VARCHAR(100),
|
||||
v1ds VARCHAR(100),
|
||||
vol NUMERIC(18,6),
|
||||
chan VARCHAR(50),
|
||||
cust VARCHAR(100),
|
||||
tier VARCHAR(50),
|
||||
pltq NUMERIC(18,6),
|
||||
price NUMERIC(18,6),
|
||||
expl NVARCHAR(MAX)
|
||||
);
|
||||
|
||||
UPDATE q
|
||||
SET
|
||||
q.price = tp.price,
|
||||
q.expl = (
|
||||
SELECT
|
||||
'target price' AS [source],
|
||||
FLOOR(q.vol / NULLIF(q.pltq, 0)) AS [calculated_pallets],
|
||||
ROUND(q.vol / NULLIF(q.pltq, 0), 5) AS [exact_pallets],
|
||||
CONCAT(tp.lower_bound, '-', ISNULL(CAST(tp.upper_bound AS VARCHAR), '∞')) AS [volume range],
|
||||
q.cust AS [customer],
|
||||
q.chan AS [channel],
|
||||
q.tier AS [tier],
|
||||
JSON_QUERY(tp.math) AS [target math] -- important if math is JSON
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
)
|
||||
OUTPUT
|
||||
inserted.id,
|
||||
inserted.bill,
|
||||
inserted.ship,
|
||||
inserted.part,
|
||||
inserted.stlc,
|
||||
inserted.v1ds,
|
||||
inserted.vol,
|
||||
inserted.chan,
|
||||
inserted.cust,
|
||||
inserted.tier,
|
||||
inserted.pltq,
|
||||
inserted.price,
|
||||
inserted.expl
|
||||
INTO @updated
|
||||
FROM pricing.price_queue q
|
||||
INNER JOIN pricing.target_prices tp ON
|
||||
q.stlc = tp.stlc
|
||||
AND q.v1ds = tp.ds
|
||||
AND q.chan = tp.chan
|
||||
AND q.tier = tp.tier
|
||||
AND FLOOR(q.vol / NULLIF(q.pltq, 0)) >= tp.lower_bound
|
||||
AND (
|
||||
tp.upper_bound IS NULL OR FLOOR(q.vol / NULLIF(q.pltq, 0)) < tp.upper_bound
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 4: Return just the enriched row
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT * FROM @updated;
|
||||
END;
|
@ -1,69 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION pricequote.process_queue()
|
||||
RETURNS SETOF pricequote.price_queue
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Set channel, tier, and pallet quantity
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE pricequote.price_queue s
|
||||
SET
|
||||
chan = cr.chan,
|
||||
tier = cr.tier,
|
||||
pltq = cr.mpck
|
||||
FROM (
|
||||
SELECT
|
||||
q.bill,
|
||||
q.ship,
|
||||
q.part,
|
||||
i.mpck,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END AS chan,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE COALESCE(sc.tier, bc.tier)
|
||||
END AS tier
|
||||
FROM pricequote.price_queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN "CMS.CUSLG".itemm i ON i.item = q.part
|
||||
) cr
|
||||
WHERE
|
||||
cr.bill = s.bill AND
|
||||
COALESCE(cr.ship, '') = COALESCE(s.ship, '') AND
|
||||
cr.part = s.part;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 2: Set price and explanation from target_prices, return touched rows
|
||||
--------------------------------------------------------------------------------
|
||||
RETURN QUERY
|
||||
WITH updated AS (
|
||||
UPDATE pricequote.price_queue q
|
||||
SET
|
||||
price = tp.price,
|
||||
expl = jsonb_build_object(
|
||||
'source', 'target price',
|
||||
'calculated_pallets', FLOOR(q.vol / NULLIF(q.pltq, 0))::INT,
|
||||
'exact_pallets', ROUND(q.vol / NULLIF(q.pltq, 0), 5),
|
||||
'volume range', tp.vol
|
||||
)
|
||||
FROM pricequote.target_prices tp
|
||||
WHERE
|
||||
q.stlc = tp.stlc
|
||||
AND q.v1ds = tp.ds
|
||||
AND q.chan = tp.chan
|
||||
AND q.tier = tp.tier
|
||||
AND tp.vol @> FLOOR(q.vol / NULLIF(q.pltq, 0))::INT
|
||||
RETURNING q.*
|
||||
)
|
||||
SELECT * FROM updated;
|
||||
|
||||
END;
|
||||
$$;
|
@ -1,69 +0,0 @@
|
||||
CREATE OR REPLACE PROCEDURE pricequote.process_queue_proc()
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Set channel, tier, and pallet quantity
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE pricequote.price_queue s
|
||||
SET
|
||||
chan = cr.chan,
|
||||
tier = cr.tier,
|
||||
pltq = cr.mpck,
|
||||
cust = cr.cust
|
||||
FROM (
|
||||
SELECT
|
||||
q.bill,
|
||||
q.ship,
|
||||
q.part,
|
||||
i.mpck,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END AS chan,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE COALESCE(sc.tier, bc.tier)
|
||||
END AS tier,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.dba
|
||||
ELSE COALESCE(sc.dba, bc.dba)
|
||||
END AS cust
|
||||
FROM pricequote.price_queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN "CMS.CUSLG".itemm i ON i.item = q.part
|
||||
) cr
|
||||
WHERE
|
||||
cr.bill = s.bill AND
|
||||
COALESCE(cr.ship, '') = COALESCE(s.ship, '') AND
|
||||
cr.part = s.part;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 2: Set price and explanation from target_prices
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE pricequote.price_queue q
|
||||
SET
|
||||
price = tp.price,
|
||||
expl = jsonb_build_object(
|
||||
'source', 'target price',
|
||||
'calculated_pallets', FLOOR(q.vol / NULLIF(q.pltq, 0))::INT,
|
||||
'exact_pallets', ROUND(q.vol / NULLIF(q.pltq, 0), 5),
|
||||
'volume range', tp.vol
|
||||
)
|
||||
FROM pricequote.target_prices tp
|
||||
WHERE
|
||||
q.stlc = tp.stlc
|
||||
AND q.v1ds = tp.ds
|
||||
AND q.chan = tp.chan
|
||||
AND q.tier = tp.tier
|
||||
AND tp.vol @> FLOOR(q.vol / NULLIF(q.pltq, 0))::INT;
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
@ -1,164 +0,0 @@
|
||||
DROP FUNCTION pricequote.build_pricing_path;
|
||||
|
||||
CREATE OR REPLACE FUNCTION pricequote.build_pricing_path(
|
||||
_json JSONB
|
||||
)
|
||||
RETURNS TABLE (
|
||||
stlc TEXT
|
||||
,seq BIGINT
|
||||
,srtcode TEXT
|
||||
,ds TEXT
|
||||
,chan TEXT
|
||||
,tier TEXT
|
||||
,vol INT4RANGE
|
||||
,func TEXT
|
||||
,val NUMERIC
|
||||
,price NUMERIC
|
||||
,math TEXT[]
|
||||
,lastflag BOOLEAN
|
||||
)
|
||||
LANGUAGE plpgsql AS
|
||||
$$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
|
||||
WITH RECURSIVE
|
||||
-- 1️⃣ Parse JSONB into rows of (entity, attr, val)
|
||||
parsed AS (
|
||||
SELECT
|
||||
e.entity,
|
||||
COALESCE(e.attr, '') AS attr,
|
||||
e.val,
|
||||
e.func
|
||||
FROM jsonb_to_recordset(_json)
|
||||
AS e(entity TEXT, attr TEXT, val NUMERIC, func TEXT)
|
||||
),
|
||||
-- 2️⃣ Attach sequence & func from master option_sequence table
|
||||
sequenced AS (
|
||||
SELECT
|
||||
p.entity,
|
||||
p.attr,
|
||||
p.val,
|
||||
p.func,
|
||||
s.DOMAIN,
|
||||
DENSE_RANK() OVER (ORDER BY s.seq) AS seq,
|
||||
ROW_NUMBER() OVER (PARTITION BY p.entity ORDER BY COALESCE(p.val,0) ASC) srt
|
||||
FROM parsed p
|
||||
JOIN pricequote.option_sequence s
|
||||
ON p.entity = s.entity
|
||||
)
|
||||
--select * from sequenced ORDER BY seq, srt
|
||||
-- 3️⃣ Recursively accumulate pricing path
|
||||
,combos AS (
|
||||
-- 🚀 Base case: first in sequence
|
||||
SELECT
|
||||
s.entity,
|
||||
s.attr,
|
||||
s.seq,
|
||||
to_char(s.srt,'FM000') srtcode,
|
||||
'' ds,
|
||||
'' chan,
|
||||
'' tier,
|
||||
null::TEXT vol,
|
||||
s.func,
|
||||
s.val,
|
||||
s.val agg,
|
||||
-- jsonb_build_array(jsonb_build_object('entity',s.entity,'attr',s.attr,'function',s.func, 'val',s.val,'seq',s.seq)) math
|
||||
ARRAY[
|
||||
CASE
|
||||
WHEN s.func = 'Price' THEN
|
||||
RPAD(s.entity || ':' || s.attr, 17, ' ') || ' + ' || LPAD(to_char(s.val, 'FM9999999990.00000'), 10, ' ')
|
||||
WHEN s.func = 'Factor' THEN
|
||||
RPAD(s.entity || ':' || s.attr, 17, ' ') || ' x ' || LPAD(to_char(s.val, 'FM9999999990.00000'), 10, ' ')
|
||||
ELSE
|
||||
RPAD(s.entity || ':' || s.attr, 17, ' ') || ' ' || LPAD(to_char(s.val, 'FM9999999990.00000'), 10, ' ')
|
||||
END
|
||||
] math
|
||||
FROM
|
||||
sequenced s
|
||||
WHERE
|
||||
s.seq = (SELECT MIN(x.seq) FROM sequenced x)
|
||||
UNION ALL
|
||||
-- 🔁 Recursive step: process next in sequence
|
||||
SELECT
|
||||
c.entity,
|
||||
c.attr,
|
||||
o.seq,
|
||||
c.srtcode || '.' || to_char(o.srt,'FM000'),
|
||||
c.ds || CASE WHEN o.DOMAIN = 'Product' THEN '.' || o.attr ELSE '' END ds,
|
||||
CASE WHEN o.DOMAIN = 'Channel' THEN o.attr ELSE c.chan END chan,
|
||||
CASE WHEN o.DOMAIN = 'Tier' THEN o.attr ELSE c.tier END tier,
|
||||
CASE WHEN o.DOMAIN = 'Volume' THEN o.attr ELSE c.vol END vol,
|
||||
o.func,
|
||||
o.val,
|
||||
CASE o.func WHEN 'Price' THEN c.agg + o.val WHEN 'Factor' THEN c.agg * o.val END agg,
|
||||
-- c.math || jsonb_build_array(jsonb_build_object('entity',o.entity,'attr',o.attr,'function',o.func, 'val',o.val,'seq',o.seq)) math,
|
||||
CASE WHEN (o.func = 'Price' AND o.val <> 0) OR (o.func = 'Factor' AND o.val <> 1) THEN
|
||||
c.math ||
|
||||
ARRAY[
|
||||
CASE
|
||||
WHEN o.func = 'Price' THEN
|
||||
RPAD(o.entity || ':' || o.attr, 17, ' ') || ' + ' || LPAD(to_char(o.val, 'FM9999999990.00000'), 10, ' ')
|
||||
WHEN o.func = 'Factor' THEN
|
||||
RPAD(o.entity || ':' || o.attr, 17, ' ') || ' x ' || LPAD(to_char(o.val, 'FM9999999990.00000'), 10, ' ')
|
||||
ELSE
|
||||
RPAD(o.entity || ':' || o.attr, 17, ' ') || ' ' || LPAD(to_char(o.val, 'FM9999999990.00000'), 10, ' ')
|
||||
END
|
||||
]
|
||||
ELSE
|
||||
c.math
|
||||
END math
|
||||
FROM
|
||||
combos c
|
||||
JOIN sequenced o ON
|
||||
o.seq = c.seq + 1
|
||||
)
|
||||
SELECT
|
||||
-- c.entity
|
||||
c.attr
|
||||
,c.seq
|
||||
,c.srtcode
|
||||
,'v1:'||SUBSTRING(c.ds,2,100) ds
|
||||
,c.chan
|
||||
,c.tier
|
||||
-- ,c.vol
|
||||
,CASE
|
||||
WHEN c.vol ~ '^[0-9]+-[0-9]+$' THEN
|
||||
int4range(
|
||||
split_part(c.vol, '-', 1)::int,
|
||||
split_part(c.vol, '-', 2)::int,
|
||||
'[)'
|
||||
)
|
||||
WHEN c.vol ~ '^[0-9]+$' THEN
|
||||
int4range(
|
||||
c.vol::int,
|
||||
NULL,
|
||||
'[)'
|
||||
)
|
||||
ELSE NULL
|
||||
END AS vol
|
||||
,c.func
|
||||
,c.val
|
||||
,c.agg
|
||||
,c.math
|
||||
,c.seq = (SELECT max(x.seq) FROM sequenced x) lastflag
|
||||
FROM
|
||||
combos c /*WHERE seq = (SELECT max(seq) FROM sequenced)*/
|
||||
ORDER BY
|
||||
c.srtcode ASC;
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
||||
/*
|
||||
Anchor:EU170S50 + 0.08
|
||||
Color Tier:P x 1.30
|
||||
Branding: + 0.00
|
||||
Packaging:SLV + 0.00
|
||||
Suffix:PCR x 1.00
|
||||
Accessories: + 0.00
|
||||
Channel:WHS + 0.00
|
||||
Volume:8 x 1.00
|
||||
-----------------------
|
||||
0.104
|
||||
*/
|
@ -1,104 +0,0 @@
|
||||
DROP FUNCTION IF EXISTS rlarp.get_option_costs_priceg;
|
||||
CREATE FUNCTION rlarp.get_option_costs_priceg(_priceg text, _majg text)
|
||||
RETURNS TABLE (
|
||||
stlc text
|
||||
,coltier text
|
||||
,branding text
|
||||
,accs_ps text
|
||||
,acc_list text
|
||||
,suffix text
|
||||
,uomp text
|
||||
,avgsc numeric
|
||||
,avgfc numeric
|
||||
,weight numeric
|
||||
,target numeric
|
||||
,futmargin numeric
|
||||
)
|
||||
LANGUAGE plpgsql AS
|
||||
$function$
|
||||
|
||||
BEGIN
|
||||
|
||||
RETURN QUERY
|
||||
WITH
|
||||
sel AS (
|
||||
SELECT
|
||||
i.stlc
|
||||
,i.coltier
|
||||
,i.branding
|
||||
--,accs
|
||||
,i.accs_ps
|
||||
,i.acc_list
|
||||
,i.suffix
|
||||
--,COALESCE(accs_ps,accs) accs_c
|
||||
--,jsonb_agg(DISTINCT r.aomult) cavitation
|
||||
--,jsonb_agg(DISTINCT r.aoctme) cyclet
|
||||
--,jsonb_arr_aggcd(mino) min_ord
|
||||
,i.uomp
|
||||
--,jsonb_agg(DISTINCT aplnt) aplnt
|
||||
--,jsonb_agg(DISTINCT colc) colc
|
||||
--,jsonb_agg(DISTINCT substring(item,12,case when branding = '' THEN 7 ELSE 4 end)) items
|
||||
--,jsonb_agg(DISTINCT majg) majgs
|
||||
--,jsonb_agg(DISTINCT assc) accs
|
||||
,round(avg(curstdus),5) avgsc
|
||||
,round(avg(futstdus),5) avgfc
|
||||
,round(avg(nwht),5) avgwt
|
||||
,i.v1ds
|
||||
FROM
|
||||
"CMS.CUSLG".itemm i
|
||||
WHERE
|
||||
true
|
||||
--stlc ~ 'TWA10200'
|
||||
--AND branding = ''
|
||||
AND aplnt <> 'I'
|
||||
AND COALESCE(i.uomp,'') <> ''
|
||||
--AND branding = ''
|
||||
GROUP BY
|
||||
i.stlc
|
||||
,i.coltier
|
||||
,i.uomp
|
||||
,i.branding
|
||||
,i.acc_list
|
||||
,i.accs_ps
|
||||
,i.suffix
|
||||
,i.v1ds
|
||||
ORDER BY
|
||||
i.stlc ASC
|
||||
)
|
||||
SELECT
|
||||
sel.stlc
|
||||
,sel.coltier
|
||||
,sel.branding
|
||||
,sel.accs_ps
|
||||
,sel.acc_list
|
||||
,sel.suffix
|
||||
,sel.uomp
|
||||
,sel.avgsc
|
||||
,sel.avgfc
|
||||
,sel.avgwt
|
||||
,t.price
|
||||
,round(CASE WHEN coalesce(t.price,0) <> 0 THEN (t.price-COALESCE(sel.avgfc,0))/t.price ELSE 0 END,3) futmarg
|
||||
FROM
|
||||
sel
|
||||
LEFT OUTER JOIN pricequote.target_prices t ON
|
||||
sel.stlc = t.stlc
|
||||
AND sel.v1ds = t.ds
|
||||
AND t.chan = 'DIR'
|
||||
AND COALESCE(t.tier,'') IN ('1')
|
||||
AND 24 <@ t.vol
|
||||
-- LEFT OUTER JOIN pricequote.market_setavgprice t ON
|
||||
-- t.mold = sel.stlc
|
||||
-- AND t.data_segment = sel.v1ds
|
||||
-- AND t.season = 2025
|
||||
-- AND t.chan = 'DIRECT'
|
||||
-- AND t.country = 'ALL'
|
||||
-- AND t.geo = 'ALL'
|
||||
-- AND t.region = 'ALL'
|
||||
WHERE
|
||||
sel.stlc IN (SELECT DISTINCT m.stlc FROM rlarp.molds m WHERE m.priceg ~ _priceg AND m.majg ~ _majg);
|
||||
|
||||
END
|
||||
|
||||
$function$
|
||||
|
||||
|
@ -1,194 +0,0 @@
|
||||
DROP FUNCTION rlarp.get_options_merged;
|
||||
|
||||
CREATE OR REPLACE FUNCTION rlarp.get_options_merged(
|
||||
_priceg TEXT,
|
||||
_majg TEXT,
|
||||
existing_json JSONB
|
||||
)
|
||||
RETURNS TABLE (
|
||||
entity TEXT,
|
||||
attr TEXT,
|
||||
val NUMERIC,
|
||||
func TEXT
|
||||
)
|
||||
LANGUAGE plpgsql AS
|
||||
$$
|
||||
BEGIN
|
||||
|
||||
RETURN QUERY
|
||||
WITH
|
||||
|
||||
-- 1️⃣ Parse existing pricing from JSONB
|
||||
existing AS (
|
||||
SELECT
|
||||
e.entity,
|
||||
COALESCE(e.attr, '') AS attr,
|
||||
e.val,
|
||||
e.func
|
||||
FROM jsonb_to_recordset(existing_json)
|
||||
AS e(entity TEXT, attr TEXT, val NUMERIC, func TEXT)
|
||||
)
|
||||
,items AS (
|
||||
SELECT
|
||||
item
|
||||
FROM
|
||||
"CMS.CUSLG".itemm
|
||||
WHERE
|
||||
stlc IN (SELECT DISTINCT stlc FROM "CMS.CUSLG".itemm WHERE pricegroup ~ _priceg AND majg ~ _majg)
|
||||
AND aplnt <> 'I'
|
||||
)
|
||||
-- 2️⃣ Build raw stack without hard-coded func
|
||||
,stack AS (
|
||||
-- Anchor
|
||||
SELECT 'Anchor' AS entity, stlc AS attr, 0::numeric AS val
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (
|
||||
SELECT item
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (SELECT item FROM items)
|
||||
)
|
||||
GROUP BY stlc
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Color Tier
|
||||
SELECT 'Color Tier' AS entity, coltier AS attr, 1 AS val
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (
|
||||
SELECT item
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (SELECT item FROM items)
|
||||
)
|
||||
GROUP BY coltier
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Branding
|
||||
SELECT 'Branding' AS entity, COALESCE(substring(branding,1,1), '') AS attr, 0 AS val
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (
|
||||
SELECT item
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (SELECT item FROM items)
|
||||
)
|
||||
GROUP BY COALESCE(substring(branding,1,1), '')
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Packaging
|
||||
SELECT 'Packaging' AS entity, COALESCE(uomp, '') AS attr, 0 AS val
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (
|
||||
SELECT item
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (SELECT item FROM items)
|
||||
)
|
||||
GROUP BY COALESCE(uomp, '')
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Accessories
|
||||
SELECT 'Accessories' AS entity, COALESCE(accs_ps, '') AS attr, 0 AS val
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (
|
||||
SELECT item
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (SELECT item FROM items)
|
||||
)
|
||||
GROUP BY COALESCE(accs_ps, '')
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Suffix
|
||||
SELECT 'Suffix' AS entity, COALESCE(suffix, '') AS attr, 1 AS val
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (
|
||||
SELECT item
|
||||
FROM "CMS.CUSLG".itemm
|
||||
WHERE item IN (SELECT item FROM items)
|
||||
)
|
||||
GROUP BY COALESCE(suffix, '')
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Channel
|
||||
SELECT 'Channel' AS entity, x.chan AS attr, 0 AS val
|
||||
FROM (VALUES ('DIR'), ('DRP'), ('WHS')) AS x(chan)
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Customer Tier
|
||||
SELECT 'Tier' AS entity, x.tier AS attr, 0 AS val
|
||||
FROM (VALUES ('1'), ('2'), ('3')) AS x(tier)
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Volume
|
||||
SELECT 'Volume' AS entity, x.chan AS attr, 0 AS val
|
||||
FROM (VALUES ('0-1'),('1-8'),('8-24'),('24')) AS x(chan)
|
||||
),
|
||||
|
||||
-- 3️⃣ Attach pricing func and sequence from option_sequence
|
||||
stack_with_meta AS (
|
||||
SELECT
|
||||
s.entity,
|
||||
COALESCE(s.attr, '') AS attr,
|
||||
s.val,
|
||||
os.func,
|
||||
os.seq
|
||||
FROM stack s
|
||||
LEFT JOIN pricequote.option_sequence os
|
||||
ON s.entity = os.entity
|
||||
),
|
||||
|
||||
-- 4️⃣ Merge: master rows with overrides
|
||||
overridden AS (
|
||||
SELECT
|
||||
s.entity,
|
||||
s.attr,
|
||||
COALESCE(e.val, s.val) AS val,
|
||||
s.func,
|
||||
s.seq
|
||||
FROM stack_with_meta s
|
||||
LEFT JOIN existing e
|
||||
ON s.entity = e.entity
|
||||
AND COALESCE(s.attr, '') = COALESCE(e.attr, '')
|
||||
AND s.func = e.func
|
||||
),
|
||||
|
||||
-- 5️⃣ Extras in saved JSON but not in master
|
||||
extras AS (
|
||||
SELECT
|
||||
e.entity,
|
||||
COALESCE(e.attr, '') AS attr,
|
||||
e.val,
|
||||
e.func,
|
||||
os.seq
|
||||
FROM existing e
|
||||
LEFT JOIN stack_with_meta s
|
||||
ON e.entity = s.entity
|
||||
AND COALESCE(e.attr, '') = COALESCE(s.attr, '')
|
||||
AND e.func = s.func
|
||||
LEFT JOIN pricequote.option_sequence os
|
||||
ON e.entity = os.entity
|
||||
WHERE s.entity IS NULL
|
||||
),
|
||||
|
||||
-- 6️⃣ Combine both sources
|
||||
combined AS (
|
||||
SELECT o.entity, o.attr, o.val, o.func, o.seq FROM overridden o
|
||||
UNION ALL
|
||||
SELECT e.entity, e.attr, e.val, e.func, e.seq FROM extras e
|
||||
)
|
||||
|
||||
-- 7️⃣ Return ordered by sequence
|
||||
SELECT
|
||||
combined.entity,
|
||||
combined.attr,
|
||||
combined.val,
|
||||
combined.func
|
||||
FROM combined
|
||||
ORDER BY combined.seq NULLS LAST, combined.entity, combined.attr;
|
||||
|
||||
END;
|
||||
$$;
|
@ -1,27 +0,0 @@
|
||||
CREATE OR ALTER FUNCTION dbo.LEAST_NUMERIC205(
|
||||
@a NUMERIC(20,5),
|
||||
@b NUMERIC(20,5)
|
||||
)
|
||||
RETURNS NUMERIC(20,5)
|
||||
AS
|
||||
BEGIN
|
||||
RETURN CASE
|
||||
WHEN @a IS NULL THEN @b
|
||||
WHEN @b IS NULL THEN @a
|
||||
WHEN @a < @b THEN @a ELSE @b
|
||||
END
|
||||
END
|
||||
|
||||
CREATE OR ALTER FUNCTION dbo.GREATEST_NUMERIC205(
|
||||
@a NUMERIC(20,5),
|
||||
@b NUMERIC(20,5)
|
||||
)
|
||||
RETURNS NUMERIC(20,5)
|
||||
AS
|
||||
BEGIN
|
||||
RETURN CASE
|
||||
WHEN @a IS NULL THEN @b
|
||||
WHEN @b IS NULL THEN @a
|
||||
WHEN @a > @b THEN @a ELSE @b
|
||||
END
|
||||
END
|
@ -1,84 +0,0 @@
|
||||
CREATE OR ALTER FUNCTION pricing.guidance_logic (
|
||||
@target_price NUMERIC(20,5),
|
||||
@last_price NUMERIC(20,5),
|
||||
@list_price NUMERIC(20,5),
|
||||
@last_date DATE
|
||||
)
|
||||
RETURNS @result TABLE (
|
||||
guidance_price NUMERIC(20,5),
|
||||
guidance_reason NVARCHAR(MAX)
|
||||
)
|
||||
AS
|
||||
BEGIN
|
||||
DECLARE @price NUMERIC(20,5);
|
||||
DECLARE @reason NVARCHAR(MAX) = '';
|
||||
DECLARE @floored NUMERIC(20,5);
|
||||
DECLARE @capped NUMERIC(20,5);
|
||||
DECLARE @use_last_price BIT = 0;
|
||||
|
||||
-- Determine if last price is recent (within last 2 years)
|
||||
IF @last_price IS NOT NULL AND @last_date IS NOT NULL AND @last_date > DATEADD(YEAR, -2, CAST(GETDATE() AS DATE))
|
||||
SET @use_last_price = 1;
|
||||
|
||||
IF @target_price IS NOT NULL AND @use_last_price = 1
|
||||
BEGIN
|
||||
SET @floored = dbo.GREATEST_NUMERIC205(@target_price, @last_price * 0.95);
|
||||
SET @capped = dbo.LEAST_NUMERIC205(@floored, @last_price);
|
||||
SET @price = dbo.LEAST_NUMERIC205(ISNULL(@list_price, 1e9), @capped);
|
||||
|
||||
IF @price = @last_price
|
||||
BEGIN
|
||||
SET @reason = 'Cap at last price';
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
SET @reason = 'Using target price';
|
||||
IF @target_price < @last_price * 0.95
|
||||
SET @reason += ', floored to 5% below last price';
|
||||
IF @target_price > @last_price
|
||||
SET @reason += ', capped to not exceed last price';
|
||||
IF @list_price IS NOT NULL AND @price = @list_price AND @target_price > @list_price
|
||||
SET @reason += ', capped to not exceed list price';
|
||||
END
|
||||
END
|
||||
ELSE IF @use_last_price = 1
|
||||
BEGIN
|
||||
SET @price = @last_price;
|
||||
SET @reason = 'Last price - no target';
|
||||
END
|
||||
ELSE IF @target_price IS NOT NULL
|
||||
BEGIN
|
||||
SET @price = @target_price;
|
||||
IF @last_price IS NOT NULL AND @last_date IS NOT NULL
|
||||
BEGIN
|
||||
SET @reason = CONCAT(
|
||||
'Last price ignored (too old: ',
|
||||
CONVERT(NVARCHAR(10), @last_date, 120),
|
||||
'), using target price'
|
||||
);
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
SET @reason = 'Target price - no prior sale';
|
||||
END
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
SET @price = NULL;
|
||||
IF @last_price IS NOT NULL AND @last_date IS NOT NULL
|
||||
BEGIN
|
||||
SET @reason = CONCAT(
|
||||
'Last price ignored (too old: ',
|
||||
CONVERT(NVARCHAR(10), @last_date, 120),
|
||||
'), no pricing available'
|
||||
);
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
SET @reason = 'No pricing available';
|
||||
END
|
||||
END
|
||||
|
||||
INSERT INTO @result VALUES (@price, @reason);
|
||||
RETURN;
|
||||
END
|
@ -1,74 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION pricequote.guidance_logic(
|
||||
_target_price NUMERIC(20,5),
|
||||
_last_price NUMERIC(20,5),
|
||||
_list_price NUMERIC(20,5),
|
||||
_last_date DATE
|
||||
)
|
||||
RETURNS TABLE (
|
||||
guidance_price NUMERIC(20,5),
|
||||
guidance_reason TEXT
|
||||
) AS $$
|
||||
DECLARE
|
||||
_price NUMERIC(20,5);
|
||||
_reason TEXT := '';
|
||||
_floored NUMERIC(20,5);
|
||||
_capped NUMERIC(20,5);
|
||||
_use_last_price BOOLEAN := FALSE;
|
||||
BEGIN
|
||||
-- Evaluate whether last price is recent enough
|
||||
IF _last_price IS NOT NULL AND _last_date IS NOT NULL AND _last_date > CURRENT_DATE - INTERVAL '2 years' THEN
|
||||
_use_last_price := TRUE;
|
||||
END IF;
|
||||
|
||||
IF _target_price IS NOT NULL AND _use_last_price THEN
|
||||
_floored := GREATEST(_target_price, _last_price * 0.95);
|
||||
_capped := LEAST(_floored, _last_price);
|
||||
_price := LEAST(COALESCE(_list_price, 1e9), _capped);
|
||||
|
||||
IF _price = _last_price THEN
|
||||
_reason := 'Cap at last price';
|
||||
ELSE
|
||||
_reason := 'Using target price';
|
||||
IF _target_price < _last_price * 0.95 THEN
|
||||
_reason := _reason || ', floored to 5% below last price';
|
||||
END IF;
|
||||
IF _target_price > _last_price THEN
|
||||
_reason := _reason || ', capped to not exceed last price';
|
||||
END IF;
|
||||
IF _list_price IS NOT NULL AND _price = _list_price AND _target_price > _list_price THEN
|
||||
_reason := _reason || ', capped to not exceed list price';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
ELSIF _use_last_price THEN
|
||||
_price := _last_price;
|
||||
_reason := 'Last price - no target';
|
||||
|
||||
ELSIF _target_price IS NOT NULL THEN
|
||||
_price := _target_price;
|
||||
|
||||
IF _last_price IS NOT NULL AND _last_date IS NOT NULL THEN
|
||||
_reason := format(
|
||||
'Last price ignored (too old: %s), using target price',
|
||||
to_char(_last_date, 'YYYY-MM-DD')
|
||||
);
|
||||
ELSE
|
||||
_reason := 'Target price - no prior sale';
|
||||
END IF;
|
||||
|
||||
ELSE
|
||||
_price := NULL;
|
||||
|
||||
IF _last_price IS NOT NULL AND _last_date IS NOT NULL THEN
|
||||
_reason := format(
|
||||
'Last price ignored (too old: %s), no pricing available',
|
||||
to_char(_last_date, 'YYYY-MM-DD')
|
||||
);
|
||||
ELSE
|
||||
_reason := 'No pricing available';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
RETURN QUERY SELECT _price, _reason;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
@ -1,42 +0,0 @@
|
||||
CREATE OR REPLACE PROCEDURE pricequote.load_target_prices(input_json JSONB)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
-- 1️⃣ Materialize the function output once
|
||||
CREATE TEMP TABLE temp_new_data ON COMMIT DROP AS
|
||||
SELECT
|
||||
stlc, ds, chan, tier, vol, price, math
|
||||
FROM
|
||||
pricequote.build_pricing_path(input_json)
|
||||
WHERE
|
||||
lastflag;
|
||||
|
||||
-- 2️⃣ Delete matching old rows
|
||||
DELETE FROM pricequote.target_prices t
|
||||
USING (
|
||||
SELECT DISTINCT stlc FROM temp_new_data
|
||||
) to_delete
|
||||
WHERE t.stlc = to_delete.stlc;
|
||||
|
||||
-- 3️⃣ Insert new rows
|
||||
INSERT INTO pricequote.target_prices (stlc, ds, chan, tier, vol, price, math)
|
||||
SELECT stlc, ds, chan, tier, vol, price, math FROM temp_new_data;
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
||||
/*
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
price,
|
||||
-- array_to_string(math, E'\n') AS math_text
|
||||
jsonb_build_object('target math',to_jsonb(math)) AS math_text
|
||||
FROM
|
||||
pricequote.build_pricing_path('[{"entity":"Anchor","attr":"JNS0T1G3","val":"0.08","func":"Price"},{"entity":"Anchor","attr":"XNS0T1G3","val":"0.08","func":"Price"},{"entity":"Anchor","attr":"XRD16002","val":"0.085","func":"Price"},{"entity":"Anchor","attr":"EU170S50","val":"0.085","func":"Price"},{"entity":"Anchor","attr":"EU170T50","val":"0.095","func":"Price"},{"entity":"Anchor","attr":"AZN06501","val":"0.12","func":"Price"},{"entity":"Anchor","attr":"1CP07010","val":"0.125","func":"Price"},{"entity":"Anchor","attr":"1CP06060","val":"0.13","func":"Price"},{"entity":"Anchor","attr":"AZA06500","val":"0.15","func":"Price"},{"entity":"Color Tier","attr":"B","val":1,"func":"Factor"},{"entity":"Color Tier","attr":"T","val":1.1,"func":"Factor"},{"entity":"Color Tier","attr":"L","val":1.1,"func":"Factor"},{"entity":"Color Tier","attr":"M","val":1.2,"func":"Factor"},{"entity":"Color Tier","attr":"P","val":1.3,"func":"Factor"},{"entity":"Color Tier","attr":"C","val":1.35,"func":"Factor"},{"entity":"Branding","val":"0","func":"Price"},{"entity":"Branding","attr":"L","val":"0.03","func":"Price"},{"entity":"Branding","attr":"P","val":"0.08","func":"Price"},{"entity":"Packaging","attr":"BDL","val":"0.002","func":"Price"},{"entity":"Packaging","attr":"CSE","val":"0.005","func":"Price"},{"entity":"Packaging","attr":"PC","val":"0.005","func":"Price"},{"entity":"Packaging","attr":"PLT","val":"0","func":"Price"},{"entity":"Packaging","attr":"SLV","val":"0.002","func":"Price"},{"entity":"Suffix","val":1,"func":"Factor"},{"entity":"Accessories","val":"0","func":"Price"},{"entity":"Channel","attr":"DIR","val":1,"func":"Factor"},{"entity":"Channel","attr":"DRP","val":1,"func":"Factor"},{"entity":"Channel","attr":"WHS","val":1.2,"func":"Factor"},{"entity":"Volume","attr":24,"val":1,"func":"Factor"},{"entity":"Volume","attr":"8-24","val":1.05,"func":"Factor"},{"entity":"Volume","attr":"1-8","val":1.1,"func":"Factor"},{"entity":"Volume","attr":"0-1","val":1.2,"func":"Factor"},{"entity":"Tier","attr":1,"val":1,"func":"Factor"},{"entity":"Tier","attr":2,"val":1.05,"func":"Factor"},{"entity":"Tier","attr":3,"val":1.07,"func":"Factor"}]'::jsonb)
|
||||
WHERE
|
||||
lastflag
|
||||
*/
|
@ -1,270 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.single_price_call
|
||||
@bill VARCHAR(100),
|
||||
@ship VARCHAR(100),
|
||||
@part VARCHAR(100),
|
||||
@v1ds VARCHAR(100),
|
||||
@vol NUMERIC(18,6)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- Working table for enriched pricing request
|
||||
DECLARE @queue TABLE (
|
||||
bill VARCHAR(100),
|
||||
ship VARCHAR(100),
|
||||
part VARCHAR(100),
|
||||
stlc VARCHAR(100),
|
||||
v1ds VARCHAR(100),
|
||||
vol NUMERIC(18,6),
|
||||
chan VARCHAR(50),
|
||||
cust VARCHAR(100),
|
||||
tier VARCHAR(50),
|
||||
pltq NUMERIC(18,6),
|
||||
volume_range TEXT,
|
||||
plevel NVARCHAR(20),
|
||||
listprice NUMERIC(20,5),
|
||||
listcode VARCHAR(10),
|
||||
hist NVARCHAR(MAX),
|
||||
last_price NUMERIC(20,5),
|
||||
last_date DATE,
|
||||
last_order NVARCHAR(10),
|
||||
last_quote NVARCHAR(10),
|
||||
tprice NUMERIC(20,5),
|
||||
guidance_price NUMERIC(20,5),
|
||||
guidance_reason NVARCHAR(MAX),
|
||||
expl NVARCHAR(MAX),
|
||||
expl_pretty NVARCHAR(MAX)
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Seed the queue with input row
|
||||
--------------------------------------------------------------------------------
|
||||
INSERT INTO @queue (bill, ship, part, v1ds, vol, expl)
|
||||
VALUES (@bill, @ship, @part, @v1ds, @vol, '{}');
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 2: Enrich with channel, tier, customer, pack quantity, and price level
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
chan =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END,
|
||||
tier =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE ISNULL(sc.tier, bc.tier)
|
||||
END,
|
||||
cust =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN bc.dba
|
||||
ELSE sc.dba
|
||||
END
|
||||
ELSE q.bill
|
||||
END,
|
||||
pltq = i.mpck,
|
||||
plevel =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN sc.plevel
|
||||
ELSE bc.plevel
|
||||
END
|
||||
ELSE bc.plevel
|
||||
END,
|
||||
stlc = substring(q.part,1,8)
|
||||
FROM @queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN CMSInterfaceIn.[CMS.CUSLG].itemm i ON i.item = q.part;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 3: Apply target price and embed metadata as JSON
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
tprice = tp.price,
|
||||
expl = (
|
||||
SELECT
|
||||
'target price' AS [source],
|
||||
tp.price AS [target_price],
|
||||
FLOOR(q.vol / NULLIF(q.pltq, 0)) AS [calculated_pallets],
|
||||
CAST(ROUND(q.vol / NULLIF(q.pltq, 0), 5) AS NUMERIC(20,5)) AS [exact_pallets],
|
||||
CONCAT(tp.lower_bound, '-', ISNULL(CAST(tp.upper_bound AS VARCHAR), '∞')) AS [volume_range],
|
||||
q.cust AS [customer],
|
||||
q.chan AS [channel],
|
||||
TRIM(q.tier) AS [tier],
|
||||
JSON_QUERY(tp.math) AS [target_math]
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
),
|
||||
volume_range = CONCAT(tp.lower_bound, '-', ISNULL(CAST(tp.upper_bound AS VARCHAR), '∞'))
|
||||
FROM @queue q
|
||||
INNER JOIN pricing.target_prices tp ON
|
||||
q.stlc = tp.stlc
|
||||
AND q.v1ds = tp.ds
|
||||
AND q.chan = tp.chan
|
||||
AND q.tier = tp.tier
|
||||
AND FLOOR(q.vol / NULLIF(q.pltq, 0)) >= tp.lower_bound
|
||||
AND (
|
||||
tp.upper_bound IS NULL OR FLOOR(q.vol / NULLIF(q.pltq, 0)) < tp.upper_bound
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 4: Pull last sale data and embed in columns and JSON
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
hist = JSON_MODIFY('{}', '$.full_history', JSON_QUERY(lp.part_stats)),
|
||||
last_price = j.price,
|
||||
last_date = j.odate,
|
||||
last_order = j.ordnum,
|
||||
last_quote = j.quoten,
|
||||
expl = JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
ISNULL(q.expl, '{}'),
|
||||
'$.last_price', j.price
|
||||
),
|
||||
'$.last_date', CONVERT(NVARCHAR(10), j.odate, 23)
|
||||
),
|
||||
'$.last_order', j.ordnum
|
||||
),
|
||||
'$.last_quote', j.quoten
|
||||
)
|
||||
FROM @queue q
|
||||
JOIN pricing.lastprice lp
|
||||
ON lp.customer = q.cust
|
||||
AND lp.mold = SUBSTRING(q.part, 1, 8)
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 *
|
||||
FROM OPENJSON(lp.part_stats) AS p
|
||||
OUTER APPLY OPENJSON(p.value)
|
||||
WITH (
|
||||
qty NUMERIC(20,5),
|
||||
price NUMERIC(20,5),
|
||||
odate DATE,
|
||||
ordnum INT,
|
||||
quoten INT
|
||||
) AS j
|
||||
WHERE p.[key] COLLATE SQL_Latin1_General_CP1_CI_AS = q.part
|
||||
ORDER BY j.odate DESC
|
||||
) AS j;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 5: Add list price info from external pricelist
|
||||
--------------------------------------------------------------------------------
|
||||
WITH ranked_prices AS (
|
||||
SELECT
|
||||
q.bill, q.ship, q.part, q.stlc, q.v1ds, q.vol,
|
||||
CAST(p.price AS NUMERIC(20,5)) AS price,
|
||||
p.jcplcd,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY q.bill, q.ship, q.part, q.stlc, q.v1ds, q.vol
|
||||
ORDER BY p.price ASC
|
||||
) AS rn
|
||||
FROM @queue q
|
||||
INNER JOIN CMSInterfaceIn."CMS.CUSLG".IPRCBHC i
|
||||
ON TRIM(i.jbplvl) = TRIM(q.plevel)
|
||||
AND CAST(GETDATE() AS DATE) BETWEEN i.jbfdat AND i.jbtdat
|
||||
INNER JOIN pricing.pricelist_ranged p
|
||||
ON p.jcplcd = TRIM(i.jbplcd)
|
||||
AND p.jcpart = q.part
|
||||
AND q.vol >= p.vb_from
|
||||
AND (p.vb_to IS NULL OR q.vol < p.vb_to)
|
||||
)
|
||||
UPDATE q
|
||||
SET expl = JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
ISNULL(q.expl, '{}'),
|
||||
'$.list_price', rp.price
|
||||
),
|
||||
'$.list_code', rp.jcplcd
|
||||
)
|
||||
,listcode = rp.jcplcd
|
||||
,listprice = rp.price
|
||||
FROM @queue q
|
||||
JOIN ranked_prices rp
|
||||
ON q.bill = rp.bill
|
||||
AND q.ship = rp.ship
|
||||
AND q.part = rp.part
|
||||
AND q.stlc = rp.stlc
|
||||
AND q.v1ds = rp.v1ds
|
||||
AND q.vol = rp.vol
|
||||
AND rp.rn = 1;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 6: Compute guidance price and logic, and embed in JSON
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
guidance_price = g.guidance_price,
|
||||
guidance_reason = g.guidance_reason,
|
||||
expl = JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
ISNULL(q.expl, '{}'),
|
||||
'$.guidance_reason',
|
||||
g.guidance_reason
|
||||
),
|
||||
'$.guidance_price',
|
||||
g.guidance_price
|
||||
)
|
||||
FROM @queue q
|
||||
CROSS APPLY pricing.guidance_logic(
|
||||
CAST(JSON_VALUE(q.expl, '$.target_price') AS NUMERIC(20,5)),
|
||||
CAST(JSON_VALUE(q.expl, '$.last_price') AS NUMERIC(20,5)),
|
||||
CAST(JSON_VALUE(q.expl, '$.list_price') AS NUMERIC(20,5)),
|
||||
CAST(JSON_VALUE(q.expl, '$.last_date') AS DATE)
|
||||
) g;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 7: Clean up for UI
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET expl_pretty =
|
||||
(
|
||||
SELECT
|
||||
'Target Price' AS [target_price.label],
|
||||
q.tprice AS [target_price.value],
|
||||
'Volume Range' AS [volume_range.label],
|
||||
q.volume_range AS [volume_range.value],
|
||||
'Channel' AS [channel.label],
|
||||
q.chan AS [channel.value],
|
||||
'Tier' AS [tier.label],
|
||||
q.tier AS [tier.value],
|
||||
'Last Price' AS [last_price.label],
|
||||
q.last_price AS [last_price.value],
|
||||
'Last Date' AS [last_date.label],
|
||||
q.last_date AS [last_date.value],
|
||||
'Last Order' AS [last_order.label],
|
||||
q.last_order AS [last_order.value],
|
||||
'List Price' AS [list_price.label],
|
||||
q.listprice AS [list_price.value],
|
||||
'List Code' AS [list_code.label],
|
||||
q.listcode AS [list_code.value],
|
||||
'Guidance Reason' AS [guidance_reason.label],
|
||||
q.guidance_reason AS [guidance_reason.value],
|
||||
'Guidance Price' AS [guidance_price.label],
|
||||
q.guidance_price AS [guidance_price.value]
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
)
|
||||
FROM @queue q;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Final: Return the enriched result row
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT * FROM @queue;
|
||||
END;
|
@ -1,209 +0,0 @@
|
||||
DROP FUNCTION IF EXISTS pricequote.single_price_call;
|
||||
|
||||
CREATE OR REPLACE FUNCTION pricequote.single_price_call(
|
||||
_bill TEXT,
|
||||
_ship TEXT,
|
||||
_part TEXT,
|
||||
_stlc TEXT,
|
||||
_v1ds TEXT,
|
||||
_vol NUMERIC
|
||||
)
|
||||
RETURNS TABLE (
|
||||
bill TEXT,
|
||||
ship TEXT,
|
||||
part TEXT,
|
||||
stlc TEXT,
|
||||
v1ds TEXT,
|
||||
vol NUMERIC,
|
||||
chan TEXT,
|
||||
cust TEXT,
|
||||
tier TEXT,
|
||||
pltq NUMERIC,
|
||||
plevel TEXT,
|
||||
-- hist JSONB,
|
||||
last_price NUMERIC,
|
||||
last_date DATE,
|
||||
last_order TEXT,
|
||||
last_quote TEXT,
|
||||
tprice NUMERIC,
|
||||
guidance_price NUMERIC,
|
||||
guidance_reason TEXT,
|
||||
expl JSONB
|
||||
) AS $$
|
||||
DECLARE
|
||||
_pltq NUMERIC;
|
||||
_chan TEXT;
|
||||
_tier TEXT;
|
||||
_cust TEXT;
|
||||
_plevel TEXT;
|
||||
_tprice NUMERIC;
|
||||
_last_price NUMERIC;
|
||||
_last_date DATE;
|
||||
_last_order TEXT;
|
||||
_last_quote TEXT;
|
||||
_list_price NUMERIC;
|
||||
_list_code TEXT;
|
||||
_hist JSONB := '{}'::jsonb;
|
||||
_expl JSONB := '{}'::jsonb;
|
||||
_this JSONB := '{}'::jsonb;
|
||||
_guidance_price NUMERIC;
|
||||
_guidance_reason TEXT;
|
||||
_partgroup TEXT;
|
||||
BEGIN
|
||||
------------------------------------------------------------------
|
||||
-- Step 1: Resolve customer metadata
|
||||
------------------------------------------------------------------
|
||||
SELECT
|
||||
i.mpck,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE COALESCE(sc.tier, bc.tier)
|
||||
END,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN bc.dba
|
||||
ELSE sc.dba
|
||||
END
|
||||
ELSE bc.dba
|
||||
END,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN sc.plevel
|
||||
ELSE bc.plevel
|
||||
END
|
||||
ELSE bc.plevel
|
||||
END,
|
||||
i.partgroup
|
||||
INTO _pltq, _chan, _tier, _cust, _plevel, _partgroup
|
||||
FROM rlarp.cust bc
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = _ship
|
||||
LEFT JOIN "CMS.CUSLG".itemm i ON i.item = _part
|
||||
WHERE bc.code = _bill;
|
||||
|
||||
-- RAISE NOTICE 'Step 1: %', _expl;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Step 2: Target price logic
|
||||
------------------------------------------------------------------
|
||||
SELECT tp.price,
|
||||
jsonb_build_object(
|
||||
'source', 'target price',
|
||||
'target_price', tp.price,
|
||||
'calculated_pallets', FLOOR(_vol / NULLIF(_pltq, 0)),
|
||||
'exact_pallets', ROUND(_vol / NULLIF(_pltq, 0), 5),
|
||||
'volume range', tp.vol::TEXT,
|
||||
'customer', _cust,
|
||||
'channel', _chan,
|
||||
'tier', TRIM(_tier),
|
||||
'target math', tp.math
|
||||
)
|
||||
INTO _tprice, _this
|
||||
FROM pricequote.target_prices tp
|
||||
WHERE tp.stlc = _stlc
|
||||
AND tp.ds = _v1ds
|
||||
AND tp.chan = _chan
|
||||
AND tp.tier = _tier
|
||||
AND FLOOR(_vol / NULLIF(_pltq, 0))::int <@ tp.vol;
|
||||
|
||||
IF _this IS NOT NULL THEN
|
||||
_expl := _expl || _this;
|
||||
END IF;
|
||||
|
||||
-- RAISE NOTICE 'Step 2: %', _expl;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Step 3: Last sale data
|
||||
------------------------------------------------------------------
|
||||
SELECT
|
||||
(lp.dataseg_stats -> _v1ds) ->> 'price',
|
||||
(lp.dataseg_stats -> _v1ds) ->> 'odate',
|
||||
(lp.dataseg_stats -> _v1ds) ->> 'ordnum',
|
||||
(lp.dataseg_stats -> _v1ds) ->> 'quoten',
|
||||
lp.dataseg_stats
|
||||
INTO
|
||||
_last_price, _last_date, _last_order, _last_quote, _hist
|
||||
FROM pricequote.lastprice lp
|
||||
WHERE lp.customer = _cust
|
||||
AND lp.partgroup = _partgroup;
|
||||
|
||||
_expl := _expl || jsonb_build_object(
|
||||
'last_price', _last_price,
|
||||
'last_date', _last_date,
|
||||
'last_order', _last_order,
|
||||
'last_quote', _last_quote
|
||||
-- 'full_history_________', _hist
|
||||
);
|
||||
|
||||
-- RAISE NOTICE 'Step 3: %', _expl;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Step 4: List price
|
||||
------------------------------------------------------------------
|
||||
SELECT
|
||||
pr.price::numeric(20,5), pr.jcplcd
|
||||
INTO
|
||||
_list_price, _list_code
|
||||
FROM
|
||||
"CMS.CUSLG".IPRCBHC i
|
||||
JOIN pricequote.pricelist_ranged pr
|
||||
ON pr.jcplcd = TRIM(i.jbplcd)
|
||||
AND pr.jcpart = _part
|
||||
AND _vol >= pr.vb_from
|
||||
AND _vol < pr.vb_to
|
||||
WHERE TRIM(i.jbplvl) = TRIM(_plevel)
|
||||
AND CURRENT_DATE BETWEEN i.jbfdat AND i.jbtdat
|
||||
ORDER BY pr.price ASC
|
||||
LIMIT 1;
|
||||
|
||||
_expl := _expl || jsonb_build_object(
|
||||
'list_price', _list_price,
|
||||
'list_code', _list_code
|
||||
);
|
||||
|
||||
-- RAISE NOTICE 'Step 4: %', _expl;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Step 5: Compute guidance price and embed it
|
||||
------------------------------------------------------------------
|
||||
|
||||
|
||||
SELECT
|
||||
gl.guidance_price, gl.guidance_reason
|
||||
INTO
|
||||
_guidance_price, _guidance_reason
|
||||
FROM
|
||||
pricequote.guidance_logic(_tprice, _last_price, _list_price, _last_date) gl;
|
||||
|
||||
_expl := _expl || jsonb_build_object(
|
||||
'guidance_price', _guidance_price,
|
||||
'guidance_reason', _guidance_reason
|
||||
);
|
||||
|
||||
|
||||
-- RAISE NOTICE 'Step 5: %', _expl;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Final: Return row
|
||||
------------------------------------------------------------------
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
_bill, _ship, _part, _stlc, _v1ds, _vol,
|
||||
_chan, _cust, _tier, _pltq, _plevel,
|
||||
-- _hist,
|
||||
_last_price, _last_date, _last_order, _last_quote,
|
||||
_tprice,
|
||||
_guidance_price,
|
||||
_guidance_reason,
|
||||
_expl;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
@ -1,164 +0,0 @@
|
||||
CREATE OR ALTER FUNCTION pricing.single_price_call_fn (
|
||||
@bill VARCHAR(100),
|
||||
@ship VARCHAR(100),
|
||||
@part VARCHAR(100),
|
||||
@stlc VARCHAR(100),
|
||||
@v1ds VARCHAR(100),
|
||||
@vol NUMERIC(18, 6)
|
||||
)
|
||||
RETURNS TABLE
|
||||
AS
|
||||
RETURN (
|
||||
WITH queue AS (
|
||||
SELECT
|
||||
@bill AS bill,
|
||||
@ship AS ship,
|
||||
@part AS part,
|
||||
@stlc AS stlc,
|
||||
@v1ds AS v1ds,
|
||||
@vol AS vol
|
||||
),
|
||||
enriched AS (
|
||||
SELECT
|
||||
q.*,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END AS chan,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE ISNULL(sc.tier, bc.tier)
|
||||
END AS tier,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN bc.dba
|
||||
ELSE sc.dba
|
||||
END
|
||||
ELSE q.bill
|
||||
END AS cust,
|
||||
i.mpck AS pltq,
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN sc.plevel
|
||||
ELSE bc.plevel
|
||||
END
|
||||
ELSE bc.plevel
|
||||
END AS plevel
|
||||
FROM
|
||||
queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN CMSInterfaceIn.[CMS.CUSLG].itemm i ON i.item = q.part
|
||||
),
|
||||
hist AS (
|
||||
SELECT TOP 1
|
||||
e.part,
|
||||
j.qty,
|
||||
j.price AS last_price,
|
||||
j.odate AS last_date,
|
||||
j.ordnum AS last_order,
|
||||
j.quoten AS last_quote,
|
||||
JSON_QUERY(lp.part_stats) AS full_history
|
||||
FROM pricing.lastprice lp
|
||||
OUTER APPLY OPENJSON(lp.part_stats) AS p
|
||||
OUTER APPLY OPENJSON(p.value)
|
||||
WITH (
|
||||
qty NUMERIC(20, 5),
|
||||
price NUMERIC(20, 5),
|
||||
odate DATE,
|
||||
ordnum INT,
|
||||
quoten INT
|
||||
) AS j
|
||||
INNER JOIN enriched e ON
|
||||
lp.customer = e.cust AND
|
||||
lp.mold = SUBSTRING(e.part, 1, 8)
|
||||
WHERE
|
||||
p.[key] COLLATE SQL_Latin1_General_CP1_CI_AS = e.part
|
||||
ORDER BY j.odate DESC
|
||||
),
|
||||
list_price_cte AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY e.part ORDER BY p.price ASC) AS rn
|
||||
FROM enriched e
|
||||
INNER JOIN CMSInterfaceIn."CMS.CUSLG".IPRCBHC i
|
||||
ON TRIM(i.jbplvl) = TRIM(e.plevel)
|
||||
AND CAST(GETDATE() AS DATE) BETWEEN i.jbfdat AND i.jbtdat
|
||||
INNER JOIN pricing.pricelist_ranged p
|
||||
ON p.jcplcd = TRIM(i.jbplcd)
|
||||
AND p.jcpart = e.part
|
||||
AND e.vol >= p.vb_from
|
||||
AND (p.vb_to IS NULL OR e.vol < p.vb_to)
|
||||
),
|
||||
FINAL AS (
|
||||
SELECT
|
||||
e.part,
|
||||
tp.price,
|
||||
e.plevel,
|
||||
h.full_history,
|
||||
h.last_price,
|
||||
h.last_date,
|
||||
h.last_order,
|
||||
h.last_quote,
|
||||
lp.price AS list_price,
|
||||
lp.jcplcd AS list_code,
|
||||
g.guidance_price,
|
||||
g.guidance_reason,
|
||||
(
|
||||
SELECT
|
||||
'target price' AS source,
|
||||
tp.price AS target_price,
|
||||
h.last_price,
|
||||
FORMAT(h.last_date, 'yyyy-MM-dd') AS last_date,
|
||||
h.last_order,
|
||||
h.last_quote,
|
||||
lp.price AS list_price,
|
||||
lp.jcplcd AS list_code,
|
||||
FLOOR(e.vol / NULLIF(e.pltq, 0)) AS calculated_pallets,
|
||||
CAST(e.vol / NULLIF(e.pltq, 0) AS NUMERIC(20,5)) AS exact_pallets,
|
||||
CONCAT(tp.lower_bound, '-', ISNULL(CAST(tp.upper_bound AS VARCHAR), '∞')) AS [volume range],
|
||||
e.cust AS customer,
|
||||
e.chan AS channel,
|
||||
RTRIM(e.tier) AS tier,
|
||||
JSON_QUERY(tp.math) AS [target math],
|
||||
-- JSON_QUERY(h.full_history) AS [price history],
|
||||
g.guidance_price,
|
||||
g.guidance_reason
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
) AS expl
|
||||
FROM enriched e
|
||||
INNER JOIN pricing.target_prices tp ON
|
||||
e.stlc = tp.stlc AND
|
||||
e.v1ds = tp.ds AND
|
||||
e.chan = tp.chan AND
|
||||
RTRIM(e.tier) = RTRIM(tp.tier) AND
|
||||
FLOOR(e.vol / NULLIF(e.pltq, 0)) >= tp.lower_bound AND
|
||||
(tp.upper_bound IS NULL OR FLOOR(e.vol / NULLIF(e.pltq, 0)) < tp.upper_bound)
|
||||
LEFT JOIN hist h ON h.part = e.part
|
||||
LEFT JOIN list_price_cte lp ON lp.part = e.part AND lp.rn = 1
|
||||
CROSS APPLY pricing.guidance_logic(
|
||||
tp.price,
|
||||
h.last_price,
|
||||
lp.price
|
||||
) g
|
||||
)
|
||||
SELECT
|
||||
part,
|
||||
price AS target_price,
|
||||
plevel,
|
||||
last_price,
|
||||
last_date,
|
||||
last_order,
|
||||
last_quote,
|
||||
list_price,
|
||||
list_code,
|
||||
guidance_price,
|
||||
guidance_reason,
|
||||
expl
|
||||
FROM FINAL
|
||||
);
|
@ -1,15 +0,0 @@
|
||||
SELECT
|
||||
lq.*
|
||||
,t.*
|
||||
FROM
|
||||
rlarp.live_quotes lq
|
||||
OUTER APPLY pricing.fn_single_price_call(
|
||||
lq.billto,
|
||||
lq.shipto,
|
||||
lq.part,
|
||||
substring(lq.part,1,8),
|
||||
lq.v1ds,
|
||||
lq.units_each
|
||||
) t
|
||||
--WHERE
|
||||
-- qid = 112794
|
@ -1,59 +0,0 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Rebuild last price history at sales matrix refresh time
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
DELETE FROM pricing.lastprice;
|
||||
|
||||
WITH srt AS (
|
||||
SELECT
|
||||
customer,
|
||||
mold,
|
||||
part,
|
||||
version,
|
||||
qty,
|
||||
ROUND(sales_usd / qty, 5) AS price,
|
||||
odate,
|
||||
oseas,
|
||||
ordnum,
|
||||
quoten,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY customer, mold, part, version
|
||||
ORDER BY odate DESC
|
||||
) AS rn
|
||||
FROM rlarp.osm_stack
|
||||
WHERE
|
||||
--quotes can't be integrated until we have datasegment or correct part code
|
||||
version IN ('Actual'/*,'Quotes'*/) AND
|
||||
customer IS NOT NULL AND
|
||||
fs_line = '41010' AND
|
||||
calc_status <> 'CANCELLED' AND
|
||||
qty <> 0 AND
|
||||
mold <> ''
|
||||
),
|
||||
json_rows AS (
|
||||
SELECT
|
||||
customer,
|
||||
mold,
|
||||
part,
|
||||
version,
|
||||
CONCAT(
|
||||
'"', part, '":',
|
||||
(
|
||||
SELECT version, qty, price, odate, ordnum, quoten
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
)
|
||||
) AS part_json
|
||||
FROM srt
|
||||
WHERE rn = 1
|
||||
)
|
||||
,onerow AS (
|
||||
SELECT
|
||||
customer,
|
||||
mold,
|
||||
CONCAT('{', STRING_AGG(part_json, ','), '}') AS part_stats
|
||||
FROM json_rows
|
||||
GROUP BY customer, mold
|
||||
)
|
||||
INSERT INTO pricing.lastprice SELECT * FROM onerow;
|
||||
|
||||
--CREATE UNIQUE INDEX lastprice_cust_mold ON pricing.lastprice(customer, mold);
|
@ -1,52 +0,0 @@
|
||||
CREATE TABLE pricequote.lastprice AS (
|
||||
WITH
|
||||
--------SORT--------
|
||||
srt AS (
|
||||
SELECT
|
||||
customer
|
||||
,partgroup
|
||||
,dataseg
|
||||
,qtyord
|
||||
,ROUND(sales_usd/qty,5) price
|
||||
,odate
|
||||
,oseas
|
||||
,ordnum
|
||||
,quoten
|
||||
,row_number() OVER (PARTITION BY customer, partgroup, dataseg, version ORDER BY odate DESC) seq
|
||||
,version
|
||||
FROM
|
||||
rlarp.osm_stack
|
||||
WHERE
|
||||
version IN ('Actual','Quotes')
|
||||
AND customer IS NOT NULL
|
||||
AND fs_line = '41010'
|
||||
AND calc_status <> 'CANCELLED'
|
||||
-- AND customer = 'ALTMAN PLANTS'
|
||||
AND qty <> 0
|
||||
AND partgroup <> ''
|
||||
AND version = 'Actual'
|
||||
-- LIMIT 10000
|
||||
)
|
||||
,onerow AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
-- Latest per-dataseg sales wrapped as JSONB object
|
||||
jsonb_object_agg(
|
||||
dataseg,
|
||||
to_jsonb(srt)
|
||||
ORDER BY odate DESC
|
||||
) AS dataseg_stats
|
||||
FROM
|
||||
srt
|
||||
WHERE
|
||||
seq = 1
|
||||
-- AND customer = 'ALTMAN PLANTS'
|
||||
-- AND partgroup ~ 'XPR15CS'
|
||||
GROUP BY customer, partgroup
|
||||
-- ORDER BY customer, partgroup
|
||||
)
|
||||
SELECT * FROM onerow --WHERE customer = 'ALTMAN PLANTS' AND partgroup = 'XPR15CS1'
|
||||
) WITH DATA;
|
||||
|
||||
SELECT * FROM pricequote.lastprice
|
@ -1,222 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.batch_price_stack
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 1: Seed temp table from rlarp.osm_stack
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT
|
||||
bill,
|
||||
ship,
|
||||
part,
|
||||
stlc,
|
||||
v1ds,
|
||||
vol,
|
||||
NULL AS chan,
|
||||
NULL AS cust,
|
||||
NULL AS tier,
|
||||
NULL AS pltq,
|
||||
NULL AS plevel,
|
||||
NULL AS hist,
|
||||
NULL AS last_price,
|
||||
NULL AS last_date,
|
||||
NULL AS last_order,
|
||||
NULL AS last_quote,
|
||||
NULL AS tprice,
|
||||
NULL AS guidance_price,
|
||||
NULL AS guidance_reason,
|
||||
'{}' AS expl,
|
||||
NULL AS list_price,
|
||||
NULL AS list_code
|
||||
INTO #queue
|
||||
FROM rlarp.osm_stack;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 2: Enrich
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
chan =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END,
|
||||
tier =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE ISNULL(sc.tier, bc.tier)
|
||||
END,
|
||||
cust =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN bc.dba
|
||||
ELSE sc.dba
|
||||
END
|
||||
ELSE q.bill
|
||||
END,
|
||||
pltq = i.mpck,
|
||||
plevel =
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN
|
||||
CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN sc.plevel
|
||||
ELSE bc.plevel
|
||||
END
|
||||
ELSE bc.plevel
|
||||
END
|
||||
FROM #queue q
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN CMSInterfaceIn.[CMS.CUSLG].itemm i ON i.item = q.part;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 3: Apply target price and embed JSON
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
tprice = tp.price,
|
||||
expl = (
|
||||
SELECT
|
||||
'target price' AS [source],
|
||||
tp.price AS [target_price],
|
||||
FLOOR(q.vol / NULLIF(q.pltq, 0)) AS [calculated_pallets],
|
||||
CAST(ROUND(q.vol / NULLIF(q.pltq, 0), 5) AS NUMERIC(20,5)) AS [exact_pallets],
|
||||
CONCAT(tp.lower_bound, '-', ISNULL(CAST(tp.upper_bound AS VARCHAR), '∞')) AS [volume range],
|
||||
q.cust AS [customer],
|
||||
q.chan AS [channel],
|
||||
TRIM(q.tier) AS [tier],
|
||||
JSON_QUERY(tp.math) AS [target math]
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
)
|
||||
FROM #queue q
|
||||
INNER JOIN pricing.target_prices tp ON
|
||||
q.stlc = tp.stlc
|
||||
AND q.v1ds = tp.ds
|
||||
AND q.chan = tp.chan
|
||||
AND q.tier = tp.tier
|
||||
AND FLOOR(q.vol / NULLIF(q.pltq, 0)) >= tp.lower_bound
|
||||
AND (
|
||||
tp.upper_bound IS NULL OR FLOOR(q.vol / NULLIF(q.pltq, 0)) < tp.upper_bound
|
||||
);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 4: Pull last sale data
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
hist = JSON_MODIFY('{}', '$.full_history', JSON_QUERY(lp.part_stats)),
|
||||
last_price = j.price,
|
||||
last_date = j.odate,
|
||||
last_order = j.ordnum,
|
||||
last_quote = j.quoten,
|
||||
expl = JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
ISNULL(q.expl, '{}'),
|
||||
'$.last_price', j.price
|
||||
),
|
||||
'$.last_date', CONVERT(NVARCHAR(10), j.odate, 23)
|
||||
),
|
||||
'$.last_order', j.ordnum
|
||||
),
|
||||
'$.last_quote', j.quoten
|
||||
)
|
||||
FROM #queue q
|
||||
JOIN pricing.lastprice lp
|
||||
ON lp.customer = q.cust
|
||||
AND lp.mold = SUBSTRING(q.part, 1, 8)
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 *
|
||||
FROM OPENJSON(lp.part_stats) AS p
|
||||
OUTER APPLY OPENJSON(p.value)
|
||||
WITH (
|
||||
qty NUMERIC(20,5),
|
||||
price NUMERIC(20,5),
|
||||
odate DATE,
|
||||
ordnum INT,
|
||||
quoten INT
|
||||
) AS j
|
||||
WHERE p.[key] COLLATE SQL_Latin1_General_CP1_CI_AS = q.part
|
||||
ORDER BY j.odate DESC
|
||||
) AS j;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 5: Add list price info
|
||||
--------------------------------------------------------------------------------
|
||||
WITH ranked_prices AS (
|
||||
SELECT
|
||||
q.bill, q.ship, q.part, q.stlc, q.v1ds, q.vol,
|
||||
CAST(p.price AS NUMERIC(20,5)) AS price,
|
||||
p.jcplcd,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY q.bill, q.ship, q.part, q.stlc, q.v1ds, q.vol
|
||||
ORDER BY p.price ASC
|
||||
) AS rn
|
||||
FROM #queue q
|
||||
INNER JOIN CMSInterfaceIn."CMS.CUSLG".IPRCBHC i
|
||||
ON TRIM(i.jbplvl) = TRIM(q.plevel)
|
||||
AND CAST(GETDATE() AS DATE) BETWEEN i.jbfdat AND i.jbtdat
|
||||
INNER JOIN pricing.pricelist_ranged p
|
||||
ON p.jcplcd = TRIM(i.jbplcd)
|
||||
AND p.jcpart = q.part
|
||||
AND q.vol >= p.vb_from
|
||||
AND (p.vb_to IS NULL OR q.vol < p.vb_to)
|
||||
)
|
||||
UPDATE q
|
||||
SET
|
||||
list_price = rp.price,
|
||||
list_code = rp.jcplcd,
|
||||
expl = JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
ISNULL(q.expl, '{}'),
|
||||
'$.list_price', rp.price
|
||||
),
|
||||
'$.list_code', rp.jcplcd
|
||||
)
|
||||
FROM #queue q
|
||||
JOIN ranked_prices rp
|
||||
ON q.bill = rp.bill
|
||||
AND q.ship = rp.ship
|
||||
AND q.part = rp.part
|
||||
AND q.stlc = rp.stlc
|
||||
AND q.v1ds = rp.v1ds
|
||||
AND q.vol = rp.vol
|
||||
AND rp.rn = 1;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Step 6: Apply guidance logic
|
||||
--------------------------------------------------------------------------------
|
||||
UPDATE q
|
||||
SET
|
||||
guidance_price = g.guidance_price,
|
||||
guidance_reason = g.guidance_reason,
|
||||
expl = JSON_MODIFY(
|
||||
JSON_MODIFY(
|
||||
ISNULL(q.expl, '{}'),
|
||||
'$.guidance_reason',
|
||||
g.guidance_reason
|
||||
),
|
||||
'$.guidance_price',
|
||||
g.guidance_price
|
||||
)
|
||||
FROM #queue q
|
||||
CROSS APPLY pricing.guidance_logic(
|
||||
CAST(JSON_VALUE(q.expl, '$.target_price') AS NUMERIC(20,5)),
|
||||
CAST(JSON_VALUE(q.expl, '$.last_price') AS NUMERIC(20,5)),
|
||||
CAST(JSON_VALUE(q.expl, '$.list_price') AS NUMERIC(20,5))
|
||||
) g;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Final output (to result table, or SELECT)
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT * FROM #queue;
|
||||
|
||||
END;
|
||||
|
@ -1,268 +0,0 @@
|
||||
-- Drop and recreate the target table
|
||||
DROP TABLE IF EXISTS pricequote.queue;
|
||||
|
||||
CREATE TABLE pricequote.queue (
|
||||
bill TEXT,
|
||||
ship TEXT,
|
||||
part TEXT,
|
||||
stlc TEXT,
|
||||
v1ds TEXT,
|
||||
vol NUMERIC,
|
||||
chan TEXT,
|
||||
cust TEXT,
|
||||
tier TEXT,
|
||||
pltq NUMERIC,
|
||||
plevel TEXT,
|
||||
last_price NUMERIC,
|
||||
last_date DATE,
|
||||
last_order TEXT,
|
||||
last_quote TEXT,
|
||||
tprice NUMERIC,
|
||||
list_price NUMERIC,
|
||||
list_code TEXT,
|
||||
guidance_price NUMERIC,
|
||||
guidance_reason TEXT,
|
||||
expl JSONB,
|
||||
this JSONB,
|
||||
partgroup TEXT
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX idx_osm_stack_merge
|
||||
ON rlarp.osm_stack (
|
||||
bill_cust,
|
||||
ship_cust,
|
||||
part,
|
||||
stlc,
|
||||
dataseg,
|
||||
qtyord
|
||||
);
|
||||
|
||||
CREATE INDEX idx_queue_merge
|
||||
ON pricequote.queue (
|
||||
bill,
|
||||
ship,
|
||||
part,
|
||||
stlc,
|
||||
v1ds,
|
||||
vol
|
||||
);
|
||||
|
||||
|
||||
--DROP PROCEDURE IF EXISTS pricequote.process_queue;
|
||||
|
||||
CREATE OR REPLACE PROCEDURE pricequote.process_queue()
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 1: Seed the queue table with distinct pricing scenarios
|
||||
-----------------------------------------------------------------------
|
||||
DELETE FROM pricequote.queue;
|
||||
|
||||
INSERT INTO pricequote.queue (bill, ship, part, stlc, v1ds, vol, expl)
|
||||
SELECT DISTINCT
|
||||
o.bill_cust AS bill,
|
||||
o.ship_cust AS ship,
|
||||
o.part,
|
||||
o.stlc,
|
||||
o.dataseg AS v1ds,
|
||||
o.qtyord AS vol,
|
||||
'{}'::jsonb AS expl
|
||||
FROM rlarp.osm_stack o
|
||||
WHERE
|
||||
o.fs_line = '41010'
|
||||
AND o.calc_status <> 'CANCELLED'
|
||||
AND o.version IN ('Actual', 'Forecast', 'Quotes')
|
||||
AND o.part IS NOT NULL
|
||||
AND substring(o.glec, 1, 1) <= '2';
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 2: Enrich customer, tier, channel, pack quantity, and level
|
||||
-----------------------------------------------------------------------
|
||||
MERGE INTO pricequote.queue q
|
||||
USING (
|
||||
SELECT
|
||||
q.ctid,
|
||||
-- Determine sales channel
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN 'WHS'
|
||||
ELSE 'DRP'
|
||||
END
|
||||
ELSE 'DIR'
|
||||
END AS chan,
|
||||
|
||||
-- Determine pricing tier
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIR' THEN bc.tier
|
||||
ELSE COALESCE(sc.tier, bc.tier)
|
||||
END AS tier,
|
||||
|
||||
-- Resolve customer DBA name
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN bc.dba
|
||||
ELSE sc.dba
|
||||
END
|
||||
ELSE bc.dba
|
||||
END AS cust,
|
||||
|
||||
-- Pack quantity
|
||||
i.mpck AS pltq,
|
||||
|
||||
-- Price level
|
||||
CASE SUBSTRING(bc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN CASE SUBSTRING(sc.cclass, 2, 3)
|
||||
WHEN 'DIS' THEN sc.plevel
|
||||
ELSE bc.plevel
|
||||
END
|
||||
ELSE bc.plevel
|
||||
END AS plevel,
|
||||
i.partgroup
|
||||
FROM pricequote.queue q
|
||||
JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN "CMS.CUSLG".itemm i ON i.item = q.part
|
||||
) src
|
||||
ON (q.ctid = src.ctid)
|
||||
WHEN MATCHED THEN
|
||||
UPDATE SET
|
||||
chan = src.chan,
|
||||
tier = src.tier,
|
||||
cust = src.cust,
|
||||
pltq = src.pltq,
|
||||
plevel = src.plevel,
|
||||
partgroup = src.partgroup;
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 3: Apply target prices and embed target metadata
|
||||
-----------------------------------------------------------------------
|
||||
UPDATE pricequote.queue q
|
||||
SET
|
||||
tprice = tp.price,
|
||||
expl = q.expl || jsonb_build_object(
|
||||
'target_price', tp.price,
|
||||
'calculated_pallets', FLOOR(q.vol / NULLIF(q.pltq, 0)),
|
||||
'exact_pallets', ROUND(q.vol / NULLIF(q.pltq, 0), 5),
|
||||
'volume range', tp.vol::TEXT,
|
||||
'customer', q.cust,
|
||||
'channel', q.chan,
|
||||
'tier', TRIM(q.tier),
|
||||
'target math', tp.math
|
||||
)
|
||||
FROM pricequote.target_prices tp
|
||||
WHERE
|
||||
tp.stlc = q.stlc
|
||||
AND tp.ds = q.v1ds
|
||||
AND tp.chan = q.chan
|
||||
AND tp.tier = q.tier
|
||||
AND FLOOR(q.vol / NULLIF(q.pltq, 0))::int <@ tp.vol;
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 4: Lookup most recent price history and embed it
|
||||
-----------------------------------------------------------------------
|
||||
UPDATE pricequote.queue q
|
||||
SET
|
||||
last_price = ((lp.dataseg_stats -> q.v1ds)::jsonb ->> 'price')::numeric,
|
||||
last_date = ((lp.dataseg_stats -> q.v1ds)::jsonb ->> 'odate')::date,
|
||||
last_order = (lp.dataseg_stats -> q.v1ds)::jsonb ->> 'ordnum',
|
||||
last_quote = (lp.dataseg_stats -> q.v1ds)::jsonb ->> 'quoten',
|
||||
expl = q.expl || jsonb_build_object(
|
||||
'last_price', ((lp.dataseg_stats -> q.v1ds)::jsonb ->> 'price')::numeric,
|
||||
'last_date', (lp.dataseg_stats -> q.v1ds)::jsonb ->> 'odate',
|
||||
'last_order', (lp.dataseg_stats -> q.v1ds)::jsonb ->> 'ordnum',
|
||||
'last_quote', (lp.dataseg_stats -> q.v1ds)::jsonb ->> 'quoten'
|
||||
)
|
||||
FROM pricequote.lastprice lp
|
||||
WHERE
|
||||
lp.customer = q.cust
|
||||
AND lp.partgroup = SUBSTRING(q.part, 1, 8);
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 5: Resolve best list price and insert it with list code
|
||||
-----------------------------------------------------------------------
|
||||
WITH ranked_prices AS (
|
||||
SELECT
|
||||
q.ctid,
|
||||
pr.price,
|
||||
pr.jcplcd,
|
||||
ROW_NUMBER() OVER (PARTITION BY q.ctid ORDER BY pr.price ASC) AS rn
|
||||
FROM pricequote.queue q
|
||||
JOIN "CMS.CUSLG".IPRCBHC i
|
||||
ON TRIM(i.jbplvl) = TRIM(q.plevel)
|
||||
AND CURRENT_DATE BETWEEN i.jbfdat AND i.jbtdat
|
||||
JOIN pricequote.pricelist_ranged pr
|
||||
ON pr.jcplcd = TRIM(i.jbplcd)
|
||||
AND pr.jcpart = q.part
|
||||
AND q.vol >= pr.vb_from
|
||||
AND q.vol < pr.vb_to
|
||||
),
|
||||
best_price AS (
|
||||
SELECT * FROM ranked_prices WHERE rn = 1
|
||||
)
|
||||
UPDATE pricequote.queue q
|
||||
SET
|
||||
list_price = p.price,
|
||||
list_code = p.jcplcd,
|
||||
expl = q.expl || jsonb_build_object(
|
||||
'list_price', p.price,
|
||||
'list_code', p.jcplcd
|
||||
)
|
||||
FROM best_price p
|
||||
WHERE q.ctid = p.ctid;
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 6: Compute guidance price using logic function
|
||||
-----------------------------------------------------------------------
|
||||
UPDATE pricequote.queue q
|
||||
SET
|
||||
guidance_price = g.guidance_price,
|
||||
guidance_reason = g.guidance_reason,
|
||||
expl = q.expl || jsonb_build_object(
|
||||
'guidance_price', g.guidance_price,
|
||||
'guidance_reason', g.guidance_reason
|
||||
)
|
||||
FROM (
|
||||
SELECT
|
||||
q.ctid,
|
||||
g.guidance_price,
|
||||
g.guidance_reason
|
||||
FROM pricequote.queue q
|
||||
JOIN LATERAL pricequote.guidance_logic(
|
||||
q.tprice,
|
||||
q.last_price,
|
||||
q.list_price,
|
||||
q.last_date
|
||||
) g ON TRUE
|
||||
) g
|
||||
WHERE q.ctid = g.ctid;
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Step 7: merge the results back into sales matrix
|
||||
-----------------------------------------------------------------------
|
||||
UPDATE rlarp.osm_stack o
|
||||
SET pricing = pricing || q.expl
|
||||
FROM pricequote.queue q
|
||||
WHERE
|
||||
o.bill_cust = q.bill
|
||||
AND o.ship_cust IS NOT DISTINCT FROM q.ship
|
||||
AND o.part = q.part
|
||||
AND o.stlc = q.stlc
|
||||
AND o.dataseg = q.v1ds
|
||||
AND o.qtyord = q.vol
|
||||
AND o.fs_line = '41010'
|
||||
AND o.calc_status <> 'CANCELLED'
|
||||
AND o.version IN ('Actual', 'Forecast', 'Quotes')
|
||||
AND o.part IS NOT NULL
|
||||
AND substring(o.glec, 1, 1) <= '2';
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Done
|
||||
-----------------------------------------------------------------------
|
||||
RAISE NOTICE 'Queue processing complete.';
|
||||
END;
|
||||
$$;
|
@ -1,184 +0,0 @@
|
||||
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
-----------------------------------------------------------traverse unit of measure graph-----------------------------------------------------------------------
|
||||
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
-------------setup table to hold target conversions---------------------
|
||||
|
||||
|
||||
SELECT DISTINCT
|
||||
jcpart partn
|
||||
,jcunit fu
|
||||
,'PC' tu
|
||||
,cast(null as numeric) factor
|
||||
INTO
|
||||
#anchor
|
||||
FROM
|
||||
cmsinterfacein.lgdat.iprcc
|
||||
WHERE
|
||||
1=1;
|
||||
|
||||
--SELECT * FROM #anchor
|
||||
|
||||
-------pre-build punit stacked on itself with the columns flipped so you can go either direction per join---------
|
||||
SELECT
|
||||
*
|
||||
INTO
|
||||
#g
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
IHPART IHPART,
|
||||
rtrim(IHUNT1) IHUNT1,
|
||||
rtrim(IHUNT2) IHUNT2,
|
||||
IHCNV1 IHCNV1,
|
||||
IHCNV2 IHCNV2
|
||||
FROM
|
||||
CMSInterfaceIN.LGDAT.PUNIT pu
|
||||
--only deal with parts in the anchor table or the &&global parts
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT partn FROM #anchor
|
||||
) items ON
|
||||
items.partn = pu.ihpart
|
||||
OR pu.ihpart = '&&GLOBAL'
|
||||
UNION
|
||||
SELECT
|
||||
IHPART IHPART,
|
||||
rtrim(IHUNT2) IHUNT1,
|
||||
rtrim(IHUNT1) IHUNT2,
|
||||
IHCNV2 IHCNV1,
|
||||
IHCNV1 IHCNV2
|
||||
FROM
|
||||
CMSInterfaceIN.LGDAT.PUNIT pu
|
||||
--only deal with parts in the anchor table or the &&global parts
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT partn FROM #anchor
|
||||
) items ON
|
||||
items.partn = pu.ihpart
|
||||
OR pu.ihpart = '&&GLOBAL'
|
||||
) x ;
|
||||
|
||||
CREATE INDEX g_idx on #g(ihpart,ihunt1);
|
||||
|
||||
WITH
|
||||
--------do the expansion on all paths until the target uom is matched----------------------------------------------
|
||||
--(complains about types not matching between anchor and recursion, explicitly just casting everything)
|
||||
uom (partn, partx, lvl, mastf, mastt, xf, xt, factor, xfactor, xnum, xden, id, uom_list) AS
|
||||
(
|
||||
SELECT
|
||||
cast(partn as varchar(20)) --partn
|
||||
,cast(partn as varchar(20)) --partx
|
||||
,cast(0 as int) --lvl
|
||||
,fu --mastf
|
||||
,tu --mastt
|
||||
,cast(fu as varchar(3)) --xf
|
||||
,cast(fu as varchar(3)) --xt
|
||||
,CAST(1 AS FLOAT) --factor
|
||||
,CAST(1 AS FLOAT) --xfactor
|
||||
,CAST(1 AS FLOAT) --xnum
|
||||
,CAST(1 AS FLOAT) --xden
|
||||
,format(row_number() over (ORDER BY partn),'000000')
|
||||
,cast(trim(fu) as varchar(max))
|
||||
FROM
|
||||
#anchor
|
||||
UNION ALL
|
||||
SELECT
|
||||
cast(uom.partn as varchar(20)) --partn
|
||||
,cast(ihpart as varchar(20)) --partx
|
||||
,CAST(uom.lvl + 1 AS INT) --lvl
|
||||
,uom.mastf --mastf
|
||||
,uom.mastt --mastt
|
||||
,cast(p.ihunt1 as varchar(3)) --xf
|
||||
,cast(p.ihunt2 as varchar(3)) --xt
|
||||
,CAST(p.ihcnv2/p.ihcnv1 AS FLOAT) --factor
|
||||
,CAST(p.ihcnv2/p.ihcnv1 AS FLOAT) * uom.xfactor --xfactor
|
||||
,p.ihcnv2 * uom.xnum --xnum
|
||||
,p.ihcnv1 * uom.xden --xden
|
||||
,uom.id + '.' + format(row_number() over (PARTITION BY uom.id ORDER BY partn),'00')
|
||||
,uom.uom_list + '.' + trim(p.ihunt2)
|
||||
FROM
|
||||
uom
|
||||
INNER JOIN #g p ON
|
||||
p.ihpart IN (uom.partn,'&&GLOBAL')
|
||||
AND p.ihunt1 = uom.xt
|
||||
WHERE
|
||||
1=1
|
||||
--AND p.ihunt2 not in ('BD','BG','BU','BX','CA','CS','PA','PL','SL','C','K','DOZ','PR')
|
||||
AND p.ihunt1 <> uom.mastt
|
||||
--prevent recursion: newest joined UOM can't be in the history
|
||||
AND charindex(p.ihunt2,uom.uom_list) = 0
|
||||
)
|
||||
--SELECT COUNT(*) FROM UOM
|
||||
--------------uom is going to have multiple rows per requested conversion, need to use row_number to pick the best row------------------------------
|
||||
,sorted AS (
|
||||
SELECT
|
||||
partn, mastf from_uom, xt to_uom, xfactor factor, lvl steps, row_number() OVER (PARTITION BY partn, mastf, mastt ORDER BY lvl ASC, factor ASC) rn
|
||||
FROM
|
||||
uom
|
||||
WHERE
|
||||
xt = mastt
|
||||
)
|
||||
SELECT * INTO #uom FROM sorted WHERE rn = 1;
|
||||
--so far so good
|
||||
|
||||
drop table #anchor;
|
||||
drop table #g;
|
||||
|
||||
TRUNCATE TABLE pricing.pricelist_ranged;
|
||||
|
||||
WITH
|
||||
conv AS (
|
||||
SELECT
|
||||
p.jcplcd,
|
||||
p.jcpart,
|
||||
p.jcunit,
|
||||
p.jcvoll,
|
||||
p.jcpric,
|
||||
u.factor,
|
||||
-- Normalize volume and price to PC
|
||||
p.jcvoll * u.factor AS vol_pc,
|
||||
p.jcpric / u.factor AS price_pc
|
||||
FROM
|
||||
cmsinterfacein.lgdat.iprcc p
|
||||
INNER JOIN #uom u
|
||||
ON u.partn = p.jcpart
|
||||
AND u.from_uom = p.jcunit
|
||||
AND u.to_uom = 'PC'
|
||||
),
|
||||
sorted AS (
|
||||
SELECT
|
||||
c.*,
|
||||
ROW_NUMBER() OVER (PARTITION BY c.jcplcd, c.jcpart ORDER BY vol_pc ASC) AS rn
|
||||
FROM conv c
|
||||
),
|
||||
ranged AS (
|
||||
SELECT
|
||||
curr.jcplcd,
|
||||
curr.jcpart,
|
||||
curr.jcunit,
|
||||
curr.jcvoll,
|
||||
curr.jcpric,
|
||||
curr.vol_pc,
|
||||
curr.price_pc,
|
||||
curr.vol_pc AS vb_from,
|
||||
COALESCE(next.vol_pc, 9999999.0) AS vb_to
|
||||
FROM
|
||||
sorted curr
|
||||
LEFT JOIN sorted next
|
||||
ON curr.jcplcd = next.jcplcd
|
||||
AND curr.jcpart = next.jcpart
|
||||
AND curr.rn + 1 = next.rn
|
||||
)
|
||||
INSERT INTO
|
||||
pricing.pricelist_ranged
|
||||
SELECT
|
||||
RTRIM(jcplcd) jcplcd,
|
||||
RTRIM(jcpart) jcpart,
|
||||
jcunit,
|
||||
jcvoll,
|
||||
jcpric,
|
||||
vb_from,
|
||||
vb_to,
|
||||
price_pc AS price
|
||||
FROM
|
||||
ranged;
|
||||
|
||||
--CREATE INDEX pricelist_ranged_idx ON pricing.pricelist_ranged(jcpart, jcplcd, vb_from, vb_to);
|
@ -1,13 +0,0 @@
|
||||
-- FAnalysis.PRICING.lastprice definition
|
||||
|
||||
-- Drop table
|
||||
|
||||
-- DROP TABLE FAnalysis.PRICING.lastprice;
|
||||
|
||||
CREATE TABLE pricing.lastprice (
|
||||
customer varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
mold varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
|
||||
part_stats nvarchar(MAX) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE NONCLUSTERED INDEX lastprice_cust_mold ON FAnalysis.PRICING.lastprice (customer ASC, mold ASC) ;
|
@ -1,14 +0,0 @@
|
||||
DROP TABLE pricing.pricelist_ranged;
|
||||
|
||||
CREATE TABLE pricing.pricelist_ranged (
|
||||
jcplcd varchar(5) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcpart varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcunit varchar(3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcvoll numeric(12,5) NOT NULL,
|
||||
jcpric numeric(12,5) NOT NULL,
|
||||
vb_from float NULL,
|
||||
vb_to float NULL,
|
||||
price float NOT NULL
|
||||
);
|
||||
|
||||
CREATE NONCLUSTERED INDEX pricelist_ranged_idx ON FAnalysis.PRICING.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC ) ;
|
@ -1,101 +0,0 @@
|
||||
DROP TABLE IF EXISTS uomc;
|
||||
|
||||
CREATE TEMP TABLE uomc AS (
|
||||
WITH
|
||||
uom AS (
|
||||
SELECT
|
||||
uom.p part
|
||||
,uom.f fu
|
||||
,uom.t tu
|
||||
,uom.nm/uom.dm conv
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
jsonb_agg(row_to_json(d)::jsonb) jdoc
|
||||
FROM
|
||||
(
|
||||
select distinct
|
||||
jcpart partn
|
||||
, jcunit fu
|
||||
, 'PC' tu
|
||||
from
|
||||
lgdat.iprcc
|
||||
WHERE
|
||||
jcpart <> ''
|
||||
) d
|
||||
) c
|
||||
JOIN LATERAL rlarp.uom_array(c.jdoc) uom ON TRUE
|
||||
)
|
||||
SELECT * FROM uom
|
||||
) WITH DATA;
|
||||
|
||||
CREATE INDEX uom_idx ON uomc (part, fu, tu);
|
||||
|
||||
|
||||
-- Clear the output table
|
||||
TRUNCATE TABLE pricequote.pricelist_ranged;
|
||||
|
||||
--DROP TABLE pricequote.pricelist_ranged;
|
||||
|
||||
-- Compute normalized volume/price and ranges
|
||||
--CREATE TABLE pricequote.pricelist_ranged AS (
|
||||
WITH
|
||||
conv AS (
|
||||
SELECT
|
||||
p.jcplcd,
|
||||
p.jcpart,
|
||||
p.jcunit,
|
||||
p.jcvoll,
|
||||
p.jcpric,
|
||||
u.conv,
|
||||
(p.jcvoll * u.conv) AS vol_pc,
|
||||
(p.jcpric / NULLIF(u.conv, 0)) AS price_pc
|
||||
FROM
|
||||
lgdat.iprcc p
|
||||
INNER JOIN uomc u
|
||||
ON u.part = p.jcpart
|
||||
AND u.fu = p.jcunit
|
||||
AND u.tu = 'PC'
|
||||
),
|
||||
--SELECT * FROM conv LIMIT 1000
|
||||
sorted AS (
|
||||
SELECT
|
||||
*,
|
||||
ROW_NUMBER() OVER (PARTITION BY jcplcd, jcpart ORDER BY vol_pc ASC) AS rn
|
||||
FROM conv
|
||||
),
|
||||
ranged AS (
|
||||
SELECT
|
||||
curr.jcplcd,
|
||||
curr.jcpart,
|
||||
curr.jcunit,
|
||||
curr.jcvoll,
|
||||
curr.jcpric,
|
||||
curr.vol_pc,
|
||||
curr.price_pc price,
|
||||
curr.vol_pc AS vb_from,
|
||||
COALESCE(next.vol_pc, 9999999.0) AS vb_to
|
||||
FROM
|
||||
sorted curr
|
||||
LEFT JOIN sorted next
|
||||
ON curr.jcplcd = next.jcplcd
|
||||
AND curr.jcpart = next.jcpart
|
||||
AND curr.rn + 1 = next.rn
|
||||
)
|
||||
--SELECT * FROM ranged
|
||||
INSERT INTO pricequote.pricelist_ranged (
|
||||
jcplcd, jcpart, jcunit, jcvoll, jcpric, vb_from, vb_to, price
|
||||
)
|
||||
SELECT
|
||||
jcplcd,
|
||||
jcpart,
|
||||
jcunit,
|
||||
jcvoll,
|
||||
jcpric,
|
||||
vb_from,
|
||||
vb_to,
|
||||
price
|
||||
FROM ranged;
|
||||
|
||||
|
||||
CREATE INDEX pricelist_ranged_idx ON pricequote.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC ) ;
|
@ -1,18 +0,0 @@
|
||||
DROP TABLE pricing.target_prices;
|
||||
|
||||
CREATE TABLE pricing.target_prices (
|
||||
stlc nvarchar(8) NOT NULL,
|
||||
ds nvarchar(20) NOT NULL,
|
||||
chan nvarchar(3) NOT NULL,
|
||||
tier nvarchar(1) NOT NULL,
|
||||
vol nvarchar(20) NOT NULL,
|
||||
lower_bound int NOT NULL,
|
||||
upper_bound int NULL,
|
||||
price numeric(28,6) NOT NULL,
|
||||
math nvarchar(MAX) NULL
|
||||
);
|
||||
|
||||
ALTER TABLE pricing.target_prices
|
||||
ADD CONSTRAINT uq_target_prices_unique_combo
|
||||
UNIQUE (stlc, ds, chan, tier, vol, lower_bound);
|
||||
|
@ -1,14 +0,0 @@
|
||||
DROP TABLE pricequote.target_prices CASCADE;
|
||||
|
||||
CREATE TABLE pricequote.target_prices (
|
||||
stlc TEXT NOT NULL,
|
||||
ds TEXT NOT NULL,
|
||||
chan TEXT NOT NULL,
|
||||
tier TEXT NOT NULL,
|
||||
vol INT4RANGE NOT NULL,
|
||||
price NUMERIC,
|
||||
math TEXT[],
|
||||
PRIMARY KEY (stlc, ds, chan, tier, vol)
|
||||
);
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON pricequote.target_prices TO PUBLIC;
|
@ -1,11 +0,0 @@
|
||||
CREATE or REPLACE VIEW pricequote.target_prices_view AS
|
||||
SELECT
|
||||
stlc
|
||||
,ds
|
||||
,chan
|
||||
,tier
|
||||
,vol::text vol
|
||||
,price
|
||||
,to_jsonb(math)::text AS math
|
||||
FROM
|
||||
pricequote.target_prices;
|
@ -1,23 +0,0 @@
|
||||
DELETE FROM pricing.target_prices;
|
||||
|
||||
INSERT INTO
|
||||
pricing.target_prices
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
-- Extract lower bound: text between '[' and ','
|
||||
TRY_CAST(SUBSTRING(vol, 2, CHARINDEX(',', vol) - 2) AS INT) AS lower_bound,
|
||||
-- Extract upper bound: text between ',' and ')'
|
||||
CASE
|
||||
WHEN RIGHT(vol, 2) = ',)' THEN NULL
|
||||
ELSE TRY_CAST(SUBSTRING(vol, CHARINDEX(',', vol) + 1, LEN(vol) - CHARINDEX(',', vol) - 1) AS INT)
|
||||
END AS upper_bound,
|
||||
price,
|
||||
math
|
||||
FROM
|
||||
usmidsap02.ubm.pricequote.target_prices_view;
|
||||
|
||||
--SELECT COUNT(*) FROM pricing.target_prices
|
@ -1,55 +0,0 @@
|
||||
--SELECT * INTO rlarp.target_prices FROM usmidsap02.ubm.pricequote.target_prices_view
|
||||
--DROP TABLE pricing.target_prices
|
||||
DELETE FROM pricing.target_prices
|
||||
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
-- Extract lower bound: text between '[' and ','
|
||||
TRY_CAST(SUBSTRING(vol, 2, CHARINDEX(',', vol) - 2) AS INT) AS lower_bound,
|
||||
-- Extract upper bound: text between ',' and ')'
|
||||
CASE
|
||||
WHEN RIGHT(vol, 2) = ',)' THEN NULL
|
||||
ELSE TRY_CAST(SUBSTRING(vol, CHARINDEX(',', vol) + 1, LEN(vol) - CHARINDEX(',', vol) - 1) AS INT)
|
||||
END AS upper_bound,
|
||||
price,
|
||||
math
|
||||
INTO
|
||||
pricing.target_prices
|
||||
FROM
|
||||
usmidsap02.ubm.pricequote.target_prices_view;
|
||||
|
||||
INSERT INTO
|
||||
pricing.target_prices
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
-- Extract lower bound: text between '[' and ','
|
||||
TRY_CAST(SUBSTRING(vol, 2, CHARINDEX(',', vol) - 2) AS INT) AS lower_bound,
|
||||
-- Extract upper bound: text between ',' and ')'
|
||||
CASE
|
||||
WHEN RIGHT(vol, 2) = ',)' THEN NULL
|
||||
ELSE TRY_CAST(SUBSTRING(vol, CHARINDEX(',', vol) + 1, LEN(vol) - CHARINDEX(',', vol) - 1) AS INT)
|
||||
END AS upper_bound,
|
||||
price,
|
||||
math
|
||||
FROM
|
||||
usmidsap02.ubm.pricequote.target_prices_view;
|
||||
|
||||
|
||||
SELECT TOP 100 * FROM rlarp.target_prices;
|
||||
|
||||
SELECT * FROM rlarp.target_prices tp
|
||||
WHERE
|
||||
stlc = 'XNS0T1G3'
|
||||
AND ds = 'v1:T..PLT..'
|
||||
AND chan = 'DIR'
|
||||
AND tier = 1
|
||||
AND 1.01 >= lower_bound
|
||||
AND (1.01 < upper_bound OR upper_bound IS NULL);
|
118
set_anchors.ts
118
set_anchors.ts
@ -1,118 +0,0 @@
|
||||
|
||||
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
|
||||
// };
|
||||
//}
|
@ -1,152 +0,0 @@
|
||||
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$;
|
@ -1,33 +0,0 @@
|
||||
SELECT
|
||||
gset.cust
|
||||
,gset.vers
|
||||
,gset.chan
|
||||
,gset.nurs
|
||||
,gset.ghse
|
||||
,gset.mold
|
||||
,gset.v1ds
|
||||
,gset.v0ds
|
||||
,je.k
|
||||
,seas.*
|
||||
FROM
|
||||
rlarp.price_pool 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'];
|
@ -1,5 +1,5 @@
|
||||
SELECT
|
||||
(select gg.d from rlarp.get_guidance_dseg('DIAM0004','DIAM0004','AMK06000','v1:B..PLT..',5000,2026) gg(d))
|
||||
rlarp.get_guidance(lq.billto, lq.shipto, lq.part, lq.units_each, 2024)
|
||||
FROM
|
||||
pricequote.live_quotes lq
|
||||
LIMIT 1
|
||||
LIMIT 100
|
||||
|
@ -1,79 +0,0 @@
|
||||
----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$;
|
@ -1,2 +1,2 @@
|
||||
-- select gg.d from rlarp.get_guidance_dseg('DIAM0004','DIAM0004','AMK06000','v1:B..PLT..',5000,2026) gg(d);
|
||||
--select gg.d from rlarp.get_guidance('DIAM0004','DIAM0004','AMK06000G18B054',5000,2024) gg(d);
|
||||
SELECT gg.d doc FROM rlarp.get_guidance_dseg($1,$2, $3,$4, $5, 2024) gg(d);
|
||||
|
@ -42,7 +42,7 @@ BEGIN
|
||||
INTO
|
||||
_mold,_stlc,_v1ds , _v0ds, _iidx
|
||||
FROM
|
||||
"CMS.CUSLG".itemm i
|
||||
"CMS.CUSLG".itemmv i
|
||||
INNER JOIN rlarp.molds m ON
|
||||
m.stlc = i.stlc
|
||||
WHERE
|
||||
|
@ -1,4 +1,4 @@
|
||||
DROP FUNCTION rlarp.get_guidance_dseg CASCADE;
|
||||
DROP FUNCTION rlarp.get_guidance_dseg;
|
||||
CREATE OR REPLACE FUNCTION rlarp.get_guidance_dseg(_bill text, _ship text, _stlc text, _dseg text, _qty numeric, _seas int)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql AS
|
||||
@ -10,34 +10,23 @@ DECLARE
|
||||
--_ship text;
|
||||
--_qty numeric;
|
||||
--_seas int;
|
||||
_prem jsonb;
|
||||
_mold text;
|
||||
_item text;
|
||||
_unti text;
|
||||
_pltq numeric;
|
||||
_cstd numeric;
|
||||
_cstdina numeric;
|
||||
_fstd numeric;
|
||||
_fstdina numeric;
|
||||
_cust text;
|
||||
_curr text;
|
||||
_rate numeric;
|
||||
_v1ds text;
|
||||
_v0ds text;
|
||||
_v1tp jsonb;
|
||||
_v0tp jsonb;
|
||||
_chan text;
|
||||
_regn text;
|
||||
_rslt jsonb;
|
||||
_targ jsonb;
|
||||
_list jsonb;
|
||||
_iidx jsonb;
|
||||
_itemr text;
|
||||
_input jsonb;
|
||||
_product jsonb;
|
||||
_customer jsonb;
|
||||
_hist jsonb;
|
||||
_pricing jsonb;
|
||||
_prem jsonb;
|
||||
_mold text;
|
||||
_item text;
|
||||
_cust text;
|
||||
_curr text;
|
||||
_rate numeric;
|
||||
_v1ds text;
|
||||
_v0ds text;
|
||||
_v1tp jsonb;
|
||||
_v0tp jsonb;
|
||||
_chan text;
|
||||
_regn text;
|
||||
_rslt jsonb;
|
||||
_targ jsonb;
|
||||
_list jsonb;
|
||||
_iidx jsonb;
|
||||
_itemr text;
|
||||
|
||||
BEGIN
|
||||
--_item := 'AMK06000G18B054';
|
||||
@ -49,141 +38,90 @@ 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;
|
||||
_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--------------------------------
|
||||
SELECT
|
||||
part_group
|
||||
,item
|
||||
,stlc
|
||||
,idxk
|
||||
,prefer
|
||||
,pltq
|
||||
,curstdus
|
||||
,curstdus_ina
|
||||
,futstdus
|
||||
,futstdus_ina
|
||||
INTO
|
||||
_mold
|
||||
,_item
|
||||
,_stlc
|
||||
,_iidx
|
||||
,_itemr
|
||||
,_pltq
|
||||
,_cstd
|
||||
,_cstdina
|
||||
,_fstd
|
||||
,_fstdina
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
i.partgroup part_group
|
||||
m.part_group
|
||||
,min(i.item) item
|
||||
,i.stlc
|
||||
,i.v1ds
|
||||
,_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
|
||||
,i.v0ds
|
||||
,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 _ds.dataseg = _v0ds THEN 1 ELSE 0 END END prefer
|
||||
,CASE WHEN i.v1ds = _v1ds THEN 2 ELSE CASE WHEN i.v0ds = _v0ds THEN 1 ELSE 0 END END prefer
|
||||
FROM
|
||||
"CMS.CUSLG".itemm i
|
||||
LEFT OUTER JOIN _ds ON
|
||||
_ds.colgrp = i.colgrp
|
||||
AND _ds.brand = SUBSTRING(i.branding,1,1)
|
||||
--INNER JOIN rlarp.molds m ON
|
||||
-- m.stlc = i.stlc
|
||||
"CMS.CUSLG".itemmv i
|
||||
INNER JOIN rlarp.molds m ON
|
||||
m.stlc = i.stlc
|
||||
WHERE
|
||||
i.stlc = _stlc
|
||||
GROUP BY
|
||||
i.partgroup
|
||||
m.part_group
|
||||
,i.stlc
|
||||
,i.v1ds
|
||||
,_ds.dataseg
|
||||
,i.mpck
|
||||
,i.v0ds
|
||||
,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 _ds.dataseg = _v0ds THEN 1 ELSE 0 END END
|
||||
,CASE WHEN i.v1ds = _v1ds THEN 2 ELSE CASE WHEN i.v0ds = _v0ds THEN 1 ELSE 0 END END
|
||||
) best
|
||||
ORDER BY
|
||||
prefer DESC
|
||||
LIMIT 1;
|
||||
_product :=
|
||||
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);
|
||||
_rslt := jsonb_build_object('mold',_mold,'v1ds',_v1ds,'v0ds',_v0ds,'stlc',_stlc,'item',_item,'item rel',_itemr,'desg',_dseg)||_iidx;
|
||||
RAISE NOTICE 'item data %', _iidx;
|
||||
|
||||
----------------channel-------------------------------------
|
||||
|
||||
SELECT rlarp.get_cust(_bill, _ship) INTO _customer;
|
||||
--_customer := jsonb_build_object('chan',_chan);
|
||||
SELECT rlarp.channel_code(_bill, _ship) INTO _chan;
|
||||
_rslt := _rslt||jsonb_build_object('chan',_chan);
|
||||
RAISE NOTICE 'chan %', _chan;
|
||||
|
||||
----------------customer------------------------------------
|
||||
--SELECT dba INTO _cust FROM rlarp.cust WHERE code = CASE WHEN _chan = 'DRP' THEN _ship ELSE _bill END ;
|
||||
--SELECT
|
||||
-- currency,
|
||||
-- (SELECT
|
||||
-- x.rate
|
||||
-- FROM
|
||||
-- rlarp.ffcret x
|
||||
-- WHERE
|
||||
-- x.perd = (select fspr from rlarp.gld where drange @> current_date)
|
||||
-- AND x.rtyp = 'MA'
|
||||
-- and x.fcur = currency
|
||||
-- AND x.tcur = 'US'
|
||||
-- )
|
||||
--INTO
|
||||
-- _curr
|
||||
-- ,_rate
|
||||
--FROM
|
||||
-- rlarp.cust
|
||||
--WHERE
|
||||
-- code = _bill;
|
||||
SELECT dba INTO _cust FROM rlarp.cust WHERE code = CASE WHEN _chan = 'DRP' THEN _ship ELSE _bill END ;
|
||||
SELECT
|
||||
currency,
|
||||
(SELECT
|
||||
x.rate
|
||||
FROM
|
||||
rlarp.ffcret x
|
||||
WHERE
|
||||
x.perd = (select fspr from rlarp.gld where drange @> current_date)
|
||||
AND x.rtyp = 'MA'
|
||||
and x.fcur = currency
|
||||
AND x.tcur = 'US'
|
||||
)
|
||||
INTO
|
||||
_curr
|
||||
,_rate
|
||||
FROM
|
||||
rlarp.cust
|
||||
WHERE
|
||||
code = _bill;
|
||||
|
||||
--_customer := jsonb_build_object(
|
||||
-- 'customer',
|
||||
-- _customer||jsonb_build_object(
|
||||
-- 'cust',_cust
|
||||
-- ,'curr',_curr
|
||||
-- ,'fxrate',_rate
|
||||
-- )
|
||||
--);
|
||||
--RAISE NOTICE 'cust %', jsonb_pretty(_customer);
|
||||
_rslt = _rslt||jsonb_build_object('cust',_cust,'curr',_curr,'fxrate',_rate);
|
||||
RAISE NOTICE 'cust %', _cust;
|
||||
|
||||
----------------price history-------------------------------
|
||||
--RAISE NOTICE 'varb %', _customer;
|
||||
SELECT jsonb_build_object('hist',rlarp.get_hist(_mold, _v1ds, _customer->'customer'->>'cust', substring(_customer->'customer'->>'chan',1,1))) INTO _hist;
|
||||
--RAISE NOTICE 'history %', jsonb_pretty(_hist);
|
||||
SELECT _rslt||jsonb_build_object('hist',rlarp.get_hist(_mold, _v1ds, _cust, substring(_chan,1,1))) INTO _rslt ;
|
||||
RAISE NOTICE 'result %', _rslt;
|
||||
|
||||
----------------target pricing------------------------------
|
||||
SELECT
|
||||
jsonb_build_object(
|
||||
'v0tp',
|
||||
target_price,
|
||||
'v0stdv',
|
||||
'stdv',
|
||||
stdev_price
|
||||
)
|
||||
INTO
|
||||
@ -194,14 +132,14 @@ BEGIN
|
||||
mold = _stlc
|
||||
AND season = _seas
|
||||
AND data_segment = _v0ds
|
||||
AND region = 'ALL'
|
||||
AND chan = _customer->'customer'->>'chantp';
|
||||
AND region = 'ALL';
|
||||
_rslt := _rslt||COALESCE(_v0tp,'{}'::jsonb);
|
||||
----------------target pricing------------------------------
|
||||
SELECT
|
||||
jsonb_build_object(
|
||||
'v1tp',
|
||||
target_price,
|
||||
'v1stdv',
|
||||
'stdv',
|
||||
stdev_price
|
||||
)
|
||||
INTO
|
||||
@ -212,12 +150,12 @@ BEGIN
|
||||
mold = _stlc
|
||||
AND season = _seas
|
||||
AND data_segment = _dseg
|
||||
AND region = 'ALL'
|
||||
AND chan = _customer->'customer'->>'chantp';
|
||||
AND region = 'ALL';
|
||||
--RAISE NOTICE 'target: %', jsonb_pretty(_targ);
|
||||
_pricing := (COALESCE(_v0tp,'{}'::jsonb)||COALESCE(_v1tp,'{}'::jsonb));
|
||||
_rslt := _rslt||COALESCE(_v1tp,'{}'::jsonb);
|
||||
|
||||
----------------inflation index-----------------------------
|
||||
RAISE NOTICE 'infaltion : %', jsonb_pretty(_iidx);
|
||||
SELECT
|
||||
jsonb_build_object(
|
||||
'iidx'
|
||||
@ -238,21 +176,17 @@ BEGIN
|
||||
)
|
||||
GROUP BY
|
||||
priority;
|
||||
_pricing := _pricing||COALESCE(_iidx,'{}'::jsonb);
|
||||
--RAISE NOTICE 'add targets: %', jsonb_pretty(_pricing);
|
||||
_rslt := _rslt||COALESCE(_iidx,'{}'::jsonb);
|
||||
|
||||
----------------list pricing---------------------------------
|
||||
SELECT coalesce(rlarp.get_list(_bill, _ship, _item, _qty),'{}'::jsonb) INTO _list;
|
||||
_pricing := _pricing||_list;
|
||||
--RAISE NOTICE 'add list: %', jsonb_pretty(_pricing);
|
||||
_rslt := _rslt||_list;
|
||||
--RAISE NOTICE 'list: %', jsonb_pretty(_list);
|
||||
|
||||
----------------get premium for quote hist gap--------------
|
||||
SELECT coalesce(rlarp.get_premium(_stlc, _seas, _customer->'customer'->>'chantp',_hist->'hist'->'cust'->>'ds', _v1ds),'{}'::jsonb) INTO _prem;
|
||||
_pricing := jsonb_build_object('pricing',_pricing||_prem);
|
||||
--RAISE NOTICE 'add bridge: %', jsonb_pretty(_pricing);
|
||||
|
||||
_rslt := _input||_product||_customer||_pricing||_hist;
|
||||
|
||||
SELECT coalesce(rlarp.get_premium(_stlc, _seas, (SELECT xchan FROM _chx WHERE chan = _chan),_rslt->'hist'->'cust'->>'ds', _v1ds),'{}'::jsonb) INTO _prem;
|
||||
_rslt := _rslt||_prem;
|
||||
--RAISE NOTICE 'list: %', jsonb_pretty(_list);
|
||||
|
||||
RETURN _rslt;
|
||||
|
||||
|
@ -16,9 +16,8 @@ sort AS (
|
||||
,gset.*
|
||||
,row_number() OVER (PARTITION BY p.agglevel ORDER BY avgunits DESC) rn
|
||||
,stats.*
|
||||
,season
|
||||
FROM
|
||||
rlarp.price_pool p
|
||||
rlarp.price_pool_dev p
|
||||
JOIN LATERAL jsonb_to_record(gset) AS gset(
|
||||
chan text
|
||||
,mold text
|
||||
@ -38,8 +37,6 @@ sort AS (
|
||||
,early_price numeric
|
||||
,recent_season int
|
||||
,recent_price numeric
|
||||
,last_season int
|
||||
,last_price numeric
|
||||
) ON TRUE
|
||||
WHERE
|
||||
gset @> jsonb_build_object(
|
||||
@ -98,9 +95,6 @@ SELECT
|
||||
,early_price
|
||||
,recent_season
|
||||
,recent_price
|
||||
,last_season
|
||||
,last_price
|
||||
,season
|
||||
FROM
|
||||
sort
|
||||
)
|
||||
@ -110,7 +104,7 @@ FROM
|
||||
,('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
|
||||
,('customer v1ds vol' ,2)
|
||||
,('market exact' ,4)
|
||||
,('market v0ds other' ,9)
|
||||
,('market v0ds vol' ,5)
|
||||
@ -136,16 +130,13 @@ FROM
|
||||
,'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' ,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC)
|
||||
,'pricinghistory' ,season
|
||||
,'rank'
|
||||
,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC)
|
||||
)
|
||||
)
|
||||
) doc
|
||||
,row_number() OVER (PARTITION BY flag.source ORDER BY rel.prefer ASC) rnk
|
||||
,season
|
||||
FROM
|
||||
flag
|
||||
LEFT OUTER JOIN rel ON
|
||||
|
@ -1,173 +0,0 @@
|
||||
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 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;
|
@ -1,233 +0,0 @@
|
||||
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$;
|
||||
|
@ -25,7 +25,7 @@ BEGIN
|
||||
stats,
|
||||
(SELECT doc FROM getj) AS gdoc
|
||||
FROM
|
||||
rlarp.price_pool p
|
||||
rlarp.price_pool_dev p
|
||||
WHERE
|
||||
gset @> jsonb_build_object(
|
||||
'mold', (SELECT doc->>'mold' FROM getj),
|
||||
|
@ -1,5 +1,5 @@
|
||||
WITH
|
||||
sel AS (select 'v1:B..PLT..' _v1ds, 'ALTMAN PLANTS' _cust, 'XPR15CS1' _mold, 'D' _chan)
|
||||
sel AS (select 'v1:P.P.PLT..' _v1ds, 'ALTMAN PLANTS' _cust, 'TFR001G0' _mold, 'D' _chan)
|
||||
,sort AS (
|
||||
SELECT
|
||||
p.agglevel
|
||||
@ -10,7 +10,7 @@ sel AS (select 'v1:B..PLT..' _v1ds, 'ALTMAN PLANTS' _cust, 'XPR15CS1' _mold, 'D'
|
||||
,row_number() OVER (PARTITION BY p.agglevel ORDER BY avgunits DESC) rn
|
||||
,stats.*
|
||||
FROM
|
||||
rlarp.price_pool p
|
||||
rlarp.price_pool_dev p
|
||||
CROSS JOIN sel
|
||||
JOIN LATERAL jsonb_to_record(gset) AS gset(
|
||||
chan text
|
||||
|
@ -1,23 +0,0 @@
|
||||
-- DELETE FROM pricequote.price_queue;
|
||||
--
|
||||
-- ALTER SEQUENCE pricequote.price_queue_id_seq RESTART WITH 1;
|
||||
--
|
||||
-- INSERT INTO
|
||||
-- pricequote.price_queue (bill, ship, part, stlc, v1ds, vol, chan, tier)
|
||||
-- SELECT DISTINCT
|
||||
-- bill_cust, ship_cust, part, stlc, dataseg, qty, chan, customer_tier
|
||||
-- FROM
|
||||
-- rlarp.osm_stack;
|
||||
|
||||
|
||||
|
||||
UPDATE
|
||||
pricequote.price_queue q
|
||||
SET
|
||||
expl = COALESCE(q.expl, '{}'::jsonb) || jsonb_build_object('price history', l.dataseg_stats)
|
||||
FROM
|
||||
pricequote.lastprice l
|
||||
WHERE
|
||||
q.cust = l.customer
|
||||
AND q.stlc = l.partgroup;
|
||||
|
@ -1,70 +0,0 @@
|
||||
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,2025)
|
||||
) 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 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
|
@ -1,9 +1,9 @@
|
||||
--CREATE OR REPLACE PROCEDURE rlarp.price_pool()
|
||||
--LANGUAGE plpgsql AS
|
||||
--$func$
|
||||
--BEGIN;
|
||||
DROP MATERIALIZED VIEW IF EXISTS rlarp.price_pool CASCADE;
|
||||
CREATE MATERIALIZED VIEW rlarp.price_pool AS (
|
||||
--BEGIN
|
||||
DROP TABLE IF EXISTS rlarp.price_pool_dev;
|
||||
CREATE TABLE IF NOT EXISTS rlarp.price_pool_dev AS (
|
||||
WITH
|
||||
agg AS (
|
||||
SELECT
|
||||
@ -11,13 +11,13 @@ CREATE MATERIALIZED VIEW rlarp.price_pool AS (
|
||||
,substring(o.version,1,1) version
|
||||
,o.chanwide
|
||||
,o.nursery_region
|
||||
,o.greenhouse_region
|
||||
,o.partgroup baseitem
|
||||
,o.majgd
|
||||
,o.assc
|
||||
,o.coltierd
|
||||
,o.dataseg v1dataseg
|
||||
,o.v0dataseg v0dataseg
|
||||
,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
|
||||
,o.oseas oseas
|
||||
,round(sum(o.qty),0) units
|
||||
,round(sum(o.sales_usd),0) sales_usd
|
||||
@ -25,104 +25,52 @@ CREATE MATERIALIZED VIEW rlarp.price_pool AS (
|
||||
,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 = o.stlc
|
||||
AND tp.mold = i.stlc
|
||||
AND tp.chan = 'DISTRIB DROP SHIP'
|
||||
AND tp.data_segment = o.dataseg
|
||||
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 = o.stlc
|
||||
AND tq.mold = i.stlc
|
||||
AND tq.chan = 'DISTRIB DROP SHIP'
|
||||
AND tq.data_segment = o.v0dataseg
|
||||
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.oseas >= 2015
|
||||
AND o.mingd <> 'B52'
|
||||
--AND o.part like 'SQL035%'
|
||||
--AND o.calc_status <> 'CANCELED'
|
||||
AND o.fs_line = '41010'
|
||||
--AND o.dsm <> 'PW'
|
||||
--AND i.coltierd <> 'C'
|
||||
GROUP BY
|
||||
o.customer
|
||||
,substring(o.version,1,1)
|
||||
,o.chanwide
|
||||
,o.nursery_region
|
||||
,o.greenhouse_region
|
||||
,o.partgroup
|
||||
,o.majgd
|
||||
,o.assc
|
||||
,o.coltierd
|
||||
,o.dataseg
|
||||
,o.v0dataseg
|
||||
,o.oseas
|
||||
HAVING
|
||||
round(sum(o.qty),0) > 0
|
||||
AND round(sum(o.sales_usd)/sum(o.qty),5) > 0
|
||||
UNION ALL
|
||||
SELECT
|
||||
o.customer
|
||||
,substring(o.version,1,1) version
|
||||
,o.chanwide
|
||||
,o.nursery_region
|
||||
,o.greenhouse_region
|
||||
,o.partgroup baseitem
|
||||
,o.majgd
|
||||
,o.assc
|
||||
,o.coltierd
|
||||
,o.dataseg v1dataseg
|
||||
,o.v0dataseg 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
|
||||
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 = o.stlc
|
||||
AND tp.chan = 'DISTRIB DROP SHIP'
|
||||
AND tp.data_segment = o.dataseg
|
||||
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 = o.stlc
|
||||
AND tq.chan = 'DISTRIB DROP SHIP'
|
||||
AND tq.data_segment = o.v0dataseg
|
||||
WHERE
|
||||
o.version IN ('Actual','Quotes')
|
||||
AND o.odate >= current_date - '4 months'::interval
|
||||
AND o.mingd <> 'B52'
|
||||
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.coltierd <> 'C'
|
||||
--AND i.coltier <> 'C'
|
||||
GROUP BY
|
||||
o.customer
|
||||
,substring(o.version,1,1)
|
||||
,o.chanwide
|
||||
,o.nursery_region
|
||||
,o.greenhouse_region
|
||||
,o.partgroup
|
||||
,o.majgd
|
||||
,o.assc
|
||||
,o.coltierd
|
||||
,o.dataseg
|
||||
,o.v0dataseg
|
||||
,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
|
||||
@ -148,7 +96,7 @@ CREATE MATERIALIZED VIEW rlarp.price_pool AS (
|
||||
,sum(sales_usd) sales_usd
|
||||
,round(sum(sales_usd )/sum(units),5) price_usd
|
||||
,round(sum(target_price)/sum(units) FILTER (WHERE COALESCE(target_price,0) <> 0 ),5) target_price
|
||||
,jsonb_agg(DISTINCT coltierd) coltierd
|
||||
,jsonb_agg(DISTINCT coltier) coltier
|
||||
,count(DISTINCT customer) custcount
|
||||
,sum(ordcount) ordcount
|
||||
FROM
|
||||
@ -176,9 +124,8 @@ CREATE MATERIALIZED VIEW rlarp.price_pool AS (
|
||||
,round(avg(ordcount) ,1) avgordcount
|
||||
,round(avg(units) ,0) avgunits
|
||||
,round(avg(target_price),5) avgtargetprice
|
||||
,min(oseas) FILTER (WHERE oseas BETWEEN 2020 AND 2023)::text early_season
|
||||
,min(oseas) FILTER (WHERE oseas BETWEEN 2020 AND 2022)::text early_season
|
||||
,min(oseas) FILTER (WHERE oseas >= 2024)::text recent_season
|
||||
,max(oseas) FILTER (WHERE oseas >= 2020)::text last_season
|
||||
--,oseas
|
||||
--,units
|
||||
--,sales_usd
|
||||
@ -212,15 +159,10 @@ CREATE MATERIALIZED VIEW rlarp.price_pool AS (
|
||||
,recent_season::int
|
||||
,'recent_price'
|
||||
,(season->recent_season->>'price_usd')::numeric
|
||||
,'last_season'
|
||||
,last_season::int
|
||||
,'last_price'
|
||||
,(season->last_season->>'price_usd')::numeric
|
||||
) stats
|
||||
FROM
|
||||
find_stats
|
||||
--LIMIT 1000
|
||||
) WITH DATA;
|
||||
|
||||
create index ppd_gset on rlarp.price_pool using gin (gset);
|
||||
--END;
|
||||
create index ppd_gset on rlarp.price_pool_dev using gin (gset);
|
||||
|
@ -1,168 +0,0 @@
|
||||
-- set work_mem TO '4GB';
|
||||
--
|
||||
DROP VIEW IF EXISTS rlarp.quote_review;
|
||||
CREATE VIEW rlarp.quote_review AS
|
||||
WITH
|
||||
---------------------get quote lines from SQL Server---------------------
|
||||
lq AS MATERIALIZED (
|
||||
SELECT
|
||||
lq.*
|
||||
,substring(lq.part,1,8) mold
|
||||
FROM
|
||||
pricequote.live_quotes lq
|
||||
WHERE
|
||||
qstat LIKE '%Submitted%'
|
||||
)
|
||||
---------------------guidance logic---------------------------------------
|
||||
,lqg AS (
|
||||
SELECT
|
||||
lq.qid
|
||||
,lq.qline
|
||||
,lq.rep
|
||||
,lq.touched
|
||||
,lq.expires
|
||||
,lq.request
|
||||
,lq.qtitle
|
||||
,lq.qstatid
|
||||
,lq.qstat
|
||||
,lq.quotenumber
|
||||
,lq.billto
|
||||
,lq.shipto
|
||||
,lq.qchan
|
||||
,lq.qcustomer
|
||||
,CASE lq.qchan WHEN 'DIR' THEN bc.tier ELSE sc.tier END customer_tier
|
||||
,lq.part
|
||||
,lq.qoptions
|
||||
,lq.partbuilt
|
||||
,lq.colgrp
|
||||
,lq.colc
|
||||
,lq.coltier
|
||||
,lq.brand
|
||||
,lq.dataseg
|
||||
,lq.v1ds
|
||||
,lq.comment
|
||||
,lq.units_each
|
||||
,lq.price
|
||||
,lq.sales
|
||||
,lq.histprice
|
||||
,lq.targetp
|
||||
,lq.lastsalesprice
|
||||
,lq.r_curr
|
||||
,lq.qt_rate
|
||||
,lq.qrn
|
||||
,lq.url
|
||||
,lq.tacticalmodifier
|
||||
,lq.finalrecommendedprice
|
||||
,lq.lowerpricelimit
|
||||
,lq.upperpricelimit
|
||||
,(lq.upperpricelimit + lq.lowerpricelimit) / 2 midrange
|
||||
,nt.price qtarget_price
|
||||
,i.partgroup part_group
|
||||
-- ,pricing->'product'->>'itemrel' item_fit
|
||||
,i.mpck pltq
|
||||
-- ,(pricing->'guidance'->'finalPrice'->>'Price')::numeric guidance
|
||||
-- ,pricing->'guidance'->'finalPrice'->>'Reason' reason
|
||||
,lq.curstdus cstd_usd
|
||||
,lq.futstdus fstd_usd
|
||||
,CASE
|
||||
WHEN i.glec = '1NU' THEN
|
||||
--if more than 8/24 pallets, use floor
|
||||
CASE WHEN units_each >= 24*mpck THEN lq.lowerpricelimit
|
||||
-- if more than a pallet use the target price
|
||||
ELSE CASE WHEN units_each >= 8*mpck THEN (lq.upperpricelimit + lq.lowerpricelimit) / 2
|
||||
-- if more than a pallet use the target price
|
||||
ELSE CASE WHEN units_each >= 2*mpck THEN lq.upperpricelimit
|
||||
-- if more than a pallet use the target price
|
||||
ELSE lq.upperpricelimit * 1.05
|
||||
END END END
|
||||
ELSE
|
||||
CASE WHEN i.pricegroup ~ '(Hanger|Dish)' THEN
|
||||
--at least 1 pallets is lower limit
|
||||
CASE WHEN units_each >= 01*mpck THEN lq.lowerpricelimit
|
||||
--at least 2 pallets is mid range
|
||||
ELSE CASE WHEN units_each >= 0.5*mpck THEN (lq.upperpricelimit + lq.lowerpricelimit) / 2
|
||||
--less than a pallet is upper + 15%
|
||||
ELSE lq.upperpricelimit
|
||||
END END
|
||||
ELSE
|
||||
--at least 8 pallets is lower limit
|
||||
CASE WHEN units_each >= 08*mpck THEN lq.lowerpricelimit
|
||||
--at least 2 pallets is mid range
|
||||
ELSE CASE WHEN units_each >= 2*mpck THEN (lq.upperpricelimit + lq.lowerpricelimit) / 2
|
||||
--at least 1 pallet is upper range
|
||||
ELSE CASE WHEN units_each >= 1*mpck THEN lq.upperpricelimit
|
||||
--less than a pallet is upper + 15%
|
||||
ELSE lq.upperpricelimit * 1.15
|
||||
END END END
|
||||
END
|
||||
END guidance
|
||||
,pl.price pricelist
|
||||
,pl.listcode
|
||||
,row_number() OVER (PARTITION BY qid, qline ORDER BY pl.price ASC) bestprice
|
||||
-- ,(pricing->'guidance'->>'ltp')::numeric ltp
|
||||
-- ,(pricing->'guidance'->>'optimization')::numeric optimization
|
||||
-- ,(pricing->'guidance'->>'inflationFactor')::numeric inflation
|
||||
-- ,jsonb_pretty(pricing) pricing
|
||||
FROM
|
||||
lq
|
||||
LEFT OUTER JOIN "CMS.CUSLG".itemm i ON
|
||||
i.item = lq.part
|
||||
LEFT OUTER JOIN rlarp.cust bc ON
|
||||
bc.code = lq.billto
|
||||
LEFT OUTER JOIN rlarp.cust sc ON
|
||||
sc.code = lq.shipto
|
||||
LEFT OUTER JOIN rlarp.plcore_fullcode_ranged pl ON
|
||||
pl.item = lq.part
|
||||
AND jsonb_build_array(pl.listcode) <@ (COALESCE(sc.lists,bc.lists))
|
||||
AND (
|
||||
lq.units_each >= pl.vb_f
|
||||
AND lq.units_each < pl.vb_t
|
||||
)
|
||||
LEFT OUTER JOIN pricequote.target_prices nt ON
|
||||
nt.stlc = i.stlc
|
||||
AND nt.ds = lq.v1ds
|
||||
AND nt.chan = lq.qchan
|
||||
AND nt.tier = CASE lq.qchan WHEN 'DIR' THEN bc.tier ELSE sc.tier END
|
||||
AND floor(lq.units_each/i.mpck)::int <@ nt.vol
|
||||
WHERE
|
||||
lq.qstat ~ 'Submitted'
|
||||
)
|
||||
-- SELECT * FROM lqg where bestprice <> 1
|
||||
-- SELECT * FROM lqg WHERE qid = 109352
|
||||
---------------------------link in sales history----------------------------------------------
|
||||
,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 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
|
||||
WHERE
|
||||
COALESCE(g.bestprice,1) = 1
|
||||
)
|
||||
SELECT * FROM hist --WHERE qid = 108655
|
Loading…
Reference in New Issue
Block a user