Compare commits

..

No commits in common. "master" and "refactor_batch" have entirely different histories.

21 changed files with 450 additions and 1089 deletions

View File

@ -1,167 +0,0 @@
DROP FUNCTION pricequote.build_pricing_path_base;
CREATE OR REPLACE FUNCTION pricequote.build_pricing_path_base(
_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,
CASE WHEN s.func = 'Price' THEN s.val ELSE NULL::NUMERIC END AS base,
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, ' ') || ' + ' || LPAD(to_char(COALESCE(NULLIF(CASE WHEN s.func = 'Price' THEN s.val END, NULL), 0) * (s.val - 1), '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,
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
WHEN o.func = 'Price' THEN c.agg + o.val
WHEN o.func = 'Factor' THEN c.agg + COALESCE(c.base, 0) * (o.val - 1)
END agg,
COALESCE(c.base, CASE WHEN o.func = 'Price' THEN o.val ELSE NULL::NUMERIC END) AS base,
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, ' ') || ' + ' || LPAD(to_char(COALESCE(c.base, 0) * (o.val - 1), '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
*/

184
esc.json
View File

@ -1,184 +0,0 @@
[
{
"folder": "01 Gal Can",
"entity": "Anchor",
"attr": "BM.03000",
"val": 0.15,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Color Tier",
"attr": "B",
"val": 1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Color Tier",
"attr": "C",
"val": 1.2,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Color Tier",
"attr": "L",
"val": 1.1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Color Tier",
"attr": "M",
"val": 1.2,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Color Tier",
"attr": "P",
"val": 1.2,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Color Tier",
"attr": "T",
"val": 1.1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Branding",
"attr": null,
"val": 0,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Branding",
"attr": "L",
"val": 0.04,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Branding",
"attr": "P",
"val": 0.1,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Packaging",
"attr": "BDL",
"val": 0.005,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Packaging",
"attr": "CSE",
"val": 0.01,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Packaging",
"attr": "PLT",
"val": 0,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Packaging",
"attr": "SLV",
"val": 0.005,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Suffix",
"attr": null,
"val": 1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Accessories",
"attr": null,
"val": 0,
"func": "Price"
},
{
"folder": "01 Gal Can",
"entity": "Channel",
"attr": "DIR",
"val": 1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Channel",
"attr": "DRP",
"val": 1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Channel",
"attr": "WHS",
"val": 1.1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Tier",
"attr": 1,
"val": 1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Tier",
"attr": 2,
"val": 1.05,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Tier",
"attr": 3,
"val": 1.1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Volume",
"attr": "00-01",
"val": 1.35,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Volume",
"attr": "01-08",
"val": 1.1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Volume",
"attr": "24",
"val": 1,
"func": "Factor"
},
{
"folder": "01 Gal Can",
"entity": "Volume",
"attr": "08-24",
"val": 1.05,
"func": "Factor"
}
]

View File

@ -7,22 +7,12 @@ EXEC pricing.single_price_call
@vol = 9600;
EXEC pricing.single_price_call
@bill = 'FARM0001',
@ship = 'KEYB0001',
@part = 'HCA10000B661100',
@v1ds = 'v1:T..CSE..D',
@bill = 'BFGS0001',
@ship = 'BOBS0002',
@part = 'HTI10754B12B024LXB04',
@v1ds = 'v1:L.L.PLT..',
@vol = 172000;
SELECT g.*
FROM (SELECT
TRY_CAST(.33275 AS NUMERIC(20,5)) AS tprice,
TRY_CAST(.758 AS NUMERIC(20,5)) AS last_price_norm,
TRY_CAST(null AS NUMERIC(20,5)) AS listprice_eff,
TRY_CAST('2025-06-01' AS DATE) AS last_date
) q
CROSS APPLY pricing.guidance_logic(q.tprice, q.last_price_norm, q.listprice_eff, q.last_date, 0.05, 1.0, 1.0) g;
SELECT * FROM pricing.lastpricedetail l WHERE customer = 'HYBELS' AND l.partgroup = 'HZP3E100'
SELECT * FROM pricing.pricelist_ranged pr WHERE pr.jcpart = 'XNS0T1G3G18B096' AND

View File

@ -1,80 +1,42 @@
SELECT
ui_json->'data'
FROM pricequote.single_price_call(
'FARM0001',
'KEYB0001',
'HCA10000B661100',
'v1:T..CSE..D',
50000
) f;
SELECT
ui_json->'details'
FROM pricequote.single_price_call(
'FARM0001',
'KEYB0001',
'HZP3E103E21D050',
'v1:C..BDL..',
50000
) f
SELECT
*, ui_json->'data'
FROM pricequote.single_price_call(
'BFGS0001',
'SPRI0019',
'INT12040G18C100',
'v1:B..CSE..',
7037
) f;
SELECT
ui_json->'details'
FROM pricequote.single_price_call(
'FARM0001',
'KEYB0001',
'HZP3E103E21D050',
'v1:C..BDL..',
50000
) f
SELECT
*, ui_json->'data'
FROM pricequote.single_price_call(
'BELL0039',
'BELL0039',
'XNS0T1G3X19B096PZBND',
'v1:L.P.PLT..',
82420
) f;
SELECT * FROM rlarp.cust WHERE code = 'PACK0009'
SELECT
ui_json
FROM pricequote.single_price_call(
'BFGS0001',
'BOBS0002',
'HTI10754B12B024LXB04',
'v1:L.L.PLT..',
172000
) f
-- SELECT * FROM pricequote.lastpricedetail l WHERE customer = 'HYBELS' AND l.partgroup = 'HZP3E100';
--
SELECT
q.billto, q.shipto, q.part, q.v1ds, q.units_each, pc.tprice, pc.tmath
FROM
pricequote.live_quotes q
LEFT JOIN LATERAL pricequote.single_price_call(
billto, shipto, part, v1ds, units_each
) pc ON TRUE
WHERE
qid = 113761
-- AND qrn = 4;
SELECT * FROM pricequote.lastpricedetail l WHERE customer = 'HYBELS' AND l.partgroup = 'HZP3E100'
create table pricequote.target_prices_base as (
with
expand AS (
SELECT
c.compset,
c.stlc,
c.floor,
b.ds,
b.chan,
b.tier,
b.vol,
b.val,
b.price,
json_pretty(to_json(b.math)) math
FROM
pricequote.core_target c
LEFT JOIN LATERAL pricequote.build_pricing_path_base (options||jsonb_build_object('entity','Anchor','attr',c.stlc,'val',c.floor,'func','Price')) b ON b.lastflag
)
-- select count(*) from expand
select * from expand
) with data;
-- SELECT
-- stlc, ds, chan, tier, vol, price, math
-- FROM
-- pricequote.build_pricing_path_base(
-- $$
-- [{"folder":"01 Gal Can","entity":"Anchor","attr":"BM.03000","val":0.15,"func":"Price"},{"folder":"01 Gal Can","entity":"Color Tier","attr":"B","val":1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Color Tier","attr":"C","val":1.2,"func":"Factor"},{"folder":"01 Gal Can","entity":"Color Tier","attr":"L","val":1.1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Color Tier","attr":"M","val":1.2,"func":"Factor"},{"folder":"01 Gal Can","entity":"Color Tier","attr":"P","val":1.2,"func":"Factor"},{"folder":"01 Gal Can","entity":"Color Tier","attr":"T","val":1.1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Branding","attr":null,"val":0,"func":"Price"},{"folder":"01 Gal Can","entity":"Branding","attr":"L","val":0.04,"func":"Price"},{"folder":"01 Gal Can","entity":"Branding","attr":"P","val":0.1,"func":"Price"},{"folder":"01 Gal Can","entity":"Packaging","attr":"BDL","val":0.005,"func":"Price"},{"folder":"01 Gal Can","entity":"Packaging","attr":"CSE","val":0.01,"func":"Price"},{"folder":"01 Gal Can","entity":"Packaging","attr":"PLT","val":0,"func":"Price"},{"folder":"01 Gal Can","entity":"Packaging","attr":"SLV","val":0.005,"func":"Price"},{"folder":"01 Gal Can","entity":"Suffix","attr":null,"val":1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Accessories","attr":null,"val":0,"func":"Price"},{"folder":"01 Gal Can","entity":"Channel","attr":"DIR","val":1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Channel","attr":"DRP","val":1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Channel","attr":"WHS","val":1.1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Tier","attr":1,"val":1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Tier","attr":2,"val":1.05,"func":"Factor"},{"folder":"01 Gal Can","entity":"Tier","attr":3,"val":1.1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Volume","attr":"00-01","val":1.35,"func":"Factor"},{"folder":"01 Gal Can","entity":"Volume","attr":"01-08","val":1.1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Volume","attr":"24","val":1,"func":"Factor"},{"folder":"01 Gal Can","entity":"Volume","attr":"08-24","val":1.05,"func":"Factor"}]
-- $$
-- )
-- WHERE
-- lastflag
pc.expl
FROM
pricequote.live_quotes
LEFT JOIN LATERAL pricequote.single_price_call(
billto, shipto, part, v1ds, units_each
) pc ON TRUE
WHERE
qid = 113278
AND qrn = 5

View File

@ -1,81 +0,0 @@
-- CREATE OR ALTER FUNCTION pricing.approval_logic;
CREATE OR ALTER FUNCTION pricing.approval_logic(
@target numeric(20,5),
@last_norm numeric(20,5),
@list_eff numeric(20,5),
@last_date date,
@floor_pct numeric(10,5) = 0.95,
@cap_last_pct numeric(10,5) = 1.00,
@cap_list_pct numeric(10,5) = 1.00
)
RETURNS @ret TABLE (
approval_price numeric(20,5),
approval_reason nvarchar(4000)
)
AS
BEGIN
DECLARE
@base_price numeric(20,5), -- starting point (target if available, else last_norm, else list_eff)
@after_floor numeric(20,5), -- base but limited to x% lower than last price
@after_cap_last numeric(20,5), -- previous step but limited to x% higher than last price
@final_price numeric(20,5), -- previous step but limited to x% higher than list price
@reason nvarchar(4000) = N''; -- logic source of price
-- Early exit if nothing to work with
IF @target IS NULL AND @last_norm IS NULL AND @list_eff IS NULL
BEGIN
INSERT INTO @ret VALUES (NULL, N'No target, last, or list available');
RETURN;
END;
-- Pick starting base price
SET @base_price = COALESCE(@target, @last_norm, @list_eff);
-- Step 1: use base price unless it's more than x% below last price
SET @after_floor = @base_price;
IF @last_norm IS NOT NULL
SET @after_floor = ROUND(
CASE WHEN @base_price >= @last_norm*@floor_pct
THEN @base_price
ELSE @last_norm*@floor_pct
END, 5);
-- Step 2: use price from previous step but don't allow it to be x% above last price
SET @after_cap_last = @after_floor;
IF @last_norm IS NOT NULL
SET @after_cap_last = ROUND(
CASE WHEN @after_floor <= @last_norm*@cap_last_pct
THEN @after_floor
ELSE @last_norm*@cap_last_pct
END, 5);
-- Step 3: use price from last step, but don't allow it to be more than x% above list price
SET @final_price = @after_cap_last;
IF @list_eff IS NOT NULL
SET @final_price = ROUND(
CASE WHEN @after_cap_last <= @list_eff*@cap_list_pct
THEN @after_cap_last
ELSE @list_eff*@cap_list_pct
END, 5);
-- Reason text
SET @reason =
CASE
WHEN @target IS NOT NULL THEN N'Using target price'
WHEN @last_norm IS NOT NULL THEN N'Using last price as base'
WHEN @list_eff IS NOT NULL THEN N'Using list price as base'
END;
IF @last_norm IS NOT NULL AND @after_floor > @base_price
SET @reason = N'Last price drop limit';
IF @last_norm IS NOT NULL AND @after_cap_last < @after_floor
SET @reason = N'Last price increase limit';
IF @list_eff IS NOT NULL AND @final_price < @after_cap_last
SET @reason = N'List price ceiling';
INSERT INTO @ret VALUES (@final_price, @reason);
RETURN;
END;

View File

@ -1,72 +0,0 @@
CREATE OR REPLACE FUNCTION pricequote.approval_logic(
_target numeric(20,5),
_last_norm numeric(20,5),
_list_eff numeric(20,5),
_last_date date,
_floor_pct numeric(10,5) DEFAULT 0.95,
_cap_last_pct numeric(10,5) DEFAULT 1.00,
_cap_list_pct numeric(10,5) DEFAULT 1.00
)
RETURNS TABLE (
approval_price numeric(20,5),
approval_reason text
)
LANGUAGE plpgsql AS $$
DECLARE
base_price numeric(20,5);
after_floor numeric(20,5);
after_cap_last numeric(20,5);
final_price numeric(20,5);
reason text := '';
BEGIN
-- Early exit if nothing to work with
IF _target IS NULL AND _last_norm IS NULL AND _list_eff IS NULL THEN
RETURN QUERY SELECT NULL::numeric, 'No target, last, or list available';
RETURN;
END IF;
-- Pick starting base price
base_price := COALESCE(_target, _last_norm, _list_eff);
-- Step 1: use base price unless it's more than x% below last price
after_floor := base_price;
IF _last_norm IS NOT NULL THEN
after_floor := GREATEST(base_price, ROUND(_last_norm*_floor_pct,5));
END IF;
-- Step 2: use price from previous step but don't allow it to be x% above last price
after_cap_last := after_floor;
IF _last_norm IS NOT NULL THEN
after_cap_last := LEAST(after_floor, ROUND(_last_norm*_cap_last_pct,5));
END IF;
-- cap to list (binds if it lowers price)
final_price := after_cap_last;
IF _list_eff IS NOT NULL THEN
final_price := LEAST(after_cap_last, ROUND(_list_eff*_cap_list_pct,5));
END IF;
-- Reason text
reason :=
CASE
WHEN _target IS NOT NULL THEN 'Using target price'
WHEN _last_norm IS NOT NULL THEN 'Using last price as base'
WHEN _list_eff IS NOT NULL THEN 'Using list price as base'
END;
IF _last_norm IS NOT NULL AND after_floor > base_price THEN
reason := 'Last price drop limit';
END IF;
IF _last_norm IS NOT NULL AND after_cap_last < after_floor THEN
reason := 'Last price increase limit';
END IF;
IF _list_eff IS NOT NULL AND final_price < after_cap_last THEN
reason := 'List price ceiling';
END IF;
RETURN QUERY SELECT final_price, reason;
END $$;

View File

@ -1,61 +1,119 @@
-- CREATE OR ALTER FUNCTION pricing.guidance_logic;
CREATE OR ALTER FUNCTION pricing.guidance_logic(
@target numeric(20,5),
@last_norm numeric(20,5),
@list_eff numeric(20,5),
@last_date date,
@floor_pct numeric(10,5) = 0.95,
@cap_last_pct numeric(10,5) = 1.00,
@cap_list_pct numeric(10,5) = 1.00
-- This function returns the least of two NUMERIC(20,5) values.
CREATE OR ALTER FUNCTION dbo.LEAST_NUMERIC205(
@a NUMERIC(20,5),
@b NUMERIC(20,5)
)
RETURNS @ret TABLE (
guidance_price numeric(20,5),
guidance_reason nvarchar(4000)
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
GO
-- This function returns the greatest of two NUMERIC(20,5) values.
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
GO
-- This function implements the guidance logic for pricing based on target, last, and list prices.
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
@base_price numeric(20,5), -- starting point (target if available, else last_norm, else list_eff)
@after_floor numeric(20,5), -- base but limited to x% lower than last price
@after_cap_last numeric(20,5), -- previous step but limited to x% higher than last price
@final_price numeric(20,5), -- previous step but limited to x% higher than list price
@reason nvarchar(4000) = N''; -- logic source of price
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;
-- Early exit if nothing to work with
IF @target IS NULL AND @last_norm IS NULL AND @list_eff IS NULL
-- 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
INSERT INTO @ret VALUES (NULL, N'No target, last, or list available');
RETURN;
END;
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);
-- Pick starting base price
SET @base_price = COALESCE(@target, @last_norm, @list_eff);
-- Reason text
SET @reason =
CASE
WHEN @target IS NOT NULL THEN N'Using target price'
WHEN @last_norm IS NOT NULL THEN N'Using last price as base'
WHEN @list_eff IS NOT NULL THEN N'Using list price as base'
END;
-- Step 1: use base price less than last price, use last price
IF @base_price < @last_norm
BEGIN
SET @base_price = @last_norm;
SET @reason = N'Last price';
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
-- Step 2: use price from previous step but don't allow it to be x% above last price
IF @base_price > @list_eff
ELSE IF @use_last_price = 1
BEGIN
SET @base_price = @list_eff;
SET @reason = N'List price ceiling';
SET @price = @last_price;
SET @reason = 'Last price - no target';
END
SET @final_price = @base_price;
INSERT INTO @ret VALUES (@final_price, @reason);
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;
END
GO

View File

@ -1,56 +1,76 @@
CREATE OR REPLACE FUNCTION pricequote.guidance_logic(
_target numeric(20,5),
_last_norm numeric(20,5),
_list_eff numeric(20,5),
_last_date date,
_floor_pct numeric(10,5) DEFAULT 0.95,
_cap_last_pct numeric(10,5) DEFAULT 1.00,
_cap_list_pct numeric(10,5) DEFAULT 1.00
_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
)
LANGUAGE plpgsql AS $$
guidance_price NUMERIC(20,5),
guidance_reason TEXT
) AS $$
DECLARE
base_price numeric(20,5);
after_floor numeric(20,5);
after_cap_last numeric(20,5);
final_price numeric(20,5);
reason text := '';
_price NUMERIC(20,5);
_reason TEXT := '';
_floored NUMERIC(20,5);
_capped NUMERIC(20,5);
_use_last_price BOOLEAN := FALSE;
BEGIN
-- Early exit if nothing to work with
IF _target IS NULL AND _last_norm IS NULL AND _list_eff IS NULL THEN
RETURN QUERY SELECT NULL::numeric, 'No target, last, or list available';
RETURN;
-- 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;
-- Pick starting base price
base_price := COALESCE(_target, _last_norm, _list_eff);
-- Reason text
reason :=
CASE
WHEN _target IS NOT NULL THEN 'Using target price'
WHEN _last_norm IS NOT NULL THEN 'Using last price as base'
WHEN _list_eff IS NOT NULL THEN 'Using list price as base'
END;
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);
-- Step 1: use base price less than last price, use last price
IF base_price < _last_norm THEN
base_price := _last_norm;
reason := 'Last price';
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',
'Last price ignored, 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',
'Last price too old, no pricing available',
to_char(_last_date, 'YYYY-MM-DD')
);
ELSE
_reason := 'No pricing available';
END IF;
END IF;
-- Step 2: use price from previous step but don't allow it to be x% above last price
IF base_price > _list_eff THEN
base_price := _list_eff;
reason := 'List price ceiling';
END IF;
final_price := base_price;
RETURN QUERY SELECT final_price, reason;
END $$;
RETURN QUERY SELECT _price, _reason;
END;
$$ LANGUAGE plpgsql;

View File

@ -15,7 +15,7 @@ RETURNS @result TABLE (
)
AS
BEGIN
DECLARE @age_threshold DATE = DATEADD(month, -18, GETDATE());
DECLARE @age_threshold DATE = DATEADD(year, -1, GETDATE());
-- Extract all relevant objects from JSON
DECLARE @dsq NVARCHAR(MAX), @dss NVARCHAR(MAX), @mrq NVARCHAR(MAX), @mrs NVARCHAR(MAX);
@ -51,57 +51,39 @@ BEGIN
-- Use the same selection logic as before
-- 1. Prefer the most recent of dss/dsq if either is within the age threshold
IF (@dss_date IS NOT NULL AND @dss_date > @age_threshold)
BEGIN
INSERT INTO @result VALUES (@dss_price, 'dss', @dss_date, @dss_qty, @dss_dataseg, @dss_ord, @dss_quote, @dss_part);
RETURN;
END
-- IF (@dsq_date IS NOT NULL AND @dsq_date > @age_threshold)
-- OR (@dss_date IS NOT NULL AND @dss_date > @age_threshold)
-- BEGIN
-- IF @dsq_date IS NOT NULL AND (@dss_date IS NULL OR @dsq_date >= @dss_date) AND @dsq_date > @age_threshold
-- INSERT INTO @result VALUES (@dsq_price, 'dsq', @dsq_date, @dsq_qty, @dsq_dataseg, @dsq_ord, @dsq_quote, @dsq_part);
-- ELSE IF @dss_date IS NOT NULL AND @dss_date > @age_threshold
-- INSERT INTO @result VALUES (@dss_price, 'dss', @dss_date, @dss_qty, @dss_dataseg, @dss_ord, @dss_quote, @dss_part);
-- RETURN;
-- END
IF (@dsq_date IS NOT NULL AND @dsq_date > @age_threshold)
OR (@dss_date IS NOT NULL AND @dss_date > @age_threshold)
BEGIN
IF @dsq_date IS NOT NULL AND (@dss_date IS NULL OR @dsq_date >= @dss_date) AND @dsq_date > @age_threshold
INSERT INTO @result VALUES (@dsq_price, 'dsq', @dsq_date, @dsq_qty, @dsq_dataseg, @dsq_ord, @dsq_quote, @dsq_part);
ELSE IF @dss_date IS NOT NULL AND @dss_date > @age_threshold
INSERT INTO @result VALUES (@dss_price, 'dss', @dss_date, @dss_qty, @dss_dataseg, @dss_ord, @dss_quote, @dss_part);
RETURN;
END
-- 2. If both dss/dsq are older than the threshold, use the most recent of mrs/mrq if either exists
IF @mrs_date IS NOT NULL AND @mrs_date > @age_threshold
BEGIN
INSERT INTO @result VALUES (@mrs_price, 'mrs', @mrs_date, @mrs_qty, @mrs_dataseg, @mrs_ord, @mrs_quote, @mrs_part);
RETURN;
END
-- IF (@mrq_date IS NOT NULL OR @mrs_date IS NOT NULL)
-- BEGIN
-- IF @mrq_date IS NOT NULL AND (@mrs_date IS NULL OR @mrq_date >= @mrs_date)
-- INSERT INTO @result VALUES (@mrq_price, 'mrq', @mrq_date, @mrq_qty, @mrq_dataseg, @mrq_ord, @mrq_quote, @mrq_part);
-- ELSE IF @mrs_date IS NOT NULL
-- INSERT INTO @result VALUES (@mrs_price, 'mrs', @mrs_date, @mrs_qty, @mrs_dataseg, @mrs_ord, @mrs_quote, @mrs_part);
-- RETURN;
-- END
IF (@mrq_date IS NOT NULL OR @mrs_date IS NOT NULL)
BEGIN
IF @mrq_date IS NOT NULL AND (@mrs_date IS NULL OR @mrq_date >= @mrs_date)
INSERT INTO @result VALUES (@mrq_price, 'mrq', @mrq_date, @mrq_qty, @mrq_dataseg, @mrq_ord, @mrq_quote, @mrq_part);
ELSE IF @mrs_date IS NOT NULL
INSERT INTO @result VALUES (@mrs_price, 'mrs', @mrs_date, @mrs_qty, @mrs_dataseg, @mrs_ord, @mrs_quote, @mrs_part);
RETURN;
END
-- 3. If all are at least as old as the threshold, pick the least oldest price available
-- DECLARE
-- @best_price NUMERIC(20,5) = NULL
-- ,@best_source NVARCHAR(10) = NULL
-- ,@best_date DATE = NULL
-- ,@best_qty NUMERIC(20,5) = NULL
-- ,@best_dataseg NVARCHAR(100) = NULL
-- ,@best_ord NVARCHAR(20) = NULL
-- ,@best_quote NVARCHAR(20) = NULL
-- ,@best_part NVARCHAR(100) = NULL;
-- IF @dsq_date IS NOT NULL
-- SELECT @best_price = @dsq_price, @best_source = 'dsq', @best_date = @dsq_date, @best_qty = @dsq_qty, @best_dataseg = @dsq_dataseg, @best_ord = @dsq_ord, @best_quote = @dsq_quote, @best_part = @dsq_part;
-- IF @dss_date IS NOT NULL AND (@best_date IS NULL OR @dss_date > @best_date)
-- SELECT @best_price = @dss_price, @best_source = 'dss', @best_date = @dss_date, @best_qty = @dss_qty, @best_dataseg = @dss_dataseg, @best_ord = @dss_ord, @best_quote = @dss_quote, @best_part = @dss_part;
-- IF @mrq_date IS NOT NULL AND (@best_date IS NULL OR @mrq_date > @best_date)
-- SELECT @best_price = @mrq_price, @best_source = 'mrq', @best_date = @mrq_date, @best_qty = @mrq_qty, @best_dataseg = @mrq_dataseg, @best_ord = @mrq_ord, @best_quote = @mrq_quote, @best_part = @mrq_part;
-- IF @mrs_date IS NOT NULL AND (@best_date IS NULL OR @mrs_date > @best_date)
-- SELECT @best_price = @mrs_price, @best_source = 'mrs', @best_date = @mrs_date, @best_qty = @mrs_qty, @best_dataseg = @mrs_dataseg, @best_ord = @mrs_ord, @best_quote = @mrs_quote, @best_part = @mrs_part;
DECLARE @best_price NUMERIC(20,5) = NULL, @best_source NVARCHAR(10) = NULL, @best_date DATE = NULL, @best_qty NUMERIC(20,5) = NULL, @best_dataseg NVARCHAR(100) = NULL, @best_ord NVARCHAR(20) = NULL, @best_quote NVARCHAR(20) = NULL, @best_part NVARCHAR(100) = NULL;
IF @dsq_date IS NOT NULL
SELECT @best_price = @dsq_price, @best_source = 'dsq', @best_date = @dsq_date, @best_qty = @dsq_qty, @best_dataseg = @dsq_dataseg, @best_ord = @dsq_ord, @best_quote = @dsq_quote, @best_part = @dsq_part;
IF @dss_date IS NOT NULL AND (@best_date IS NULL OR @dss_date > @best_date)
SELECT @best_price = @dss_price, @best_source = 'dss', @best_date = @dss_date, @best_qty = @dss_qty, @best_dataseg = @dss_dataseg, @best_ord = @dss_ord, @best_quote = @dss_quote, @best_part = @dss_part;
IF @mrq_date IS NOT NULL AND (@best_date IS NULL OR @mrq_date > @best_date)
SELECT @best_price = @mrq_price, @best_source = 'mrq', @best_date = @mrq_date, @best_qty = @mrq_qty, @best_dataseg = @mrq_dataseg, @best_ord = @mrq_ord, @best_quote = @mrq_quote, @best_part = @mrq_part;
IF @mrs_date IS NOT NULL AND (@best_date IS NULL OR @mrs_date > @best_date)
SELECT @best_price = @mrs_price, @best_source = 'mrs', @best_date = @mrs_date, @best_qty = @mrs_qty, @best_dataseg = @mrs_dataseg, @best_ord = @mrs_ord, @best_quote = @mrs_quote, @best_part = @mrs_part;
-- IF @best_price IS NOT NULL
-- INSERT INTO @result VALUES (@best_price, @best_source, @best_date, @best_qty, @best_dataseg, @best_ord, @best_quote, @best_part);
IF @best_price IS NOT NULL
INSERT INTO @result VALUES (@best_price, @best_source, @best_date, @best_qty, @best_dataseg, @best_ord, @best_quote, @best_part);
RETURN;
END

View File

@ -12,7 +12,7 @@ DECLARE
BEGIN
-- Central control for age threshold
DECLARE
age_threshold INTERVAL := INTERVAL '18 months';
age_threshold INTERVAL := INTERVAL '1 year';
dsq_date DATE := NULL;
dss_date DATE := NULL;
mrq_date DATE := NULL;
@ -35,31 +35,40 @@ BEGIN
END IF;
-- 1. Prefer the most recent of dss/dsq if either is within the age threshold
IF dss_date IS NOT NULL AND dss_date > (CURRENT_DATE - age_threshold) THEN
result := dss || jsonb_build_object('source', 'dss');
IF (dsq_date IS NOT NULL AND dsq_date > (CURRENT_DATE - age_threshold))
OR (dss_date IS NOT NULL AND dss_date > (CURRENT_DATE - age_threshold)) THEN
IF dsq_date IS NOT NULL AND (dss_date IS NULL OR dsq_date >= dss_date) AND dsq_date > (CURRENT_DATE - age_threshold) THEN
result := dsq || jsonb_build_object('source', 'dsq');
ELSIF dss_date IS NOT NULL AND dss_date > (CURRENT_DATE - age_threshold) THEN
result := dss || jsonb_build_object('source', 'dss');
END IF;
-- 2. If both dss/dsq are older than the threshold, use the most recent of mrs/mrq if either exists
ELSIF mrs_date IS NOT NULL AND mrs_date > (CURRENT_DATE - age_threshold) THEN
result := mrs || jsonb_build_object('source', 'mrs');
ELSIF (mrq_date IS NOT NULL OR mrs_date IS NOT NULL) THEN
IF mrq_date IS NOT NULL AND (mrs_date IS NULL OR mrq_date >= mrs_date) THEN
result := mrq || jsonb_build_object('source', 'mrq');
ELSIF mrs_date IS NOT NULL THEN
result := mrs || jsonb_build_object('source', 'mrs');
END IF;
-- 3. If all are at least as old as the threshold, pick the least oldest price available
ELSE
best := NULL;
best_date := NULL;
-- IF dsq_date IS NOT NULL THEN
-- best := dsq || jsonb_build_object('source', 'dsq');
-- best_date := dsq_date;
-- END IF;
-- IF dss_date IS NOT NULL AND (best_date IS NULL OR dss_date > best_date) THEN
-- best := dss || jsonb_build_object('source', 'dss');
-- best_date := dss_date;
-- END IF;
-- IF mrq_date IS NOT NULL AND (best_date IS NULL OR mrq_date > best_date) THEN
-- best := mrq || jsonb_build_object('source', 'mrq');
-- best_date := mrq_date;
-- END IF;
-- IF mrs_date IS NOT NULL AND (best_date IS NULL OR mrs_date > best_date) THEN
-- best := mrs || jsonb_build_object('source', 'mrs');
-- best_date := mrs_date;
-- END IF;
IF dsq_date IS NOT NULL THEN
best := dsq || jsonb_build_object('source', 'dsq');
best_date := dsq_date;
END IF;
IF dss_date IS NOT NULL AND (best_date IS NULL OR dss_date > best_date) THEN
best := dss || jsonb_build_object('source', 'dss');
best_date := dss_date;
END IF;
IF mrq_date IS NOT NULL AND (best_date IS NULL OR mrq_date > best_date) THEN
best := mrq || jsonb_build_object('source', 'mrq');
best_date := mrq_date;
END IF;
IF mrs_date IS NOT NULL AND (best_date IS NULL OR mrs_date > best_date) THEN
best := mrs || jsonb_build_object('source', 'mrs');
best_date := mrs_date;
END IF;
result := best;
END IF;
RETURN result;

View File

@ -46,8 +46,6 @@ CREATE TABLE pricequote.queue (
list_relevance TEXT,
guidance_price NUMERIC,
guidance_reason TEXT,
approval_price NUMERIC,
approval_reason TEXT,
expl JSONB,
ui_json JSONB
);
@ -68,7 +66,6 @@ BEGIN
-- 1) Seed queue from matrix
--------------------------------------------------------------------
DELETE FROM pricequote.queue;
-- 1:30
INSERT INTO pricequote.queue (bill, ship, part, stlc, v1ds, vol, expl, ui_json)
SELECT DISTINCT
@ -87,7 +84,7 @@ BEGIN
AND o.version IN ('Actual', 'Forecast', 'Quotes')
AND o.part IS NOT NULL
AND SUBSTRING(o.glec, 1, 1) <= '2';
-- 2:12 0:38
-- 46 seconds
--------------------------------------------------------------------
-- 2) Enrich: chan, tier, cust, pltq, plevel, partgroup (+stlc fix)
@ -129,7 +126,7 @@ BEGIN
plevel = s.plevel,
partgroup = s.partgroup,
stlc = COALESCE(q.stlc, s.stlc_fix);
-- 4:51 0:17
-- 16 seconds
--------------------------------------------------------------------
-- 3) Scenario fields from item master: part_v1ds, v0ds, orig costs
@ -149,7 +146,7 @@ BEGIN
END
FROM "CMS.CUSLG".itemm i0
WHERE i0.item = q.part;
-- 3:21 0:20
-- 16 seconds
--------------------------------------------------------------------
-- 4) History: store hist, extract last_* with precedence helper
@ -187,7 +184,7 @@ BEGIN
AND lp2.partgroup = q2.partgroup
) AS x
WHERE q.ctid = x.ctid;
-- 7:32 1:31
-- 2 min 3 sec
--------------------------------------------------------------------
-- 5) Target (requested v1ds): tprice, tmath, volume_range
@ -197,14 +194,14 @@ BEGIN
tprice = tp.price,
tmath = to_json(tp.math),
volume_range = tp.vol::TEXT
FROM pricequote.target_prices_base tp
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;
-- 2:51 0:15
-- 22 seconds
--------------------------------------------------------------------
-- 6) Target for last_dataseg (tprice_last)
@ -212,15 +209,15 @@ BEGIN
UPDATE pricequote.queue q
SET
tprice_last = tp2.price
FROM pricequote.target_prices_base tp2
FROM pricequote.target_prices tp2
WHERE
q.last_dataseg IS NOT NULL
AND tp2.stlc = q.stlc
AND tp2.ds = q.last_dataseg
AND tp2.chan = q.chan
AND tp2.tier = q.tier
AND FLOOR(q.last_qty / NULLIF(q.pltq, 0))::INT <@ tp2.vol;
-- 1:26 0:08
AND FLOOR(q.vol / NULLIF(q.pltq, 0))::INT <@ tp2.vol;
-- 17 sec
--------------------------------------------------------------------
-- 7) Cost data for requested v1ds and last_dataseg
@ -253,7 +250,7 @@ BEGIN
ON v0l.stlc = q2.stlc AND v0l.v0ds = q2.last_v0ds
) AS s
WHERE q.ctid = s.ctid;
-- 4:15 0:25
-- 28 seconds
--------------------------------------------------------------------
-- 8) List price (lowest valid); allow open-ended ranges (vb_to IS NULL)
@ -283,7 +280,7 @@ BEGIN
listcode = p.jcplcd
FROM best_price p
WHERE q.ctid = p.ctid;
-- 2:48 0:18
-- 18 seconds
--------------------------------------------------------------------
-- 9) Normalize last (when last_dataseg != v1ds) + effective list flags
@ -300,7 +297,7 @@ BEGIN
AND q.curstd_last IS NOT NULL
AND q.curstd IS NOT NULL
AND q.curstd_last <> 0
THEN ROUND(q.curstd / q.curstd_last,5)
THEN q.curstd / q.curstd_last
END,
last_premium_method = CASE
WHEN q.last_isdiff IS NOT NULL
@ -331,7 +328,7 @@ BEGIN
END,
listprice_eff = CASE WHEN q.customized <> '' THEN NULL ELSE q.listprice END,
list_relevance = CASE WHEN q.customized <> '' THEN 'Ignore - Customized' ELSE '' END;
-- 2:22 0:23
-- 21 seconds
--------------------------------------------------------------------
-- 10) Guidance using normalized last + effective list
@ -339,35 +336,22 @@ BEGIN
UPDATE pricequote.queue q
SET
guidance_price = s.guidance_price,
guidance_reason = s.guidance_reason,
approval_price = s.approval_price,
approval_reason = s.approval_reason
guidance_reason = s.guidance_reason
FROM (
SELECT
q2.ctid,
g.guidance_price,
g.guidance_reason,
a.approval_price,
a.approval_reason
FROM
pricequote.queue q2
JOIN LATERAL pricequote.guidance_logic(
q2.tprice,
q2.last_price_norm,
q2.listprice_eff,
q2.last_date,
1.0, 1.0, 1.0
) g ON TRUE
JOIN LATERAL pricequote.approval_logic(
q2.tprice,
q2.last_price_norm,
q2.listprice_eff,
q2.last_date,
1.0, 1.0, 1.0
) a ON TRUE
g.guidance_reason
FROM pricequote.queue q2
JOIN LATERAL pricequote.guidance_logic(
q2.tprice,
q2.last_price_norm,
q2.listprice_eff,
q2.last_date
) g ON TRUE
) s
WHERE q.ctid = s.ctid;
-- 4:33 0:39
-- 31 seconds
--------------------------------------------------------------------
-- 11) Build expl and ui_json identical to single_price_call
@ -422,9 +406,7 @@ BEGIN
'list_relevance', q.list_relevance
),
'guidance_price', q.guidance_price,
'guidance_reason', q.guidance_reason,
'approval_price', q.approval_price,
'approval_reason', q.approval_reason
'guidance_reason', q.guidance_reason
),
ui_json = jsonb_build_object(
'details', jsonb_build_array(
@ -515,7 +497,7 @@ BEGIN
),
'data', q.expl
);
-- 7:59 2:17
-- 2 minutes 33 seconds
--------------------------------------------------------------------
-- 12) Merge back into matrix (store both expl and ui)
@ -539,7 +521,7 @@ BEGIN
AND o.version IN ('Actual', 'Forecast', 'Quotes')
AND o.part IS NOT NULL
AND SUBSTRING(o.glec, 1, 1) <= '2';
-- 14:13 10:09
-- 9 minutes 35 seconds
RAISE NOTICE 'Queue processing complete.';
END;

