sql_items = [
datetime_function_sql_item,
is_seo_valid_function_sql_item,
quality_view_sql_item,
article_category_view_sql_item,
base_article_view_sql_item,
article_view_sql_item,
article_b2b_view_sql_item,
master_article_view_sql_item,
reclamation_mat_view_sql_item,
purchase_mat_view_sql_item,
purchase_id_index_sql_item,
purchase_date_of_purchase_index_sql_item,
sale_mat_view_sql_item,
sale_id_index_sql_item,
sale_date_of_sale_index_sql_item,
incentive_sale_mat_view_sql_item,
incentive_item_mat_view_sql_item,
product_view_sql_item,
color_master_view_sql_item,
product_special_offers_view_sql_item,
series_view_sql_item,
stock_products_view_sql_item,
pl_master_product_view_sql_item,
pl_master_product_quality_view_sql_item,
pl_product_view_sql_item,
pl_product_variant_view_sql_item,
pl_stock_products_sold_view_sql_item,
]
#
# module containing `datetime_function_sql_item` and `is_seo_valid_function_sql_item` follows
#
from migrate_sql.config import SQLItem
"""
This third party app stores datetime as DATE column and INT column with seconds passed that day.
This function converts these columns into PostgreSQL datetime type.
"""
datetime_function_sql_item = SQLItem(
name='datetime',
sql='''
CREATE OR REPLACE FUNCTION datetime(day date, seconds numeric) returns timestamp without time zone
LANGUAGE plpgsql AS $$
BEGIN
RETURN day + (floor(seconds / 3600) || ':' || floor(seconds % 3600 / 60) || ':' || seconds % 60)::TIME;
END;
$$;
''',
reverse_sql='DROP FUNCTION IF EXISTS datetime(day date, seconds numeric)',
replace=True,
)
is_seo_valid_function_sql_item = SQLItem(
name='is_seo_valid',
sql='''
CREATE OR REPLACE FUNCTION is_seo_valid(seo text) returns boolean
LANGUAGE plpgsql AS $$
BEGIN
RETURN seo ~ '^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$';
END;
$$;
''',
reverse_sql='DROP FUNCTION IF EXISTS is_seo_valid(seo text)',
replace=True,
)
#
# module containing `article_view_sql_item` follows
#
article_view_sql_item = SQLItem(
name=Article._meta.db_table,
sql='''
CREATE OR REPLACE VIEW {view_name} AS
SELECT
sq.*,
CASE
WHEN sq.buying_price <> 0 THEN round((sq.price / sq.buying_price - 1) * 100, 2)
ELSE 0
END AS margin,
GREATEST(
LEAST(
NULLIF(sq.price_for_installment_calculation, 0), -- zero turns off this price
sq.eshop_price
),
0
) AS installment_price
FROM (
SELECT
DISTINCT ON (a.id)
a.id AS id,
a.name AS "name",
a.code AS code,
COALESCE(a.master, FALSE) AS master,
a.created AS created,
a.fk_id_article_producer AS fk_id_article_producer,
a.fk_id_master_product AS fk_id_master_product,
a.fk_id_color_rgb AS fk_id_color_rgb,
a.fk_id_vat AS fk_id_vat,
a.cf_article_name AS cf_article_name,
a.cf_article_short_name AS cf_article_short_name,
a.cf_seo_name AS cf_seo_name,
a.cf_article_type AS cf_article_type,
q.cf_article_quality AS cf_article_quality,
COALESCE(a.active2, FALSE) AS active2,
COALESCE(a.cf_www_visible, FALSE) AS cf_www_visible,
COALESCE(a.cf_bo_for_sell, FALSE) AS cf_bo_for_sell,
COALESCE(a.cf_buy_up_recommended, FALSE) AS cf_buy_up_recommended,
COALESCE(a.cf_clearance_sale, FALSE) AS cf_clearance_sale,
COALESCE(a.cf_article_short_name, a.name) AS short_name,
COALESCE(a.cf_article_name, a.name) AS long_name,
COALESCE(q.uniform_id, 1) AS quality_uniform_id,
COALESCE(repurchase_prices.repurchase_price, 0) AS repurchase_price,
COALESCE(
CASE
WHEN a.is_spare_part THEN spare_parts_buying_prices.buying_price
WHEN q.is_new THEN buying_prices.buying_price
ELSE repurchase_prices.repurchase_price
END,
0
) AS buying_price,
COALESCE(pd_store.price_with_vat, 0) AS price,
COALESCE(pd_eshop.price_with_vat, pd_store.price_with_vat, 0) AS eshop_price,
COALESCE(pd_common.price_with_vat, 0) AS common_price,
COALESCE(pd_installment.price_with_vat, 0) AS price_for_installment_calculation,
q.is_vat_version AS is_vat_version,
a_vat_0.id AS fk_id_article_zero_vat_version,
CASE WHEN q.is_new THEN COALESCE(a.cf_bo_cheque, 0) ELSE 0 END AS cheque_value,
CASE WHEN q.is_new THEN COALESCE(a.cf_cheque_explicit, FALSE) ELSE FALSE END AS gold_cheque
FROM {base_article_view} a
LEFT JOIN article_variant av ON av.fk_id_article = a.id
LEFT JOIN {quality_view} q ON q.cf_article_quality = COALESCE(a.cf_article_quality, '{new_quality_code}')
LEFT JOIN
(
SELECT
DISTINCT ON (c.fk_id_article_variant)
c.fk_id_article_variant AS fk_id_article_variant,
round(bp.price::NUMERIC, 2) AS repurchase_price
FROM price bp
JOIN conditions c ON bp.fk_id_conditions = c.id
JOIN chain ch ON c.fk_id_chain = ch.id
WHERE ch.code='some-id' AND bp.valid_from <= now()
ORDER BY c.fk_id_article_variant, bp.valid_from DESC
) AS repurchase_prices ON repurchase_prices.fk_id_article_variant = av.id
LEFT JOIN
(
SELECT
DISTINCT ON (asi.fk_id_article_variant)
asi.fk_id_article_variant AS fk_id_article_variant,
ceil(asi.last_base_buying_price::NUMERIC * 1.21) AS buying_price
FROM article_store_info asi
JOIN store s on asi.fk_id_store = s.id
WHERE s.code in ('some-id', 'some-id')
ORDER BY asi.fk_id_article_variant, asi.date2 DESC, s.code
) AS buying_prices ON buying_prices.fk_id_article_variant = av.id
LEFT JOIN
(
SELECT
DISTINCT ON (asi.fk_id_article_variant)
asi.fk_id_article_variant AS fk_id_article_variant,
ceil(asi.last_base_buying_price::NUMERIC * 1.21) AS buying_price
FROM article_store_info asi
JOIN store s on asi.fk_id_store = s.id
WHERE s.code = 'some-id'
ORDER BY asi.fk_id_article_variant, asi.date2 DESC
) AS spare_parts_buying_prices ON spare_parts_buying_prices.fk_id_article_variant = av.id
LEFT JOIN price pd_eshop ON
pd_eshop.fk_id_article_variant = av.id AND
pd_eshop.fk_id_chain = 'some-id' AND
pd_eshop.fk_id_price_zone = 'some-id' AND
pd_eshop.valid_from < extract(EPOCH FROM now()) * 1000 AND
pd_eshop.valid_to > extract(EPOCH FROM now()) * 1000
LEFT JOIN price pd_store ON
pd_store.fk_id_article_variant = av.id AND
pd_store.fk_id_chain = 'some-id' AND
pd_store.fk_id_price_zone = 'some-id' AND
pd_store.valid_from < extract(EPOCH FROM now()) * 1000 AND
pd_store.valid_to > extract(EPOCH FROM now()) * 1000
LEFT JOIN price pd_common ON
pd_common.fk_id_article_variant = av.id AND
pd_common.fk_id_chain = 'some-id' AND
pd_common.fk_id_price_zone = 'some-id' AND
pd_common.valid_from < extract(EPOCH FROM now()) * 1000 AND
pd_common.valid_to > extract(EPOCH FROM now()) * 1000
LEFT JOIN price pd_installment ON -- used for Cetelem payments
pd_installment.fk_id_article_variant = av.id AND
pd_installment.fk_id_chain = 'some-id' AND
pd_installment.fk_id_price_zone = 'some-id' AND
pd_installment.valid_from < extract(EPOCH FROM now()) * 1000 AND
pd_installment.valid_to > extract(EPOCH FROM now()) * 1000
LEFT JOIN {quality_view} q_vat_0
ON q_vat_0.uniform_id = q.uniform_id AND NOT q_vat_0.is_vat_version AND q.is_vat_version
LEFT JOIN article a_vat_0 -- #26502
ON a_vat_0.id <> a.id
AND a_vat_0.fk_id_vat = 'some-id' -- zero VAT
AND a.fk_id_vat = 'some-id' -- 21 VAT
AND a.fk_id_master_product = a_vat_0.fk_id_master_product
AND a.fk_id_color_rgb = a_vat_0.fk_id_color_rgb
AND q_vat_0.cf_article_quality = COALESCE(a_vat_0.cf_article_quality, '{new_quality_code}')
WHERE
a.fk_id_vat IS NOT NULL
AND a.fk_id_article_producer IS NOT NULL
AND (
a.is_spare_part -- spare part exception #27658
OR a.master -- masters exception (do not have cf_bo_for_sell, cf_www_visible and active2 filled)
OR (
NOT a.is_spare_part -- article is not spare part (must have active2)
AND a.active2 IS TRUE
)
)
ORDER BY
a.id,
q.cf_article_quality,
a_vat_0.id
) sq
'''.format(
view_name=Article._meta.db_table,
base_article_view=base_article_view_sql_item.name,
quality_view=quality_view_sql_item.name,
new_quality_code=NEW_QUALITY_CODE,
),
reverse_sql='DROP VIEW IF EXISTS {view_name}'.format(view_name=Article._meta.db_table),
replace=True,
dependencies=(
('my_django_app', quality_view_sql_item.name),
('my_django_app', base_article_view_sql_item.name),
),
)