914 lines
23 KiB
SQL
914 lines
23 KiB
SQL
-- +goose Up
|
|
DELIMITER //
|
|
DROP PROCEDURE IF EXISTS get_full_product
|
|
//
|
|
CREATE PROCEDURE get_full_product(
|
|
IN p_id_product INT UNSIGNED,
|
|
IN p_id_shop INT UNSIGNED,
|
|
IN p_id_lang INT UNSIGNED,
|
|
IN p_id_customer INT UNSIGNED,
|
|
IN b2b_id_country INT UNSIGNED,
|
|
IN p_quantity INT UNSIGNED
|
|
)
|
|
BEGIN
|
|
DECLARE v_tax_rate DECIMAL(10, 4) DEFAULT 0;
|
|
DECLARE p_id_currency DECIMAL(10, 4) DEFAULT 0;
|
|
SELECT
|
|
COALESCE(t.rate, 0.0000) INTO v_tax_rate
|
|
FROM
|
|
ps_tax_rule tr
|
|
INNER JOIN ps_tax t ON t.id_tax = tr.id_tax
|
|
LEFT JOIN b2b_countries ON b2b_countries.id = b2b_id_country
|
|
WHERE
|
|
tr.id_tax_rules_group = (
|
|
SELECT
|
|
ps.id_tax_rules_group
|
|
FROM
|
|
ps_product_shop ps
|
|
WHERE
|
|
ps.id_product = p_id_product
|
|
AND ps.id_shop = p_id_shop
|
|
LIMIT
|
|
1
|
|
)
|
|
AND tr.id_country = b2b_countries.ps_id_country
|
|
ORDER BY
|
|
tr.id_state DESC,
|
|
tr.zipcode_from != '' DESC,
|
|
tr.id_tax_rule DESC
|
|
LIMIT
|
|
1;
|
|
|
|
SELECT
|
|
b2b_currencies.ps_id_currency INTO p_id_currency
|
|
FROM
|
|
b2b_currencies
|
|
LEFT JOIN b2b_countries ON b2b_countries.b2b_id_currency = b2b_currencies.id
|
|
WHERE
|
|
b2b_countries.id = b2b_id_country
|
|
LIMIT 1;
|
|
|
|
/* FINAL JSON */
|
|
SELECT
|
|
JSON_OBJECT(
|
|
/* ================= PRODUCT ================= */
|
|
'id_product',
|
|
p.id_product,
|
|
'reference',
|
|
p.reference,
|
|
'name',
|
|
pl.name,
|
|
'description',
|
|
pl.description,
|
|
'short_description',
|
|
pl.description_short,
|
|
/* ================= PRICE ================= */
|
|
'price',
|
|
JSON_OBJECT(
|
|
'base',
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate),
|
|
|
|
'final_tax_excl',
|
|
(
|
|
CASE
|
|
WHEN bsp.id IS NOT NULL THEN
|
|
CASE
|
|
/* FIXED PRICE */
|
|
WHEN bsp.reduction_type = 'amount' THEN
|
|
(
|
|
CASE
|
|
WHEN bsp.b2b_id_currency IS NULL THEN bsp.price
|
|
ELSE bsp.price * br_bsp.conversion_rate
|
|
END
|
|
)
|
|
|
|
/* PERCENTAGE */
|
|
WHEN bsp.reduction_type = 'percentage' THEN
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
* (1 - bsp.percentage_reduction / 100)
|
|
|
|
ELSE
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
END
|
|
|
|
ELSE
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
END
|
|
),
|
|
|
|
'final_tax_incl',
|
|
(
|
|
(
|
|
CASE
|
|
WHEN bsp.id IS NOT NULL THEN
|
|
CASE
|
|
WHEN bsp.reduction_type = 'amount' THEN
|
|
(
|
|
CASE
|
|
WHEN bsp.b2b_id_currency IS NULL THEN bsp.price
|
|
ELSE bsp.price * br_bsp.conversion_rate
|
|
END
|
|
)
|
|
|
|
WHEN bsp.reduction_type = 'percentage' THEN
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
* (1 - bsp.percentage_reduction / 100)
|
|
|
|
ELSE
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
END
|
|
ELSE
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
END
|
|
) * (1 + v_tax_rate / 100)
|
|
)
|
|
),
|
|
/* ================= META ================= */
|
|
'active',
|
|
COALESCE(ps.active, p.active),
|
|
'visibility',
|
|
COALESCE(ps.visibility, p.visibility),
|
|
'manufacturer',
|
|
m.name,
|
|
'category',
|
|
cl.name,
|
|
/* ================= IMAGE ================= */
|
|
'cover_image',
|
|
JSON_OBJECT(
|
|
'id',
|
|
i.id_image,
|
|
'legend',
|
|
il.legend
|
|
),
|
|
/* ================= FEATURES ================= */
|
|
'features',
|
|
(
|
|
SELECT
|
|
JSON_ARRAYAGG(
|
|
JSON_OBJECT(
|
|
'name',
|
|
fl.name,
|
|
'value',
|
|
fvl.value
|
|
)
|
|
)
|
|
FROM
|
|
ps_feature_product fp
|
|
JOIN ps_feature_lang fl ON fl.id_feature = fp.id_feature
|
|
AND fl.id_lang = p_id_lang
|
|
JOIN ps_feature_value_lang fvl ON fvl.id_feature_value = fp.id_feature_value
|
|
AND fvl.id_lang = p_id_lang
|
|
WHERE
|
|
fp.id_product = p.id_product
|
|
),
|
|
/* ================= COMBINATIONS ================= */
|
|
'combinations',
|
|
(
|
|
SELECT
|
|
JSON_ARRAYAGG(
|
|
JSON_OBJECT(
|
|
'id_product_attribute',
|
|
pa.id_product_attribute,
|
|
'reference',
|
|
pa.reference,
|
|
'price',
|
|
JSON_OBJECT(
|
|
'impact',
|
|
COALESCE(pas.price, pa.price),
|
|
'final_tax_excl',
|
|
(
|
|
COALESCE(ps.price, p.price) + COALESCE(pas.price, pa.price)
|
|
),
|
|
'final_tax_incl',
|
|
(
|
|
(
|
|
COALESCE(ps.price, p.price) + COALESCE(pas.price, pa.price)
|
|
) * (1 + v_tax_rate / 100)
|
|
)
|
|
),
|
|
'stock',
|
|
IFNULL(sa.quantity, 0),
|
|
'default_on',
|
|
pas.default_on,
|
|
/* ATTRIBUTES JSON */
|
|
'attributes',
|
|
(
|
|
SELECT
|
|
JSON_ARRAYAGG(
|
|
JSON_OBJECT(
|
|
'group',
|
|
agl.name,
|
|
'attribute',
|
|
al.name
|
|
)
|
|
)
|
|
FROM
|
|
ps_product_attribute_combination pac
|
|
JOIN ps_attribute a ON a.id_attribute = pac.id_attribute
|
|
JOIN ps_attribute_lang al ON al.id_attribute = a.id_attribute
|
|
AND al.id_lang = p_id_lang
|
|
JOIN ps_attribute_group_lang agl ON agl.id_attribute_group = a.id_attribute_group
|
|
AND agl.id_lang = p_id_lang
|
|
WHERE
|
|
pac.id_product_attribute = pa.id_product_attribute
|
|
),
|
|
/* IMAGES */
|
|
'images',
|
|
(
|
|
SELECT
|
|
JSON_ARRAYAGG(img.id_image)
|
|
FROM
|
|
ps_product_attribute_image pai
|
|
JOIN ps_image img ON img.id_image = pai.id_image
|
|
WHERE
|
|
pai.id_product_attribute = pa.id_product_attribute
|
|
)
|
|
)
|
|
)
|
|
FROM
|
|
ps_product_attribute pa
|
|
JOIN ps_product_attribute_shop pas ON pas.id_product_attribute = pa.id_product_attribute
|
|
AND pas.id_shop = p_id_shop
|
|
LEFT JOIN ps_stock_available sa ON sa.id_product = pa.id_product
|
|
AND sa.id_product_attribute = pa.id_product_attribute
|
|
AND sa.id_shop = p_id_shop
|
|
WHERE
|
|
pa.id_product = p.id_product
|
|
)
|
|
) AS product_json
|
|
FROM
|
|
ps_product p
|
|
LEFT JOIN ps_product_shop ps ON ps.id_product = p.id_product
|
|
AND ps.id_shop = p_id_shop
|
|
LEFT JOIN ps_product_lang pl ON pl.id_product = p.id_product
|
|
AND pl.id_lang = p_id_lang
|
|
AND pl.id_shop = p_id_shop
|
|
LEFT JOIN ps_category_lang cl ON cl.id_category = COALESCE(ps.id_category_default, p.id_category_default)
|
|
AND cl.id_lang = p_id_lang
|
|
AND cl.id_shop = p_id_shop
|
|
LEFT JOIN ps_manufacturer m ON m.id_manufacturer = p.id_manufacturer
|
|
LEFT JOIN ps_image i ON i.id_product = p.id_product
|
|
AND i.cover = 1
|
|
LEFT JOIN ps_image_lang il ON il.id_image = i.id_image
|
|
AND il.id_lang = p_id_lang
|
|
/* SPECIFIC PRICE */
|
|
LEFT JOIN (
|
|
SELECT bsp.*
|
|
FROM b2b_specific_price bsp
|
|
|
|
/* RELATIONS */
|
|
LEFT JOIN b2b_specific_price_product bsp_p
|
|
ON bsp_p.b2b_specific_price_id = bsp.id
|
|
|
|
LEFT JOIN b2b_specific_price_category bsp_c
|
|
ON bsp_c.b2b_specific_price_id = bsp.id
|
|
|
|
WHERE bsp.is_active = TRUE
|
|
|
|
/* SCOPE MATCH */
|
|
AND (
|
|
/* PRODUCT */
|
|
(bsp.scope = 'product' AND bsp_p.id_product = p_id_product)
|
|
|
|
/* CATEGORY */
|
|
OR (
|
|
bsp.scope = 'category'
|
|
AND bsp_c.id_category IN (
|
|
SELECT cp.id_category
|
|
FROM ps_category_product cp
|
|
WHERE cp.id_product = p_id_product
|
|
)
|
|
)
|
|
|
|
/* SHOP (GLOBAL) */
|
|
OR (bsp.scope = 'shop')
|
|
)
|
|
|
|
/* CUSTOMER MATCH */
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
AND c.b2b_id_customer = p_id_customer
|
|
)
|
|
)
|
|
|
|
/* COUNTRY MATCH */
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_country ctry
|
|
WHERE ctry.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_country ctry
|
|
WHERE ctry.b2b_specific_price_id = bsp.id
|
|
AND ctry.b2b_id_country = b2b_id_country
|
|
)
|
|
)
|
|
|
|
/* QUANTITY */
|
|
AND bsp.from_quantity <= p_quantity
|
|
|
|
/* DATE */
|
|
AND (
|
|
bsp.has_expiration_date = FALSE OR (
|
|
(bsp.valid_from IS NULL OR bsp.valid_from <= NOW())
|
|
AND (bsp.valid_till IS NULL OR bsp.valid_till >= NOW())
|
|
)
|
|
)
|
|
|
|
ORDER BY
|
|
/* 🔥 SCOPE PRIORITY */
|
|
bsp.scope = 'product' DESC,
|
|
bsp.scope = 'category' DESC,
|
|
bsp.scope = 'shop' DESC,
|
|
|
|
/* 🔥 CUSTOMER PRIORITY */
|
|
(
|
|
EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
AND c.b2b_id_customer = p_id_customer
|
|
)
|
|
) DESC,
|
|
|
|
/* 🔥 COUNTRY PRIORITY */
|
|
(
|
|
EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_country ctry
|
|
WHERE ctry.b2b_specific_price_id = bsp.id
|
|
AND ctry.b2b_id_country = b2b_id_country
|
|
)
|
|
) DESC,
|
|
|
|
/* GLOBAL fallback (no restrictions) naturally goes last */
|
|
|
|
bsp.from_quantity DESC,
|
|
bsp.id DESC
|
|
|
|
LIMIT 1
|
|
) bsp ON 1=1
|
|
LEFT JOIN b2b_currency_rates br_bsp
|
|
ON br_bsp.b2b_id_currency = bsp.b2b_id_currency
|
|
AND br_bsp.created_at = (
|
|
SELECT MAX(created_at)
|
|
FROM b2b_currency_rates
|
|
WHERE b2b_id_currency = bsp.b2b_id_currency
|
|
)
|
|
LEFT JOIN b2b_countries ON b2b_countries.id = b2b_id_country
|
|
LEFT JOIN b2b_currencies ON b2b_currencies.id = p_id_currency
|
|
LEFT JOIN b2b_currency_rates r ON r.b2b_id_currency = b2b_currencies.id
|
|
AND r.created_at = (
|
|
SELECT
|
|
MAX(created_at)
|
|
FROM
|
|
b2b_currency_rates
|
|
WHERE
|
|
b2b_id_currency = b2b_currencies.id
|
|
)
|
|
WHERE
|
|
p.id_product = p_id_product
|
|
LIMIT
|
|
1;
|
|
END //
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
-----------------------------------
|
|
|
|
|
|
DELIMITER //
|
|
|
|
DROP PROCEDURE IF EXISTS get_product_attributes_with_price //
|
|
CREATE PROCEDURE get_product_attributes_with_price(
|
|
IN p_id_lang INT UNSIGNED,
|
|
IN p_id_product INT UNSIGNED,
|
|
IN p_id_shop INT UNSIGNED,
|
|
IN p_id_customer INT UNSIGNED,
|
|
IN p_id_country INT UNSIGNED,
|
|
IN p_quantity INT UNSIGNED
|
|
)
|
|
BEGIN
|
|
|
|
DECLARE v_tax_rate DECIMAL(10,4) DEFAULT 0;
|
|
DECLARE v_currency_rate DECIMAL(10,4) DEFAULT 1;
|
|
|
|
-- =========================================================
|
|
-- TAX
|
|
-- =========================================================
|
|
SELECT COALESCE(t.rate, 0)
|
|
INTO v_tax_rate
|
|
FROM ps_tax_rule tr
|
|
INNER JOIN ps_tax t ON t.id_tax = tr.id_tax
|
|
LEFT JOIN b2b_countries c ON c.id = p_id_country
|
|
WHERE tr.id_tax_rules_group = (
|
|
SELECT ps.id_tax_rules_group
|
|
FROM ps_product_shop ps
|
|
WHERE ps.id_product = p_id_product
|
|
AND ps.id_shop = p_id_shop
|
|
LIMIT 1
|
|
)
|
|
AND tr.id_country = c.ps_id_country
|
|
LIMIT 1;
|
|
|
|
-- =========================================================
|
|
-- CURRENCY
|
|
-- =========================================================
|
|
SELECT COALESCE(r.conversion_rate, 1)
|
|
INTO v_currency_rate
|
|
FROM b2b_countries c
|
|
LEFT JOIN b2b_currencies cur ON cur.id = c.b2b_id_currency
|
|
LEFT JOIN b2b_currency_rates r ON r.b2b_id_currency = cur.id
|
|
WHERE c.id = p_id_country
|
|
ORDER BY r.created_at DESC
|
|
LIMIT 1;
|
|
|
|
-- =========================================================
|
|
-- MAIN RESULT
|
|
-- =========================================================
|
|
SELECT
|
|
pa.id_product_attribute,
|
|
pa.reference,
|
|
|
|
-- =====================================================
|
|
-- BASE PRICE (product + attribute impact)
|
|
-- =====================================================
|
|
(
|
|
(COALESCE(ps.price, p.price) + COALESCE(pas.price, 0))
|
|
* v_currency_rate
|
|
) AS base_price,
|
|
|
|
-- =====================================================
|
|
-- FINAL PRICE EXCL (FULL RULE ENGINE)
|
|
-- =====================================================
|
|
COALESCE(sp.price_tax_excl,
|
|
(COALESCE(ps.price, p.price) + COALESCE(pas.price, 0)) * v_currency_rate
|
|
) AS price_tax_excl,
|
|
|
|
-- =====================================================
|
|
-- FINAL PRICE INCL
|
|
-- =====================================================
|
|
(
|
|
COALESCE(sp.price_tax_excl,
|
|
(COALESCE(ps.price, p.price) + COALESCE(pas.price, 0)) * v_currency_rate
|
|
)
|
|
) * (1 + v_tax_rate / 100) AS price_tax_incl,
|
|
|
|
-- =====================================================
|
|
-- STOCK
|
|
-- =====================================================
|
|
IFNULL(sa.quantity, 0) AS quantity,
|
|
|
|
-- =====================================================
|
|
-- ATTRIBUTES
|
|
-- =====================================================
|
|
(
|
|
SELECT JSON_ARRAYAGG(
|
|
JSON_OBJECT(
|
|
'group', agl.name,
|
|
'attribute', al.name
|
|
)
|
|
)
|
|
FROM ps_product_attribute_combination pac
|
|
JOIN ps_attribute a ON a.id_attribute = pac.id_attribute
|
|
JOIN ps_attribute_lang al
|
|
ON al.id_attribute = a.id_attribute AND al.id_lang = p_id_lang
|
|
JOIN ps_attribute_group_lang agl
|
|
ON agl.id_attribute_group = a.id_attribute_group AND agl.id_lang = p_id_lang
|
|
WHERE pac.id_product_attribute = pa.id_product_attribute
|
|
) AS attributes
|
|
|
|
FROM ps_product_attribute pa
|
|
|
|
JOIN ps_product_attribute_shop pas
|
|
ON pas.id_product_attribute = pa.id_product_attribute
|
|
AND pas.id_shop = p_id_shop
|
|
|
|
JOIN ps_product p
|
|
ON p.id_product = pa.id_product
|
|
|
|
LEFT JOIN ps_product_shop ps
|
|
ON ps.id_product = p.id_product
|
|
AND ps.id_shop = p_id_shop
|
|
|
|
LEFT JOIN ps_stock_available sa
|
|
ON sa.id_product = pa.id_product
|
|
AND sa.id_product_attribute = pa.id_product_attribute
|
|
AND sa.id_shop = p_id_shop
|
|
|
|
-- =====================================================
|
|
-- FULL SPECIFIC PRICE ENGINE (IDENTICAL RULES TO MAIN)
|
|
-- =====================================================
|
|
LEFT JOIN (
|
|
|
|
SELECT *
|
|
FROM (
|
|
|
|
SELECT
|
|
pa.id_product_attribute,
|
|
|
|
-- FINAL PRICE
|
|
CASE
|
|
WHEN bsp.reduction_type = 'amount' THEN
|
|
CASE
|
|
WHEN bsp.b2b_id_currency IS NULL THEN bsp.price
|
|
ELSE bsp.price
|
|
END
|
|
|
|
WHEN bsp.reduction_type = 'percentage' THEN
|
|
(
|
|
(COALESCE(ps.price, p.price) + COALESCE(pas.price, 0))
|
|
* v_currency_rate
|
|
) * (1 - bsp.percentage_reduction / 100)
|
|
|
|
ELSE
|
|
(
|
|
(COALESCE(ps.price, p.price) + COALESCE(pas.price, 0))
|
|
* v_currency_rate
|
|
)
|
|
END AS price_tax_excl,
|
|
|
|
ROW_NUMBER() OVER (
|
|
PARTITION BY pa.id_product_attribute
|
|
ORDER BY
|
|
bsp.scope = 'product' DESC,
|
|
bsp.scope = 'category' DESC,
|
|
bsp.scope = 'shop' DESC,
|
|
bsp.from_quantity DESC,
|
|
bsp.id DESC
|
|
) AS rn
|
|
|
|
FROM ps_product_attribute pa
|
|
|
|
JOIN ps_product p ON p.id_product = pa.id_product
|
|
|
|
LEFT JOIN ps_product_shop ps
|
|
ON ps.id_product = p.id_product
|
|
AND ps.id_shop = p_id_shop
|
|
|
|
LEFT JOIN ps_product_attribute_shop pas
|
|
ON pas.id_product_attribute = pa.id_product_attribute
|
|
|
|
JOIN b2b_specific_price bsp ON bsp.is_active = TRUE
|
|
|
|
LEFT JOIN b2b_specific_price_product bsp_p
|
|
ON bsp_p.b2b_specific_price_id = bsp.id
|
|
|
|
LEFT JOIN b2b_specific_price_category bsp_c
|
|
ON bsp_c.b2b_specific_price_id = bsp.id
|
|
|
|
WHERE pa.id_product = p_id_product
|
|
|
|
-- =========================
|
|
-- SCOPE
|
|
-- =========================
|
|
AND (
|
|
(bsp.scope = 'product' AND bsp_p.id_product = p_id_product)
|
|
|
|
OR (
|
|
bsp.scope = 'category'
|
|
AND bsp_c.id_category IN (
|
|
SELECT id_category
|
|
FROM ps_category_product
|
|
WHERE id_product = p_id_product
|
|
)
|
|
)
|
|
|
|
OR (bsp.scope = 'shop')
|
|
)
|
|
|
|
-- =========================
|
|
-- CUSTOMER
|
|
-- =========================
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
AND c.b2b_id_customer = p_id_customer
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- COUNTRY
|
|
-- =========================
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_country c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_country c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
AND c.b2b_id_country = p_id_country
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- ATTRIBUTE
|
|
-- =========================
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_product_attribute a
|
|
WHERE a.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_product_attribute a
|
|
WHERE a.b2b_specific_price_id = bsp.id
|
|
AND a.id_product_attribute = pa.id_product_attribute
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- QUANTITY
|
|
-- =========================
|
|
AND bsp.from_quantity <= p_quantity
|
|
|
|
-- =========================
|
|
-- DATE
|
|
-- =========================
|
|
AND (
|
|
bsp.has_expiration_date = FALSE
|
|
OR (
|
|
(bsp.valid_from IS NULL OR bsp.valid_from <= NOW())
|
|
AND (bsp.valid_till IS NULL OR bsp.valid_till >= NOW())
|
|
)
|
|
)
|
|
|
|
) ranked
|
|
|
|
WHERE ranked.rn = 1
|
|
|
|
) sp ON sp.id_product_attribute = pa.id_product_attribute
|
|
|
|
WHERE pa.id_product = p_id_product;
|
|
|
|
END //
|
|
|
|
DELIMITER ;
|
|
|
|
--------------------------------
|
|
|
|
|
|
DELIMITER //
|
|
|
|
DROP PROCEDURE IF EXISTS get_product_price //
|
|
CREATE PROCEDURE get_product_price(
|
|
IN p_id_product INT UNSIGNED,
|
|
IN p_id_shop INT UNSIGNED,
|
|
IN p_id_customer INT UNSIGNED,
|
|
IN p_id_country INT UNSIGNED,
|
|
IN p_quantity INT UNSIGNED
|
|
)
|
|
BEGIN
|
|
|
|
DECLARE v_tax_rate DECIMAL(10,4) DEFAULT 0;
|
|
DECLARE v_currency_rate DECIMAL(10,4) DEFAULT 1;
|
|
|
|
DECLARE v_base_price DECIMAL(20,6) DEFAULT 0;
|
|
DECLARE v_final_excl DECIMAL(20,6) DEFAULT 0;
|
|
DECLARE v_final_incl DECIMAL(20,6) DEFAULT 0;
|
|
|
|
DECLARE v_has_specific INT DEFAULT 0;
|
|
DECLARE v_reduction_type VARCHAR(20);
|
|
DECLARE v_percentage DECIMAL(10,4);
|
|
DECLARE v_fixed_price DECIMAL(20,6);
|
|
DECLARE v_specific_currency_id INT;
|
|
|
|
-- =========================
|
|
-- 1. TAX RATE
|
|
-- =========================
|
|
SELECT COALESCE(t.rate, 0)
|
|
INTO v_tax_rate
|
|
FROM ps_tax_rule tr
|
|
INNER JOIN ps_tax t ON t.id_tax = tr.id_tax
|
|
LEFT JOIN b2b_countries c ON c.id = p_id_country
|
|
WHERE tr.id_tax_rules_group = (
|
|
SELECT ps.id_tax_rules_group
|
|
FROM ps_product_shop ps
|
|
WHERE ps.id_product = p_id_product
|
|
AND ps.id_shop = p_id_shop
|
|
LIMIT 1
|
|
)
|
|
AND tr.id_country = c.ps_id_country
|
|
ORDER BY tr.id_state DESC, tr.zipcode_from DESC, tr.id_tax_rule DESC
|
|
LIMIT 1;
|
|
|
|
-- =========================
|
|
-- 2. CURRENCY RATE
|
|
-- =========================
|
|
SELECT COALESCE(r.conversion_rate, 1)
|
|
INTO v_currency_rate
|
|
FROM b2b_countries c
|
|
LEFT JOIN b2b_currencies cur ON cur.id = c.b2b_id_currency
|
|
LEFT JOIN b2b_currency_rates r ON r.b2b_id_currency = cur.id
|
|
WHERE c.id = p_id_country
|
|
ORDER BY r.created_at DESC
|
|
LIMIT 1;
|
|
|
|
-- =========================
|
|
-- 3. BASE PRICE
|
|
-- =========================
|
|
SELECT COALESCE(ps.price, p.price) * v_currency_rate
|
|
INTO v_base_price
|
|
FROM ps_product p
|
|
LEFT JOIN ps_product_shop ps
|
|
ON ps.id_product = p.id_product
|
|
AND ps.id_shop = p_id_shop
|
|
WHERE p.id_product = p_id_product
|
|
LIMIT 1;
|
|
|
|
-- =========================
|
|
-- 4. SPECIFIC PRICE (correct wildcard-aware match)
|
|
-- =========================
|
|
SELECT
|
|
1,
|
|
bsp.reduction_type,
|
|
bsp.percentage_reduction,
|
|
bsp.price,
|
|
bsp.b2b_id_currency
|
|
INTO
|
|
v_has_specific,
|
|
v_reduction_type,
|
|
v_percentage,
|
|
v_fixed_price,
|
|
v_specific_currency_id
|
|
FROM b2b_specific_price bsp
|
|
|
|
LEFT JOIN b2b_specific_price_product bsp_p
|
|
ON bsp_p.b2b_specific_price_id = bsp.id
|
|
|
|
LEFT JOIN b2b_specific_price_category bsp_c
|
|
ON bsp_c.b2b_specific_price_id = bsp.id
|
|
|
|
LEFT JOIN b2b_specific_price_customer bsp_u
|
|
ON bsp_u.b2b_specific_price_id = bsp.id
|
|
|
|
LEFT JOIN b2b_specific_price_country bsp_ct
|
|
ON bsp_ct.b2b_specific_price_id = bsp.id
|
|
|
|
LEFT JOIN b2b_specific_price_product_attribute bsp_pa
|
|
ON bsp_pa.b2b_specific_price_id = bsp.id
|
|
|
|
WHERE bsp.is_active = TRUE
|
|
|
|
-- =========================
|
|
-- PRODUCT / CATEGORY / SHOP SCOPE
|
|
-- =========================
|
|
AND (
|
|
(bsp.scope = 'product' AND bsp_p.id_product = p_id_product)
|
|
|
|
OR (
|
|
bsp.scope = 'category'
|
|
AND bsp_c.id_category IN (
|
|
SELECT id_category
|
|
FROM ps_category_product
|
|
WHERE id_product = p_id_product
|
|
)
|
|
)
|
|
|
|
OR (bsp.scope = 'shop')
|
|
)
|
|
|
|
-- =========================
|
|
-- CUSTOMER RULE (wildcard-aware)
|
|
-- =========================
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1
|
|
FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1
|
|
FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
AND c.b2b_id_customer = p_id_customer
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- COUNTRY RULE (wildcard-aware)
|
|
-- =========================
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1
|
|
FROM b2b_specific_price_country c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1
|
|
FROM b2b_specific_price_country c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
AND c.b2b_id_country = p_id_country
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- PRODUCT ATTRIBUTE RULE (wildcard-aware)
|
|
-- =========================
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1
|
|
FROM b2b_specific_price_product_attribute a
|
|
WHERE a.b2b_specific_price_id = bsp.id
|
|
)
|
|
OR EXISTS (
|
|
SELECT 1
|
|
FROM b2b_specific_price_product_attribute a
|
|
WHERE a.b2b_specific_price_id = bsp.id
|
|
AND a.id_product_attribute = 0
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- QUANTITY RULE
|
|
-- =========================
|
|
AND bsp.from_quantity <= p_quantity
|
|
|
|
-- =========================
|
|
-- DATE RULE (FIXED precedence bug)
|
|
-- =========================
|
|
AND (
|
|
bsp.has_expiration_date = FALSE
|
|
OR (
|
|
(bsp.valid_from IS NULL OR bsp.valid_from <= NOW())
|
|
AND (bsp.valid_till IS NULL OR bsp.valid_till >= NOW())
|
|
)
|
|
)
|
|
|
|
-- =========================
|
|
-- PRIORITY ORDERING (IMPROVED)
|
|
-- =========================
|
|
ORDER BY
|
|
-- strongest match wins
|
|
(EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_customer c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)) DESC,
|
|
|
|
(EXISTS (
|
|
SELECT 1 FROM b2b_specific_price_country c
|
|
WHERE c.b2b_specific_price_id = bsp.id
|
|
)) DESC,
|
|
|
|
bsp.scope = 'product' DESC,
|
|
bsp.scope = 'category' DESC,
|
|
bsp.scope = 'shop' DESC,
|
|
|
|
bsp.from_quantity DESC,
|
|
bsp.id DESC
|
|
|
|
LIMIT 1;
|
|
|
|
-- =========================
|
|
-- 5. APPLY SPECIFIC PRICE
|
|
-- =========================
|
|
SET v_final_excl = v_base_price;
|
|
|
|
IF v_has_specific = 1 THEN
|
|
|
|
IF v_reduction_type = 'amount' THEN
|
|
|
|
IF v_specific_currency_id IS NULL THEN
|
|
SET v_final_excl = v_fixed_price;
|
|
ELSE
|
|
SET v_final_excl = v_fixed_price; -- assume already converted or pre-handled
|
|
END IF;
|
|
|
|
ELSEIF v_reduction_type = 'percentage' THEN
|
|
SET v_final_excl = v_base_price * (1 - v_percentage / 100);
|
|
END IF;
|
|
|
|
END IF;
|
|
|
|
-- =========================
|
|
-- 6. TAX
|
|
-- =========================
|
|
SET v_final_incl = v_final_excl * (1 + v_tax_rate / 100);
|
|
|
|
-- =========================
|
|
-- 7. RETURN RESULT
|
|
-- =========================
|
|
SELECT
|
|
p_id_product AS id_product,
|
|
v_base_price AS price_base,
|
|
v_final_excl AS price_tax_excl,
|
|
v_final_incl AS price_tax_incl,
|
|
v_tax_rate AS tax_rate;
|
|
|
|
END //
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
-- +goose Down
|