|
|
|
|
@@ -1,386 +1,410 @@
|
|
|
|
|
-- +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
|
|
|
|
|
DELIMITER //
|
|
|
|
|
|
|
|
|
|
DROP FUNCTION IF EXISTS fn_product_price //
|
|
|
|
|
CREATE FUNCTION fn_product_price(
|
|
|
|
|
p_id_product INT UNSIGNED,
|
|
|
|
|
p_id_shop INT UNSIGNED,
|
|
|
|
|
p_id_customer INT UNSIGNED,
|
|
|
|
|
p_id_country INT UNSIGNED,
|
|
|
|
|
p_quantity INT UNSIGNED,
|
|
|
|
|
p_id_product_attribute INT UNSIGNED
|
|
|
|
|
)
|
|
|
|
|
RETURNS JSON
|
|
|
|
|
DETERMINISTIC
|
|
|
|
|
READS SQL DATA
|
|
|
|
|
BEGIN
|
|
|
|
|
|
|
|
|
|
DECLARE v_tax_rate DECIMAL(10,4) DEFAULT 0;
|
|
|
|
|
|
|
|
|
|
DECLARE v_base_raw DECIMAL(20,6);
|
|
|
|
|
DECLARE v_base DECIMAL(20,6);
|
|
|
|
|
DECLARE v_excl DECIMAL(20,6);
|
|
|
|
|
DECLARE v_incl DECIMAL(20,6);
|
|
|
|
|
|
|
|
|
|
DECLARE v_reduction_type VARCHAR(20);
|
|
|
|
|
DECLARE v_percentage DECIMAL(10,4);
|
|
|
|
|
DECLARE v_fixed_price DECIMAL(20,6);
|
|
|
|
|
DECLARE v_specific_currency_id BIGINT;
|
|
|
|
|
|
|
|
|
|
DECLARE v_has_specific INT DEFAULT 0;
|
|
|
|
|
|
|
|
|
|
-- currency
|
|
|
|
|
DECLARE v_target_currency BIGINT;
|
|
|
|
|
DECLARE v_target_rate DECIMAL(13,6) DEFAULT 1;
|
|
|
|
|
DECLARE v_specific_rate DECIMAL(13,6) DEFAULT 1;
|
|
|
|
|
|
|
|
|
|
SET p_id_product_attribute = NULLIF(p_id_product_attribute, 0);
|
|
|
|
|
|
|
|
|
|
-- ================= TAX =================
|
|
|
|
|
SELECT COALESCE(t.rate, 0)
|
|
|
|
|
INTO v_tax_rate
|
|
|
|
|
FROM ps_tax_rule tr
|
|
|
|
|
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
|
|
|
|
|
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),
|
|
|
|
|
AND tr.id_country = c.ps_id_country
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
|
|
|
|
|
'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
|
|
|
|
|
)
|
|
|
|
|
-- ================= TARGET CURRENCY =================
|
|
|
|
|
SELECT c.b2b_id_currency
|
|
|
|
|
INTO v_target_currency
|
|
|
|
|
FROM b2b_countries c
|
|
|
|
|
WHERE c.id = p_id_country
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
|
|
|
|
|
/* PERCENTAGE */
|
|
|
|
|
WHEN bsp.reduction_type = 'percentage' THEN
|
|
|
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
|
|
|
* (1 - bsp.percentage_reduction / 100)
|
|
|
|
|
-- latest target rate
|
|
|
|
|
SELECT r.conversion_rate
|
|
|
|
|
INTO v_target_rate
|
|
|
|
|
FROM b2b_currency_rates r
|
|
|
|
|
WHERE r.b2b_id_currency = v_target_currency
|
|
|
|
|
ORDER BY r.created_at DESC
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
|
|
|
|
|
ELSE
|
|
|
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
|
|
|
END
|
|
|
|
|
-- ================= BASE PRICE (RAW) =================
|
|
|
|
|
SELECT
|
|
|
|
|
COALESCE(ps.price, p.price) + COALESCE(pas.price, 0)
|
|
|
|
|
INTO v_base_raw
|
|
|
|
|
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_attribute_shop pas
|
|
|
|
|
ON pas.id_product_attribute = p_id_product_attribute
|
|
|
|
|
AND pas.id_shop = p_id_shop
|
|
|
|
|
WHERE p.id_product = p_id_product;
|
|
|
|
|
|
|
|
|
|
ELSE
|
|
|
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
|
|
|
END
|
|
|
|
|
),
|
|
|
|
|
-- convert base to target currency
|
|
|
|
|
SET v_base = v_base_raw * v_target_rate;
|
|
|
|
|
|
|
|
|
|
'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
|
|
|
|
|
)
|
|
|
|
|
-- ================= RULE SELECTION =================
|
|
|
|
|
SELECT
|
|
|
|
|
1,
|
|
|
|
|
bsp.reduction_type,
|
|
|
|
|
bsp.percentage_reduction,
|
|
|
|
|
bsp.price,
|
|
|
|
|
bsp.b2b_id_currency
|
|
|
|
|
|
|
|
|
|
WHEN bsp.reduction_type = 'percentage' THEN
|
|
|
|
|
COALESCE(ps.price * r.conversion_rate, p.price * r.conversion_rate)
|
|
|
|
|
* (1 - bsp.percentage_reduction / 100)
|
|
|
|
|
INTO
|
|
|
|
|
v_has_specific,
|
|
|
|
|
v_reduction_type,
|
|
|
|
|
v_percentage,
|
|
|
|
|
v_fixed_price,
|
|
|
|
|
v_specific_currency_id
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
/* ================= FAVORITE ================= */
|
|
|
|
|
'is_favorite',
|
|
|
|
|
EXISTS(
|
|
|
|
|
SELECT 1 FROM b2b_favorites f
|
|
|
|
|
WHERE f.user_id = p_id_customer AND f.product_id = p_id_product
|
|
|
|
|
),
|
|
|
|
|
/* ================= 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 */
|
|
|
|
|
WHERE bsp.is_active = 1
|
|
|
|
|
AND bsp.from_quantity <= p_quantity
|
|
|
|
|
|
|
|
|
|
/* DATE */
|
|
|
|
|
-- intersection rules (unchanged)
|
|
|
|
|
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())
|
|
|
|
|
NOT EXISTS (SELECT 1 FROM b2b_specific_price_product x WHERE x.b2b_specific_price_id = bsp.id)
|
|
|
|
|
OR EXISTS (SELECT 1 FROM b2b_specific_price_product x WHERE x.b2b_specific_price_id = bsp.id AND x.id_product = p_id_product)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
AND (
|
|
|
|
|
NOT EXISTS (SELECT 1 FROM b2b_specific_price_product_attribute x WHERE x.b2b_specific_price_id = bsp.id)
|
|
|
|
|
OR EXISTS (SELECT 1 FROM b2b_specific_price_product_attribute x WHERE x.b2b_specific_price_id = bsp.id AND x.id_product_attribute = p_id_product_attribute)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
AND (
|
|
|
|
|
NOT EXISTS (SELECT 1 FROM b2b_specific_price_category x WHERE x.b2b_specific_price_id = bsp.id)
|
|
|
|
|
OR EXISTS (
|
|
|
|
|
SELECT 1 FROM b2b_specific_price_category x
|
|
|
|
|
JOIN ps_category_product cp ON cp.id_category = x.id_category
|
|
|
|
|
WHERE x.b2b_specific_price_id = bsp.id AND cp.id_product = p_id_product
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ORDER BY
|
|
|
|
|
/* 🔥 SCOPE PRIORITY */
|
|
|
|
|
bsp.scope = 'product' DESC,
|
|
|
|
|
bsp.scope = 'category' DESC,
|
|
|
|
|
bsp.scope = 'shop' DESC,
|
|
|
|
|
AND (
|
|
|
|
|
NOT EXISTS (SELECT 1 FROM b2b_specific_price_customer x WHERE x.b2b_specific_price_id = bsp.id)
|
|
|
|
|
OR EXISTS (SELECT 1 FROM b2b_specific_price_customer x WHERE x.b2b_specific_price_id = bsp.id AND x.b2b_id_customer = p_id_customer)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/* 🔥 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,
|
|
|
|
|
AND (
|
|
|
|
|
NOT EXISTS (SELECT 1 FROM b2b_specific_price_country x WHERE x.b2b_specific_price_id = bsp.id)
|
|
|
|
|
OR EXISTS (SELECT 1 FROM b2b_specific_price_country x WHERE x.b2b_specific_price_id = bsp.id AND x.b2b_id_country = p_id_country)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/* 🔥 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,
|
|
|
|
|
ORDER BY
|
|
|
|
|
-- customer wins
|
|
|
|
|
(EXISTS (SELECT 1 FROM b2b_specific_price_customer x WHERE x.b2b_specific_price_id = bsp.id AND x.b2b_id_customer = p_id_customer)) DESC,
|
|
|
|
|
|
|
|
|
|
/* GLOBAL fallback (no restrictions) naturally goes last */
|
|
|
|
|
-- attribute
|
|
|
|
|
(EXISTS (SELECT 1 FROM b2b_specific_price_product_attribute x WHERE x.b2b_specific_price_id = bsp.id AND x.id_product_attribute = p_id_product_attribute)) DESC,
|
|
|
|
|
|
|
|
|
|
-- product
|
|
|
|
|
(EXISTS (SELECT 1 FROM b2b_specific_price_product x WHERE x.b2b_specific_price_id = bsp.id AND x.id_product = p_id_product)) DESC,
|
|
|
|
|
|
|
|
|
|
-- category
|
|
|
|
|
(EXISTS (
|
|
|
|
|
SELECT 1 FROM b2b_specific_price_category x
|
|
|
|
|
JOIN ps_category_product cp ON cp.id_category = x.id_category
|
|
|
|
|
WHERE x.b2b_specific_price_id = bsp.id AND cp.id_product = p_id_product
|
|
|
|
|
)) DESC,
|
|
|
|
|
|
|
|
|
|
-- country
|
|
|
|
|
(EXISTS (SELECT 1 FROM b2b_specific_price_country x WHERE x.b2b_specific_price_id = bsp.id AND x.b2b_id_country = p_id_country)) DESC,
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
|
|
|
|
|
-- ================= APPLY =================
|
|
|
|
|
SET v_excl = v_base;
|
|
|
|
|
|
|
|
|
|
IF v_has_specific = 1 THEN
|
|
|
|
|
|
|
|
|
|
IF v_reduction_type = 'amount' THEN
|
|
|
|
|
|
|
|
|
|
-- convert specific price currency if needed
|
|
|
|
|
IF v_specific_currency_id IS NOT NULL AND v_specific_currency_id != v_target_currency THEN
|
|
|
|
|
|
|
|
|
|
SELECT r.conversion_rate
|
|
|
|
|
INTO v_specific_rate
|
|
|
|
|
FROM b2b_currency_rates r
|
|
|
|
|
WHERE r.b2b_id_currency = v_specific_currency_id
|
|
|
|
|
ORDER BY r.created_at DESC
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
|
|
|
|
|
-- normalize → then convert to target
|
|
|
|
|
SET v_excl = (v_fixed_price / v_specific_rate) * v_target_rate;
|
|
|
|
|
|
|
|
|
|
ELSE
|
|
|
|
|
SET v_excl = v_fixed_price;
|
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
|
|
ELSEIF v_reduction_type = 'percentage' THEN
|
|
|
|
|
SET v_excl = v_base * (1 - v_percentage / 100);
|
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
|
|
SET v_incl = v_excl * (1 + v_tax_rate / 100);
|
|
|
|
|
|
|
|
|
|
RETURN JSON_OBJECT(
|
|
|
|
|
'base', v_base,
|
|
|
|
|
'final_tax_excl', v_excl,
|
|
|
|
|
'final_tax_incl', v_incl,
|
|
|
|
|
'tax_rate', v_tax_rate,
|
|
|
|
|
'rate', v_target_rate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
END //
|
|
|
|
|
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
DELIMITER //
|
|
|
|
|
|
|
|
|
|
DROP PROCEDURE IF EXISTS get_product_variants //
|
|
|
|
|
CREATE PROCEDURE get_product_variants(
|
|
|
|
|
IN p_id_product INT,
|
|
|
|
|
IN p_id_shop INT,
|
|
|
|
|
IN p_id_lang INT,
|
|
|
|
|
IN p_id_customer INT,
|
|
|
|
|
IN p_id_country INT,
|
|
|
|
|
IN p_quantity INT
|
|
|
|
|
)
|
|
|
|
|
BEGIN
|
|
|
|
|
|
|
|
|
|
SELECT
|
|
|
|
|
pa.id_product_attribute,
|
|
|
|
|
pa.reference,
|
|
|
|
|
|
|
|
|
|
-- PRICE (computed once per row via correlated subquery)
|
|
|
|
|
CAST(JSON_UNQUOTE(JSON_EXTRACT(
|
|
|
|
|
fn_product_price(
|
|
|
|
|
p_id_product,
|
|
|
|
|
p_id_shop,
|
|
|
|
|
p_id_customer,
|
|
|
|
|
p_id_country,
|
|
|
|
|
p_quantity,
|
|
|
|
|
pa.id_product_attribute
|
|
|
|
|
),
|
|
|
|
|
'$.base'
|
|
|
|
|
)) AS DECIMAL(20,6)) AS base_price,
|
|
|
|
|
|
|
|
|
|
CAST(JSON_UNQUOTE(JSON_EXTRACT(
|
|
|
|
|
fn_product_price(
|
|
|
|
|
p_id_product,
|
|
|
|
|
p_id_shop,
|
|
|
|
|
p_id_customer,
|
|
|
|
|
p_id_country,
|
|
|
|
|
p_quantity,
|
|
|
|
|
pa.id_product_attribute
|
|
|
|
|
),
|
|
|
|
|
'$.final_tax_excl'
|
|
|
|
|
)) AS DECIMAL(20,6)) AS price_tax_excl,
|
|
|
|
|
|
|
|
|
|
CAST(JSON_UNQUOTE(JSON_EXTRACT(
|
|
|
|
|
fn_product_price(
|
|
|
|
|
p_id_product,
|
|
|
|
|
p_id_shop,
|
|
|
|
|
p_id_customer,
|
|
|
|
|
p_id_country,
|
|
|
|
|
p_quantity,
|
|
|
|
|
pa.id_product_attribute
|
|
|
|
|
),
|
|
|
|
|
'$.final_tax_incl'
|
|
|
|
|
)) AS DECIMAL(20,6)) AS price_tax_incl,
|
|
|
|
|
|
|
|
|
|
IFNULL(sa.quantity, 0) AS quantity,
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
END //
|
|
|
|
|
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
DELIMITER //
|
|
|
|
|
|
|
|
|
|
DROP PROCEDURE IF EXISTS get_product_price //
|
|
|
|
|
CREATE PROCEDURE get_product_price(
|
|
|
|
|
IN p_id_product INT,
|
|
|
|
|
IN p_id_shop INT,
|
|
|
|
|
IN p_id_customer INT,
|
|
|
|
|
IN p_id_country INT,
|
|
|
|
|
IN p_quantity INT
|
|
|
|
|
)
|
|
|
|
|
BEGIN
|
|
|
|
|
|
|
|
|
|
SELECT fn_product_price(
|
|
|
|
|
p_id_product,
|
|
|
|
|
p_id_shop,
|
|
|
|
|
p_id_customer,
|
|
|
|
|
p_id_country,
|
|
|
|
|
p_quantity,
|
|
|
|
|
NULL
|
|
|
|
|
) AS price;
|
|
|
|
|
|
|
|
|
|
END //
|
|
|
|
|
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
DELIMITER //
|
|
|
|
|
DROP PROCEDURE IF EXISTS get_product_base //
|
|
|
|
|
CREATE PROCEDURE get_product_base(
|
|
|
|
|
IN p_id_product INT,
|
|
|
|
|
IN p_id_shop INT,
|
|
|
|
|
IN p_id_lang INT
|
|
|
|
|
)
|
|
|
|
|
BEGIN
|
|
|
|
|
SELECT
|
|
|
|
|
p.id_product AS id, -- matches view.Product.ID
|
|
|
|
|
|
|
|
|
|
p.reference,
|
|
|
|
|
p.supplier_reference,
|
|
|
|
|
p.ean13,
|
|
|
|
|
p.upc,
|
|
|
|
|
p.isbn,
|
|
|
|
|
|
|
|
|
|
-- Price related (basic)
|
|
|
|
|
p.price AS base_price,
|
|
|
|
|
p.wholesale_price,
|
|
|
|
|
p.unity,
|
|
|
|
|
p.unit_price_ratio,
|
|
|
|
|
|
|
|
|
|
-- Stock & Availability
|
|
|
|
|
p.quantity,
|
|
|
|
|
p.minimal_quantity,
|
|
|
|
|
p.available_for_order,
|
|
|
|
|
p.available_date,
|
|
|
|
|
p.out_of_stock AS out_of_stock_behavior, -- 0=deny, 1=allow, 2=default
|
|
|
|
|
|
|
|
|
|
-- Flags
|
|
|
|
|
COALESCE(ps.on_sale, 0) AS on_sale,
|
|
|
|
|
COALESCE(ps.show_price, 1) AS show_price,
|
|
|
|
|
p.condition,
|
|
|
|
|
p.is_virtual,
|
|
|
|
|
|
|
|
|
|
-- Physical
|
|
|
|
|
p.weight,
|
|
|
|
|
p.width,
|
|
|
|
|
p.height,
|
|
|
|
|
p.depth,
|
|
|
|
|
p.additional_shipping_cost,
|
|
|
|
|
|
|
|
|
|
-- Delivery
|
|
|
|
|
p.additional_delivery_times AS delivery_days, -- you can adjust if needed
|
|
|
|
|
|
|
|
|
|
-- Status
|
|
|
|
|
COALESCE(ps.active, p.active) AS active,
|
|
|
|
|
COALESCE(ps.visibility, p.visibility) AS visibility,
|
|
|
|
|
p.indexed,
|
|
|
|
|
|
|
|
|
|
-- Other useful
|
|
|
|
|
p.date_add,
|
|
|
|
|
p.date_upd,
|
|
|
|
|
|
|
|
|
|
-- Language data
|
|
|
|
|
pl.name,
|
|
|
|
|
pl.description,
|
|
|
|
|
pl.description_short,
|
|
|
|
|
|
|
|
|
|
-- Relations
|
|
|
|
|
m.name AS manufacturer,
|
|
|
|
|
cl.name AS category
|
|
|
|
|
|
|
|
|
|
-- This doesn't fit to base product, I'll add proper is_favorite to product later
|
|
|
|
|
|
|
|
|
|
-- EXISTS(
|
|
|
|
|
-- SELECT 1 FROM b2b_favorites f
|
|
|
|
|
-- WHERE f.user_id = p_id_customer AND f.product_id = p_id_product
|
|
|
|
|
-- ) AS is_favorite
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
WHERE p.id_product = p_id_product
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
END //
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
-- +goose Down
|
|
|
|
|
|