View File

@ -136,8 +136,6 @@ BEGIN
------------step 6 compute guidance------------
guidance_price NUMERIC(20,5),
guidance_reason NVARCHAR(MAX),
approval_price NUMERIC(20,5),
approval_reason NVARCHAR(MAX),
------------step 7 build json------------------
expl NVARCHAR(MAX),
ui_json NVARCHAR(MAX)
@ -175,7 +173,7 @@ BEGIN
WHEN 'DIS' THEN bc.dba
ELSE sc.dba
END
ELSE bc.dba
ELSE q.bill
END,
pltq = i.mpck,
plevel =
@ -358,7 +356,7 @@ BEGIN
SET
listcode = rp.jcplcd
,listprice = rp.price
,listprice_eff = CASE WHEN q.customized <> '' THEN NULL ELSE rp.price END
,listprice_eff = CASE WHEN q.customized <> '' THEN NULL ELSE q.listprice END
,list_relevance = CASE WHEN q.customized <> '' THEN 'Ignore - Customized' ELSE '' END
,list_from = vb_from
FROM @queue q
@ -379,33 +377,13 @@ BEGIN
SET
guidance_price = g.guidance_price
,guidance_reason = g.guidance_reason
,approval_price = a.approval_price
,approval_reason = a.approval_reason
FROM @queue q
CROSS APPLY pricing.guidance_logic(
TRY_CAST(q.tprice AS NUMERIC(20,5)),
TRY_CAST(q.last_price_norm AS NUMERIC(20,5)),
TRY_CAST(q.listprice_eff AS NUMERIC(20,5)),
TRY_CAST(q.last_date AS DATE),
--allowable price drop percent
1.0,
--cap on last price
1.0,
--cap on list percent
1.0
) g
CROSS APPLY pricing.approval_logic(
TRY_CAST(q.tprice AS NUMERIC(20,5)),
TRY_CAST(q.last_price_norm AS NUMERIC(20,5)),
TRY_CAST(q.listprice_eff AS NUMERIC(20,5)),
TRY_CAST(q.last_date AS DATE),
--allowable price drop percent
1.0,
--cap on last price
1.0,
--cap on list percent
1.0
) a;
TRY_CAST(q.last_date AS DATE)
) g;
--------------------------------------------------------------------------------
-- Step 8: Assemble structured 'expl' JSON from populated columns.
@ -452,8 +430,6 @@ BEGIN
,q.list_relevance AS list_relevance
,q.guidance_price AS guidance_price
,q.guidance_reason AS guidance_reason
,q.approval_price AS approval_price
,q.approval_reason AS approval_reason
-- JSON_QUERY(hist) AS [history]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
@ -468,13 +444,11 @@ BEGIN
(
SELECT
panel.label,
panel.detailLevel,
JSON_QUERY(panel.details) AS details
FROM (
-- History Panel
SELECT
'History' AS label,
1 as detailLevel,
(
SELECT
----------------------label------------------------------------------------
@ -484,14 +458,12 @@ BEGIN
CASE ISNULL(q.last_source, '')
WHEN 'mrq' THEN 'Similar Quote'
WHEN 'mrs' THEN 'Similar Sale'
WHEN 'dsq' THEN 'Last Quote'
WHEN 'dss' THEN 'Last Sale'
WHEN 'dsq' THEN 'Last Sale'
WHEN 'dss' THEN 'Last Quote'
ELSE ''
END
ELSE 'No Recent'
END AS label,
----------------------detail-----------------------------------------------
1 AS detailLevel,
----------------------value------------------------------------------------
ISNULL(q.last_price, 0) AS value,
----------------------type-------------------------------------------------
@ -513,12 +485,8 @@ BEGIN
END,
ISNULL(' | ' + CONVERT(varchar(10), q.last_date, 120), ''),
' | Qty ' + format(q.last_qty,'#,###'),
CASE WHEN COALESCE(last_isdiff,'') <> ''
THEN
' | Normalized To: ' + cast(last_price_norm AS varchar(10))
+ ' | ' /*+ q.last_premium_method*/ + ' Last Target = ' + format(q.tprice_last,'0.0####') + ' | Current Target = ' + format(q.tprice,'0.0####')
ELSE ''
END
CASE WHEN last_isdiff <> '' THEN ' | Normalized To: ' + cast(last_price_norm AS varchar(10)) ELSE '' END,
' | ' /*+ q.last_premium_method*/ + ' Last Target = ' + format(q.tprice_last,'0.0####') + ' | Current Target ' + format(q.tprice,'0.0####')
)
ELSE
''
@ -532,30 +500,25 @@ BEGIN
-- List Panel
SELECT
'List' AS label,
1 AS detailLevel,
(
SELECT
COALESCE('Code: ' + q.listcode,'No List') AS label,
1 AS detailLevel,
COALESCE(q.listprice,0) AS value,
'currency' AS type,
COALESCE('List Min Qty: ' + format(q.list_from,'#,###'),'') + CASE WHEN q.list_relevance = '' THEN '' ELSE ' (' + q.list_relevance + ')' END AS note
FOR JSON PATH
) AS details
)
UNION ALL
-- Target Support Panel
SELECT
'Target Calculation' AS label,
5 AS detailLevel,
(
SELECT * FROM (
SELECT
----------------------label------------------------------------------------
CASE WHEN value <> '' THEN replace(RTRIM(SUBSTRING(value,1,18)),'Anchor:', '') ELSE 'No Target' END AS label,
----------------------detailLevel------------------------------------------
10 AS detailLevel,
----------------------value------------------------------------------------
CASE WHEN value <> '' THEN
TRY_CAST(SUBSTRING(value,23,7) AS NUMERIC(20,5))
@ -580,8 +543,6 @@ BEGIN
SELECT
----------------------label------------------------------------------------
'Target' AS label,
----------------------detailLevel------------------------------------------
5 AS detailLevel,
----------------------value------------------------------------------------
tprice AS value,
----------------------type-------------------------------------------------
@ -598,11 +559,9 @@ BEGIN
-- Guidance Panel
SELECT
'Guidance' AS label,
1 AS detailLevel,
(
SELECT
'Price' AS label,
1 AS detailLevel,
COALESCE(q.guidance_price,0) AS value,
'currency' AS type,
q.guidance_reason AS note
@ -619,5 +578,5 @@ BEGIN
--------------------------------------------------------------------------------
-- Final: Return all calculated fields and JSON payloads.
--------------------------------------------------------------------------------
SELECT guidance_price, ui_json FROM @queue;
SELECT guidance_price, ui_json FROM @queue;
END;

View File

@ -35,7 +35,7 @@
====================================================================================
*/
-- DROP FUNCTION pricequote.single_price_call(text,text,text,text,numeric) CASCADE;
--DROP FUNCTION pricequote.single_price_call(text,text,text,text,numeric) CASCADE;
CREATE OR REPLACE FUNCTION pricequote.single_price_call(
_bill TEXT,
@ -89,8 +89,6 @@ RETURNS TABLE (
list_relevance TEXT,
guidance_price NUMERIC,
guidance_reason TEXT,
approval_price NUMERIC,
approval_reason TEXT,
expl JSONB,
ui_json JSONB
) AS $$
@ -150,8 +148,6 @@ DECLARE
------------step 6 compute guidance------------
_guidance_price NUMERIC;
_guidance_reason TEXT;
_approval_price NUMERIC;
_approval_reason TEXT;
------------step 7 build json------------------
_expl JSONB := '{}'::jsonb;
_ui_json JSONB := '{}'::jsonb;
@ -269,7 +265,7 @@ BEGIN
,_tmath
,_volume_range
FROM
pricequote.target_prices_base tp
pricequote.target_prices tp
WHERE
tp.stlc = _stlc
AND tp.ds = _v1ds
@ -287,36 +283,38 @@ BEGIN
INTO
_tprice_last
FROM
pricequote.target_prices_base tp
pricequote.target_prices tp
WHERE
tp.stlc = _stlc
AND tp.ds = _last_dataseg
AND tp.chan = _chan
AND tp.tier = _tier
AND FLOOR(_last_qty / NULLIF(_pltq, 0))::int <@ tp.vol;
AND FLOOR(_vol / NULLIF(_pltq, 0))::int <@ tp.vol;
------------------------------------------------------------------
-- Step 4: Cost data for normalization
------------------------------------------------------------------
-- Current/future standard for requested v1ds
SELECT
curstdus, futstdus
INTO
_curstd, _futstd
FROM
"CMS.CUSLG".itemm i
WHERE
i.item = _part
AND i.v1ds = _v1ds;
SELECT
ROUND(CASE WHEN COALESCE(_customized,'') = '' THEN _curstd_orig ELSE COALESCE(v1.curstdus, v0.curstdus) END,5) AS curstd,
ROUND(CASE WHEN COALESCE(_customized,'') = '' THEN _futstd_orig ELSE COALESCE(v1.futstdus, v0.futstdus) END,5) AS futstd,
ROUND(CASE WHEN COALESCE(_last_isdiff,'') = '' THEN _curstd_orig ELSE COALESCE(v1l.curstdus, v0l.curstdus) END,5) AS curstd_last,
ROUND(CASE WHEN COALESCE(_last_isdiff,'') = '' THEN _futstd_orig ELSE COALESCE(v1l.futstdus, v0l.futstdus) END,5) AS futstd_last
INTO
_curstd, _futstd, _curstd_last, _futstd_last
FROM (VALUES (1)) AS x(dummy)
LEFT JOIN rlarp.cost_v1ds v1
ON v1.stlc = _stlc AND v1.v1ds = _v1ds
LEFT JOIN rlarp.cost_v0ds v0
ON v0.stlc = _stlc AND v0.v0ds = _v0ds
LEFT JOIN rlarp.cost_v1ds v1l
ON v1l.stlc = _stlc AND v1l.v1ds = _last_dataseg
LEFT JOIN rlarp.cost_v0ds v0l
ON v0l.stlc = _stlc AND v0l.v0ds = _last_v0ds
LIMIT 1;
-- Current/future standard for last_dataseg
SELECT
curstdus, futstdus
INTO
_curstd_last, _futstd_last
FROM
"CMS.CUSLG".itemm i
WHERE
i.item = _part
AND i.v1ds = _last_dataseg;
------------------------------------------------------------------
-- Step 5: Normalize last price if needed
@ -327,7 +325,7 @@ BEGIN
_last_price_norm := ROUND(_last_price * (_tprice / _tprice_last), 5);
_last_premium_method := 'Target Price Ratio';
ELSIF _curstd_last IS NOT NULL AND _curstd IS NOT NULL AND _curstd_last <> 0 THEN
_last_premium := ROUND(_curstd / _curstd_last, 5);
_last_premium := _curstd / _curstd_last;
_last_price_norm := ROUND(_last_price * (_curstd / _curstd_last), 5);
_last_premium_method := 'Cost Ratio';
ELSE
@ -376,16 +374,10 @@ BEGIN
SELECT
gl.guidance_price
,gl.guidance_reason
,al.approval_price
,al.approval_reason
INTO
_guidance_price
,_guidance_reason
,_approval_price
,_approval_reason
FROM
pricequote.guidance_logic(_tprice, _last_price_norm, _listprice_eff, _last_date, 1.0, 1.0, 1.0) gl
CROSS JOIN pricequote.approval_logic(_tprice, _last_price_norm, _listprice_eff, _last_date, 1.0, 1.0, 1.0) al;
FROM pricequote.guidance_logic(_tprice, _last_price_norm, _listprice_eff, _last_date) gl;
------------------------------------------------------------------
-- Step 8: Build explanation JSON
@ -433,8 +425,7 @@ BEGIN
'targets',
jsonb_build_object(
'target_price', _tprice,
'target_math', _tmath,
'volume_range', _volume_range
'target_math', _tmath
),
'list',
jsonb_build_object(
@ -444,9 +435,7 @@ BEGIN
'list_relevance', _list_relevance
),
'guidance_price', _guidance_price,
'guidance_reason', _guidance_reason,
'approval_price', _approval_price,
'approval_reason', _approval_reason
'guidance_reason', _guidance_reason
);
------------------------------------------------------------------
@ -459,11 +448,9 @@ BEGIN
------------------------------------------
jsonb_build_object(
'label', 'History',
10, 'detailLevel',
'details', jsonb_build_array(
jsonb_build_object(
'label', CASE WHEN _last_price IS NOT NULL THEN 'Last Sale: ' || _last_date ELSE 'No Recent' END,
'detailLevel', 10,
'value', COALESCE(_last_price,0),
'type', 'currency',
'note', CASE WHEN _last_price IS NOT NULL THEN
@ -481,7 +468,6 @@ BEGIN
||CASE WHEN COALESCE(_last_premium,1) <> 1 THEN
COALESCE(jsonb_build_array(jsonb_build_object(
'label','Price Difference',
'detailLevel',10,
'value', _last_premium,
'type','percent',
'note', _last_premium_method
@ -492,7 +478,6 @@ BEGIN
||CASE WHEN COALESCE(_last_premium,1) <> 1 THEN
COALESCE(jsonb_build_array(jsonb_build_object(
'label','Adjusted Price',
'detailLevel',10,
'value', _last_price_norm,
'type','currency',
'note','normalized to ' || _v1ds
@ -506,11 +491,9 @@ BEGIN
------------------------------------------
jsonb_build_object(
'label', 'List',
'detailLevel',10,
'details', jsonb_build_array(
jsonb_build_object(
'label', 'List:' || COALESCE(_list_code, ''),
'detailLevel',10,
'value', _list_price,
'type', 'currency',
'note', _list_relevance
@ -522,7 +505,6 @@ BEGIN
------------------------------------------
jsonb_build_object(
'label', 'Target Calculation',
'detailLevel',10,
'details',
-- jsonb_build_array(
(
@ -531,8 +513,6 @@ BEGIN
jsonb_build_object(
----------------------label------------------------------------------------
'label',CASE WHEN value <> '' THEN RTRIM(SUBSTRING(value,1,18)) ELSE 'No Target' END,
----------------------detailLevel------------------------------------------
'detailLevel',10,
----------------------value------------------------------------------------
'value',CASE WHEN value <> '' THEN
SUBSTRING(value,23,7)::NUMERIC(20,5) +
@ -566,11 +546,9 @@ BEGIN
------------------------------------------
jsonb_build_object(
'label', 'Guidance',
'detailLevel',10,
'details', jsonb_build_array(
jsonb_build_object(
'label', 'Price',
'detailLevel',10,
'value', COALESCE(_guidance_price,0),
'type', 'currency',
'note', COALESCE(_guidance_reason,'')
@ -594,7 +572,6 @@ BEGIN
_tprice, _tmath, _volume_range,
_list_price, _list_code, _listprice_eff, _list_relevance,
_guidance_price, _guidance_reason,
_approval_price, _approval_reason,
_expl, _ui_json;
END;
$$ LANGUAGE plpgsql;

View File

@ -105,9 +105,6 @@ lq AS MATERIALIZED (
-- ,jsonb_pretty(pricing) pricing
,p.guidance_price
,p.guidance_reason
,p.approval_price
,p.approval_reason
,p.tprice guidance_target
,jsonb_pretty(p.ui_json->'data') expl
FROM
lq
@ -178,4 +175,4 @@ lq AS MATERIALIZED (
WHERE
COALESCE(g.bestprice,1) = 1
)
SELECT * FROM hist --LIMIT 1000--WHERE qid = 108655
SELECT * FROM hist --WHERE qid = 108655

View File

@ -1,16 +0,0 @@
DROP TABLE IF EXISTS pricequote.core_target;
CREATE TABLE pricequote.core_target (
compset TEXT NOT NULL,
stlc TEXT NOT NULL,
floor NUMERIC NOT NULL,
options JSONB NOT NULL,
PRIMARY KEY (stlc)
);
GRANT SELECT, INSERT, UPDATE, DELETE ON pricequote.target_prices TO PUBLIC;
DROP TABLE IF EXISTS import.core_target;
CREATE TABLE import.core_target AS (SELECT * FROM pricequote.core_target);

View File

@ -51,50 +51,42 @@ WITH base AS (
ranked AS (
SELECT
b.*
-- Most recent sale (Actuals only)
,CASE WHEN b.version = 'Actual' THEN
ROW_NUMBER() OVER (
-- Most recent sale
,ROW_NUMBER() OVER (
PARTITION BY b.customer, b.partgroup
ORDER BY b.odate DESC
)
END AS rn_mrs
-- Most recent quote (Quotes only)
,CASE WHEN b.version = 'Quotes' THEN
ROW_NUMBER() OVER (
ORDER BY CASE WHEN b.version = 'Actual' THEN b.odate ELSE NULL END DESC
) AS rn_mrs
-- Most recent quote
,ROW_NUMBER() OVER (
PARTITION BY b.customer, b.partgroup
ORDER BY b.odate DESC
)
END AS rn_mrq
-- Largest volume sale (Actuals only; last 12 months prioritized)
,CASE WHEN b.version = 'Actual' THEN
ROW_NUMBER() OVER (
ORDER BY CASE WHEN b.version = 'Quotes' THEN b.odate ELSE NULL END DESC
) AS rn_mrq
-- Largest volume sale (last 12 months)
,ROW_NUMBER() OVER (
PARTITION BY b.customer, b.partgroup
ORDER BY
CASE WHEN b.version = 'Actual' AND b.odate >= DATEADD(YEAR, -1, GETDATE()) THEN 1 ELSE 0 END DESC,
b.qty DESC
)
END AS rn_lvs
-- Largest volume quote (Quotes only; last 12 months prioritized)
,CASE WHEN b.version = 'Quotes' THEN
ROW_NUMBER() OVER (
ORDER BY CASE
WHEN b.version = 'Actual' AND b.odate >= DATEADD(YEAR, -1, GETDATE())
THEN b.qty ELSE NULL
END DESC
) AS rn_lvs
-- Largest volume quote (last 12 months)
,ROW_NUMBER() OVER (
PARTITION BY b.customer, b.partgroup
ORDER BY
CASE WHEN b.version = 'Quotes' AND b.odate >= DATEADD(YEAR, -1, GETDATE()) THEN 1 ELSE 0 END DESC,
b.qty DESC
)
END AS rn_lvq
,CASE WHEN b.version = 'Actual' THEN
ROW_NUMBER() OVER (
ORDER BY CASE
WHEN b.version = 'Quotes' AND b.odate >= DATEADD(YEAR, -1, GETDATE())
THEN b.qty ELSE NULL
END DESC
) AS rn_lvq
-- Most recent sale per data segment
,ROW_NUMBER() OVER (
PARTITION BY b.customer, b.partgroup, b.dataseg, b.version
ORDER BY b.odate DESC
)
END AS rn_dss
,CASE WHEN b.version = 'Quotes' THEN
ROW_NUMBER() OVER (
ORDER BY CASE WHEN b.version = 'Actual' THEN b.odate ELSE NULL END DESC
) AS rn_dss
-- Most recent quote per data segment
,ROW_NUMBER() OVER (
PARTITION BY b.customer, b.partgroup, b.dataseg, b.version
ORDER BY b.odate DESC
)
END AS rn_dsq
ORDER BY CASE WHEN b.version = 'Quotes' THEN b.odate ELSE NULL END DESC
) AS rn_dsq
FROM base b
)
--------------------------------------------------------------------------------
@ -129,7 +121,7 @@ ON #flagged(customer, partgroup, dataseg, version, part, qty, price, odate, ordn
-- Step 3.1: Explode all flags from the #flagged table
WITH exploded_flags AS (
SELECT
customer, partgroup, part, dataseg, version, qty, price, odate, ordnum, quoten,
customer, partgroup, part, dataseg, version, part, qty, price, odate, ordnum, quoten,
flag
FROM #flagged
CROSS APPLY (VALUES (f1), (f2), (f3), (f4), (f5), (f6)) AS f(flag)

View File

@ -1,6 +1,6 @@
-- REFRESH MATERIALIZED VIEW pricequote.lastpricedetail;
REFRESH MATERIALIZED VIEW pricequote.lastpricedetail;
DROP MATERIALIZED VIEW pricequote.lastpricedetail;
--DROP MATERIALIZED VIEW pricequote.lastpricedetail
CREATE MATERIALIZED VIEW pricequote.lastpricedetail AS
WITH base AS (
@ -28,38 +28,38 @@ WITH base AS (
ranked AS (
SELECT b.*,
-- Most recent sale (Actuals first, newest date first)
CASE WHEN version = 'Actual' THEN ROW_NUMBER() OVER (
ROW_NUMBER() OVER (
PARTITION BY customer, partgroup
ORDER BY (version = 'Actual') DESC,
odate DESC NULLS LAST
) END AS rn_mrs,
) AS rn_mrs,
-- Most recent quote (Quotes first, newest date first)
CASE WHEN version = 'Quotes' THEN ROW_NUMBER() OVER (
ROW_NUMBER() OVER (
PARTITION BY customer, partgroup
ORDER BY (version = 'Quotes') DESC,
odate DESC NULLS LAST
) END AS rn_mrq,
) AS rn_mrq,
-- Largest volume sale in last year (those inside window first)
CASE WHEN version = 'Actual' THEN ROW_NUMBER() OVER (
ROW_NUMBER() OVER (
PARTITION BY customer, partgroup
ORDER BY (version = 'Actual' AND odate >= CURRENT_DATE - INTERVAL '1 year') DESC,
qty DESC NULLS LAST
) END AS rn_lvs,
) AS rn_lvs,
-- Largest volume quote in last year (those inside window first)
CASE WHEN version = 'Quotes' THEN ROW_NUMBER() OVER (
ROW_NUMBER() OVER (
PARTITION BY customer, partgroup
ORDER BY (version = 'Quotes' AND odate >= CURRENT_DATE - INTERVAL '1 year') DESC,
qty DESC NULLS LAST
) END AS rn_lvq,
) AS rn_lvq,
-- Per dataseg/version: most recent (version fixed in partition, so just date)
CASE WHEN version = 'Actual' THEN ROW_NUMBER() OVER (
ROW_NUMBER() OVER (
PARTITION BY customer, partgroup, dataseg, version
ORDER BY odate DESC NULLS LAST
) END AS rn_dss,
CASE WHEN version = 'Quotes' THEN ROW_NUMBER() OVER (
) AS rn_dss,
ROW_NUMBER() OVER (
PARTITION BY customer, partgroup, dataseg, version
ORDER BY odate DESC NULLS LAST
) END AS rn_dsq
) AS rn_dsq
FROM base b
),
flagged AS (
@ -139,4 +139,4 @@ WITH DATA;
--SELECT * FROM pricequote.lastpricedetail;
CREATE INDEX lastpricedetail_idx ON pricequote.lastpricedetail(customer, partgroup);
CREATE INDEX lastpricedetail_idx ON pricequote.lastpricedetail(customer, partgroup);

View File

@ -1,28 +0,0 @@
CREATE OR REPLACE PROCEDURE pricequote.refresh_target_prices_base()
LANGUAGE plpgsql
AS $$
BEGIN
DELETE FROM pricequote.target_prices_base;
WITH expand AS (
SELECT
c.compset,
c.stlc,
c.floor,
b.ds,
b.chan,
b.tier,
b.vol,
b.val,
b.price,
b.math AS math
FROM pricequote.core_target c
LEFT JOIN LATERAL pricequote.build_pricing_path_base(
c.options || jsonb_build_object('entity','Anchor','attr',c.stlc,'val',c.floor,'func','Price')
) AS b
ON b.lastflag
)
INSERT INTO pricequote.target_prices_base
SELECT * FROM expand;
END;
$$;

View File

@ -1,17 +0,0 @@
DROP TABLE pricequote.target_prices_base CASCADE;
CREATE TABLE pricequote.target_prices_base (
compset TEXT NOT NULL,
stlc TEXT NOT NULL,
floor NUMERIC NOT NULL,
ds TEXT NOT NULL,
chan TEXT NOT NULL,
tier TEXT NOT NULL,
vol INT4RANGE NOT NULL,
val NUMERIC NOT NULL,
price NUMERIC,
math TEXT[],
PRIMARY KEY (stlc, ds, chan, tier, vol)
);
GRANT SELECT, INSERT, UPDATE, DELETE ON pricequote.target_prices_base TO PUBLIC;

View File

@ -8,4 +8,4 @@ SELECT
,price
,to_jsonb(math)::text AS math
FROM
pricequote.target_prices_base;
pricequote.target_prices;

View File

@ -1,77 +1,75 @@
{
"details": [
{
"label": "History",
"detailLevel": 10,
"details": [
"details": [
{
"label": "Last Quote",
"detailLevel": 10,
"value": 0.1012,
"type": "currency",
"note": "XNS0T1G3G18B096 | Ord# 1008338 | 2025-06-12 | Qty 19,200"
}
]
},
{
"label": "List",
"detailLevel": 10,
"details": [
{
"label": "Code: GUAU",
"detailLevel": 10,
"value": 0.11,
"type": "currency",
"note": "List Min Qty: 9,600"
}
]
},
{
"label": "Target Calculation",
"detailLevel": 10,
"details": [
{
"label": "XNS0T1G3",
"detailLevel": 10,
"value": 0.08,
"type": "currency",
"note": "Base Floor"
"label": "Model Inputs",
"details": [
{
"label": "Base Cost",
"value": 1.22446,
"type": "currency"
}
]
},
{
"label": "Channel:WHS",
"detailLevel": 10,
"value": 0.2,
"type": "Percent",
"note": "Premium"
"label": "Peer Target",
"details": [
{
"label": "Peer Median Margin",
"value": 36.873,
"type": "percent",
"note": "DIR|102 - HANGING POTS|110 - INJECTION|Tier 2"
}
]
},
{
"label": "Volume:1-8",
"detailLevel": 10,
"value": 0.1,
"type": "Percent",
"note": "Premium"
"label": "Target Support",
"details": [
{
"label": "Tier 1 Truckload",
"value": 80,
"type": "currency",
"note": "reviewed floor price"
},
{
"label": "Warehouse",
"value": 1.2,
"type": "percent"
}
]
},
{
"label": "Target",
"detailLevel": 10,
"value": 0.1056,
"type": "currency",
"note": "Total"
"label": "Factor Adjustment",
"details": [
{
"label": "Package UOM",
"value": -0.01,
"type": "percent"
},
{
"label": "# of Pallets",
"value": 0.02,
"type": "percent",
"note": "0.03"
},
{
"label": "Urgency",
"value": 0.03,
"type": "percent",
"note": "Top Priority"
},
{
"label": "State Adder/Subtractor",
"value": -0.02,
"type": "percent",
"note": "OH"
},
{
"label": "Branding",
"value": 0,
"type": "currency"
}
]
}
]
},
{
"label": "Guidance",
"detailLevel": 10,
"details": [
{
"label": "Price",
"detailLevel": 10,
"value": 0.1012,
"type": "currency",
"note": "Using target price, capped to not exceed last price"
}
]
}
]
]
}