diff --git a/migrations/000.349.sql b/migrations/000.349.sql new file mode 100644 index 0000000..8cdf78c --- /dev/null +++ b/migrations/000.349.sql @@ -0,0 +1,77 @@ +-- Create new order rows table + + + +CREATE TYPE order_row_status AS ENUM ( + 'no_status', + 'process', + 'error', + 'print', + 'packed', + 'cancelled', + 'sent' +); + +CREATE TYPE order_row_type AS ENUM ( + 'discount', + 'fee', + 'print', + 'stock', + 'sample', + 'refund' +); + +-- TODO: new-order: how to deal with inquiries??? +CREATE TYPE order_row_sub_type AS ENUM ( + 'no_subtype', + 'wallpaper', + 'canvas', + 'poster', + 'framed_print', + 'inquiry_wallpaper', + 'inquiry_canvas', + 'inquiry_poster', + 'inquiry_framed_print', + 'retouch_fee', + 'contract_customer_discount', + 'discount_code', + 'wallpaper_kit', + 'canvas_frame', + 'sample', + 'admin_product' +); + +-- Start sequence at 1 million for orders id table +ALTER SEQUENCE orders_id_seq RESTART WITH 1000000; + +CREATE TABLE order_rows ( + id int GENERATED ALWAYS AS IDENTITY (START WITH 2500000) PRIMARY KEY, + type order_row_type NOT NULL, + sub_type order_row_sub_type NOT NULL, + status order_row_status DEFAULT 'no_status', + order_id int REFERENCES orders (id), + designer_id int REFERENCES designers (designerid), + inserted timestamp with time zone DEFAULT now(), + updated timestamp with time zone, + price numeric NOT NULL, + commission_amount numeric DEFAULT 0.0, + data JSONB +); + +COMMENT ON COLUMN order_rows.price IS 'Price without VAT'; + +CREATE TRIGGER updated_timestamp BEFORE UPDATE ON public.order_rows FOR EACH ROW EXECUTE PROCEDURE public.updated_timestamp(); + +CREATE INDEX ON order_rows(order_id); +CREATE INDEX ON order_rows(designer_id); +CREATE INDEX ON order_rows(status); +CREATE INDEX ON order_rows(type); +CREATE INDEX ON order_rows(sub_type); + +CREATE INDEX ON order_rows((data->>'inquiryid')); +CREATE INDEX ON order_rows((data->>'code')); +CREATE INDEX ON order_rows((data->>'artNo')); +CREATE INDEX ON order_rows((data->>'group')); + +-- added column order_row_id to samples +ALTER TABLE samples ADD column IF NOT EXISTS order_row_id int REFERENCES order_rows (id); diff --git a/migrations/000.350.sql b/migrations/000.350.sql new file mode 100644 index 0000000..65dc1a4 --- /dev/null +++ b/migrations/000.350.sql @@ -0,0 +1,130 @@ +INSERT INTO order_rows (id, type, sub_type, status, order_id, designer_id, price, commission_amount, data, inserted) + OVERRIDING SYSTEM VALUE +SELECT rowid, itype::order_row_type, isubtype::order_row_sub_type, status::order_row_status, order_id, designer_id, price, commission_amount, data, inserted + FROM ( + SELECT orow.orderid order_id, + orow.rowid, + orow.inserted, + (odata.odata ->> 'designerId')::int designer_id, + (odata.odata ->> 'commission_amount')::float commission_amount, + CASE + -- next line are for admin products + WHEN (odata.odata ->> 'type') = 'stock' AND (odata.odata ->> 'path') is NULL THEN 'fee' + WHEN (odata.odata ->> 'modifier') LIKE '%Discount%' THEN 'discount' + WHEN (odata.odata ->> 'modifier') LIKE '%discount%' THEN 'discount' + WHEN (odata.odata ->> 'modifier') LIKE '%Fee%' THEN 'fee' + WHEN (odata.odata ->> 'path') = 'sample' THEN 'sample' + WHEN (odata.odata ->> 'type') = 'stock' THEN 'stock' + WHEN (odata.odata ->> 'status') = 'cancelled' THEN 'refund' + ELSE 'print' + END itype, + + CASE + -- next line are for admin products + WHEN (odata.odata ->> 'type') = 'stock' AND (odata.odata ->> 'path') is NULL THEN 'admin_product' + WHEN (odata.odata ->> 'modifier') = 'contractCustomerDiscount' THEN 'contract_customer_discount' + WHEN (odata.odata ->> 'modifier') = 'discount' THEN 'discount_code' + WHEN (odata.odata ->> 'path') = 'sample' THEN 'sample' + WHEN (odata.odata ->> 'path') = 'doityourselfframe' THEN 'canvas_frame' + WHEN (odata.odata ->> 'path') = 'wallpaper-kit' THEN 'wallpaper_kit' + WHEN (odata.odata ->> 'group') LIKE '%wallpaper' AND (odata.odata ->> 'inquiryid') IS NULL THEN 'wallpaper' + WHEN (odata.odata ->> 'group') LIKE 'canvas' AND (odata.odata ->> 'inquiryid') IS NULL THEN 'canvas' + WHEN (odata.odata ->> 'group') LIKE 'poster' AND (odata.odata ->> 'inquiryid') IS NULL THEN 'poster' + WHEN (odata.odata ->> 'group') LIKE 'framed-print' AND (odata.odata ->> 'inquiryid') IS NULL THEN 'framed_print' + WHEN (odata.odata ->> 'group') LIKE '%wallpaper' AND (odata.odata ->> 'inquiryid') IS NOT NULL THEN 'inquiry_wallpaper' + WHEN (odata.odata ->> 'group') LIKE 'canvas' AND (odata.odata ->> 'inquiryid') IS NOT NULL THEN 'inquiry_canvas' + WHEN (odata.odata ->> 'group') LIKE 'poster' AND (odata.odata ->> 'inquiryid') IS NOT NULL THEN 'inquiry_poster' + WHEN (odata.odata ->> 'group') LIKE 'framed-print' AND (odata.odata ->> 'inquiryid') IS NOT NULL THEN 'inquiry_framed_print' + ELSE 'no_subtype' + END isubtype, + + + CASE + -- next line are for admin products + WHEN (odata.odata ->> 'type') = 'stock' AND (odata.odata ->> 'path') is NULL THEN 'no_status' + WHEN (odata.odata ->> 'status') = 'pack' THEN 'process' + WHEN (odata.odata ->> 'status') IS NULL THEN 'no_status' + WHEN (odata.odata ->> 'imageprocessingrejected') = 'true' THEN 'error' + WHEN (odata.odata ->> 'imagedonotprint') = 'true' THEN 'cancelled' + ELSE (odata.odata ->> 'status') + END status, + (odata.odata ->> 'price')::float price, + odata.odata - '{designerId, commission_amount, status, price}'::text[] "data" + FROM "order-rows" orow + JOIN ( + SELECT od.rowid, + json_object_agg(orf.name, od.value)::jsonb AS odata + FROM "order-rows_details" od + JOIN "order-row_fields" orf + ON od.fieldid = orf.fieldid + GROUP BY 1 + ) odata ON orow.rowid = odata.rowid + WHERE orow.orderid IN + ( + SELECT oof.orderid + FROM "order-orders_fields" oof + WHERE fieldid = 168 + AND "value" = 'true' + ) + ) s; + +UPDATE order_rows SET data = jsonb_set("data", '{commission_resale}', to_jsonb((data ->> 'commission_resale')::int)) WHERE data->>'commission_resale' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{height}', to_jsonb((data ->> 'height')::int)) WHERE data->>'height' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{inquiryid}', to_jsonb((data ->> 'inquiryid')::int)) WHERE data->>'inquiryid' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{printId}', to_jsonb((data ->> 'printId')::int)) WHERE data->>'printId' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{productId}', to_jsonb((data ->> 'productId')::int)) WHERE data->>'productId' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{resolution}', to_jsonb((data ->> 'resolution')::int)) WHERE data->>'resolution' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{stockId}', to_jsonb((data ->> 'stockId')::int)) WHERE data->>'stockId' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{width}', to_jsonb((data ->> 'width')::int)) WHERE data->>'width' <> ''; + +UPDATE order_rows SET data = jsonb_set("data", '{commission}', to_jsonb((data ->> 'commission')::numeric)) WHERE data->>'commission' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{discountValue}', to_jsonb((data ->> 'discountValue')::numeric)) WHERE data->>'discountValue' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{displayHeight}', to_jsonb((data ->> 'displayHeight')::numeric)) WHERE data->>'displayHeight' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{displayWidth}', to_jsonb((data ->> 'displayWidth')::numeric)) WHERE data->>'displayWidth' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{fixedVAT}', to_jsonb((data ->> 'fixedVAT')::numeric)) WHERE data->>'fixedVAT' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{height_mm}', to_jsonb((data ->> 'height_mm')::numeric)) WHERE data->>'height_mm' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{imageHeight}', to_jsonb((data ->> 'imageHeight')::int)) WHERE data->>'imageHeight' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{imageWidth}', to_jsonb((data ->> 'imageWidth')::int)) WHERE data->>'imageWidth' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{percent}', to_jsonb((data ->> 'percent')::numeric)) WHERE data->>'percent' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{retouch_price}', to_jsonb((data ->> 'retouch_price')::numeric)) WHERE data->>'retouch_price' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{VAT}', to_jsonb((data ->> 'VAT')::numeric)) WHERE data->>'VAT' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{x}', to_jsonb((data ->> 'x')::numeric)) WHERE data->>'x' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{y}', to_jsonb((data ->> 'y')::numeric)) WHERE data->>'y' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{weight}', to_jsonb((data ->> 'weight')::numeric)) WHERE data->>'weight' <> ''; +UPDATE order_rows SET data = jsonb_set("data", '{width_mm}', to_jsonb((data ->> 'width_mm')::numeric)) WHERE data->>'width_mm' <> ''; + +UPDATE order_rows SET data = jsonb_set("data", '{automated}', to_jsonb(false)) WHERE data->>'automated' = '0'; +UPDATE order_rows SET data = jsonb_set("data", '{automated}', to_jsonb(true)) WHERE data->>'automated' = '1'; + +UPDATE order_rows SET data = jsonb_set("data", '{framed}', to_jsonb(false)) WHERE data->>'framed' = '0'; +UPDATE order_rows SET data = jsonb_set("data", '{framed}', to_jsonb(true)) WHERE data->>'framed' = '1'; + +UPDATE order_rows SET data = jsonb_set("data", '{uploaded}', to_jsonb(false)) WHERE data->>'uploaded' = '0'; +UPDATE order_rows SET data = jsonb_set("data", '{uploaded}', to_jsonb(true)) WHERE data->>'uploaded' = '1'; + +UPDATE order_rows SET data = jsonb_set("data", '{imagedonotprint}', to_jsonb(false)) WHERE data->>'imagedonotprint' = 'false'; +UPDATE order_rows SET data = jsonb_set("data", '{imagedonotprint}', to_jsonb(true)) WHERE data->>'imagedonotprint' = 'true'; + +UPDATE order_rows SET data = jsonb_set("data", '{imageprocessed}', to_jsonb(false)) WHERE data->>'imageprocessed' = 'false'; +UPDATE order_rows SET data = jsonb_set("data", '{imageprocessed}', to_jsonb(true)) WHERE data->>'imageprocessed' = 'true'; + +UPDATE order_rows SET data = jsonb_set("data", '{imageprocessingrejected}', to_jsonb(false)) WHERE data->>'imageprocessingrejected' = 'false'; +UPDATE order_rows SET data = jsonb_set("data", '{imageprocessingrejected}', to_jsonb(true)) WHERE data->>'imageprocessingrejected' = 'true'; + +UPDATE order_rows SET data = jsonb_set("data", '{mirrored}', to_jsonb(false)) WHERE data->>'mirrored' = '0'; +UPDATE order_rows SET data = jsonb_set("data", '{mirrored}', to_jsonb(true)) WHERE data->>'mirrored' = '1'; + +UPDATE order_rows SET data = jsonb_set("data", '{no_shipping}', to_jsonb(false)) WHERE data->>'no_shipping' = 'False'; +UPDATE order_rows SET data = jsonb_set("data", '{no_shipping}', to_jsonb(true)) WHERE data->>'no_shipping' = 'True'; + +UPDATE order_rows SET data = jsonb_set("data", '{packed}', to_jsonb(false)) WHERE data->>'packed' = 'false'; +UPDATE order_rows SET data = jsonb_set("data", '{packed}', to_jsonb(true)) WHERE data->>'packed' = 'true'; + +UPDATE order_rows SET data = jsonb_set("data", '{process}', to_jsonb(false)) WHERE data->>'process' = 'false'; +UPDATE order_rows SET data = jsonb_set("data", '{process}', to_jsonb(true)) WHERE data->>'process' = 'true'; + +UPDATE order_rows SET data = jsonb_set("data", '{edge_fixed}', to_jsonb(false)) WHERE data->>'edge_fixed' = 'false'; +UPDATE order_rows SET data = jsonb_set("data", '{edge_fixed}', to_jsonb(true)) WHERE data->>'edge_fixed' = 'true'; + +-- Special case of a job row from 2015 that appeared in processing list +UPDATE order_rows SET type = 'refund' WHERE id = 303385; diff --git a/migrations/000.351.sql b/migrations/000.351.sql new file mode 100644 index 0000000..101b8a8 --- /dev/null +++ b/migrations/000.351.sql @@ -0,0 +1,13 @@ +-- migrate email and phone to addresses table + +ALTER TABLE addresses ADD column IF NOT EXISTS email text; +ALTER TABLE addresses ADD column IF NOT EXISTS phone text; + +UPDATE addresses SET phone = oo.phone, email = oo.email FROM orders oo WHERE addresses.id = oo.billing_address_id; +UPDATE addresses SET phone = oo.delivery_phone, email = oo.delivery_email FROM orders oo WHERE addresses.id = oo.delivery_address_id; + + +-- ALTER table orders drop column phone; +-- ALTER table orders drop column email; +-- ALTER table orders drop column delivery_email; +-- ALTER table orders drop column delivery_phone; diff --git a/migrations/000.352.sql b/migrations/000.352.sql new file mode 100644 index 0000000..bc2a261 --- /dev/null +++ b/migrations/000.352.sql @@ -0,0 +1,234 @@ +-- Adapt to orders and order_rows tables + +-- +DROP VIEW IF EXISTS v_analytics_contract_customer_discounts; + +CREATE VIEW v_analytics_contract_customer_discounts AS + SELECT + order_rows.order_id as orderid, + order_rows.id as rowid, + orders.delivery_vat as vat, + order_rows.price, + round((order_rows.data->>'percent')::numeric / 100 , 2) AS percent + FROM order_rows + JOIN orders on orders.id = order_rows.order_id + WHERE order_rows.sub_type = 'contract_customer_discount'; + +GRANT SELECT ON v_analytics_contract_customer_discounts TO datastudio; + +-- +DROP VIEW IF EXISTS v_analytics_discounts; + +CREATE VIEW v_analytics_discounts AS + SELECT + order_rows.order_id as orderid, + order_rows.id as rowid, + order_rows.data->>'type' as type, + orders.delivery_vat as vat, + (abs(price / exchange_rate))::float AS price_sek, + order_rows.data->>'code' as code, + order_rows.data->>'no_shipping' as no_shipping + from order_rows + JOIN orders on orders.id = order_rows.order_id + WHERE order_rows.sub_type = 'discount_code'; + +GRANT SELECT ON v_analytics_discounts TO datastudio; + +-- + +DROP VIEW IF EXISTS v_analytics_inquiries; + +CREATE VIEW v_analytics_inquiries AS + SELECT inquiries.inquiryid, + inquiries.inserted::date AS inserted, + inquiries.updated::date AS updated, + inquiries.company, + inquiries.firstname, + inquiries.lastname AS email, + inquiries.market_id, + inquiries.locale_id AS product_group, + inquiries.price_m2, + inquiries.price_effect, + inquiries.price_retouch, + inquiries.width, + inquiries.height, + inquiries."artNo", + inquiries.materialid, + inquiries.zendesk_ticket, + order_rows.id AS order_row_id, + order_rows.order_id AS order_id + FROM inquiries + LEFT JOIN order_rows on order_rows.data->>'inquiryid' = inquiries.inquiryid::text + ORDER BY (inquiries.inserted::date) DESC; + +GRANT SELECT ON v_analytics_inquiries to datastudio; + +-- + +DROP VIEW IF EXISTS v_analytics_order_rows; + +CREATE VIEW v_analytics_order_rows AS + SELECT + CASE + WHEN orders.market IS NULL THEN 'Unknown' + WHEN orders.market = 'GB' THEN 'Photowall UK' + WHEN orders.market = 'GLOBAL' THEN 'Photowall OTHER' + ELSE 'Photowall ' || orders.market + END AS account, + order_rows.order_id as orderid, + order_rows.id as rowid, + orders.inserted::date AS orderdate, + order_rows.data->>'artNo' AS artno, + order_rows.data->>'productId' AS productid, + order_rows.data->>'name' AS name, + order_rows.data->>'inquiryid' AS inquiryid, + CASE + WHEN order_rows.type = 'sample' THEN 'Sample' + ELSE order_rows.data->>'group' + END AS type, + order_rows.data->>'material' as material, + COALESCE((order_rows.data->>'width_mm')::float / 10::float, (order_rows.data->>'width')::float) AS width, + COALESCE((order_rows.data->>'height_mm')::float / 10::float, (order_rows.data->>'height')::float) AS height, + CASE + WHEN order_rows.status = 'process' THEN 'Ready for processing' + WHEN order_rows.status = 'print' THEN 'Ready for packing' + WHEN order_rows.status = 'packed' THEN 'Ready for sending' + WHEN order_rows.status = 'sent' THEN 'Sent' + ELSE 'Unknown' + END AS status, + order_rows.data->>'commission' AS commission_percent, + round((order_rows.data->>'height')::float) AS commission_amount, + order_rows.data->>'discountType' AS discount_type, + order_rows.data->>'discountValue' AS discount_value, + CASE + WHEN order_rows.data->>'discountType' <> '%' THEN (order_rows.data->>'discountValue')::float / orders.exchange_rate + ELSE NULL::float + END AS discount_amount_sek, + orders.currency::TEXT AS order_currency, + order_rows.data->>'designer' AS designer, + (order_rows.price / orders.exchange_rate)::float AS item_value_sek, + order_rows.data->>'framed' AS canvas_frame, + order_rows.data->>'posterHanger' as poster_hanger, + order_rows.data->>'frame_color' as framed_print_frame, + order_rows.price::float AS price, + orders.delivery_vat AS vat + FROM order_rows + LEFT JOIN orders ON orders.id = order_rows.order_id + WHERE order_rows.type in ('print', 'stock'); + + +GRANT SELECT ON v_analytics_order_rows to datastudio; + + +-- + +DROP VIEW IF EXISTS v_analytics_orders_not_delivered; +CREATE VIEW v_analytics_orders_not_delivered AS + SELECT + CASE + WHEN orders.market IS NULL THEN 'Unknown' + WHEN orders.market = 'GB' THEN 'Photowall UK' + WHEN orders.market = 'GLOBAL' THEN 'Photowall OTHER' + ELSE 'Photowall ' || orders.market + END AS account, + orders.inserted::date AS orderdate, + orders.id as orderid, + md5(billing_address.first_name || 'secret') AS first_name, + md5(billing_address.last_name || 'secret') AS last_name, + md5(billing_address.company_name || 'secret') AS company, + md5(billing_address.address1 || 'secret') AS address, + billing_address.zipcode AS postal_code, + billing_address.city, + billing_address.country_code AS country, + md5(billing_address.email || 'secret') AS email, + order_sum::float / exchange_rate::float AS order_value_sek + FROM orders + LEFT JOIN addresses billing_address ON billing_address.id = orders.billing_address_id + WHERE confirmed = 1 AND delivered = 0 AND canceled = 0 AND paid = 1; + +GRANT SELECT ON v_analytics_orders_not_delivered to datastudio; + + +-- + +DROP VIEW IF EXISTS v_analytics_orders_rows_not_delivered; +CREATE VIEW v_analytics_orders_rows_not_delivered AS + SELECT order_rows.id AS order_row_id, + orders.id as orderid, + orders.inserted AS order_date, + order_rows.data->>'group' AS product_group, + order_rows.data->>'artNo' AS artno, + order_rows.status::TEXT AS status, + order_rows.data->>'name' AS name, + order_rows.data->>'material' AS material + FROM order_rows + JOIN orders ON order_rows.order_id = orders.id + WHERE order_rows.type in ('print', 'stock') + AND orders.confirmed = 1 + AND orders.delivered = 0 + AND orders.canceled = 0 + AND orders.paid = 1; +GRANT SELECT ON v_analytics_orders_rows_not_delivered to datastudio; + + +-- Update view +CREATE OR REPLACE VIEW public.v_analytics_orders2 AS + SELECT orders.id AS order_id, + orders.inserted AS order_date, + orders.delivered, + orders.newsletter, + orders.credit_invoice, + orders.canceled, + orders.reminder, + orders.delivered_date, + orders.country_code, + orders.language, + orders.delivery_country_code, + orders.delivery_method, + orders.delivery_price, + orders.customer_type, + orders.payment_type, + orders.currency, + orders.exchange_rate, + orders.exchange_rate_eur, + orders.invoice_id, + orders.contract_customer_id, + orders.vat_number, + orders.cancels_order_id, + orders.cancelled_by_order_id, + orders.reseller_store, + orders.order_sum, + orders.order_sum / orders.exchange_rate AS order_sum_sek, + billing_address.email, + billing_address.phone, + billing_address.address1 AS billing_address_address1, + billing_address.address2 AS billing_address_address2, + billing_address.company_name AS billing_address_company_name, + billing_address.country_code AS billing_address_country_code, + billing_address.city AS billing_address_city, + billing_address.zipcode AS billing_address_zipcode, + billing_address.first_name AS billing_address_first_name, + billing_address.last_name AS billing_address_last_name, + billing_address.state AS billing_address_state, + delivery_address.address1 AS delivery_address_address1, + delivery_address.address2 AS delivery_address_address2, + delivery_address.company_name AS delivery_address_company_name, + delivery_address.country_code AS delivery_address_country_code, + delivery_address.city AS delivery_address_city, + delivery_address.zipcode AS delivery_address_zipcode, + delivery_address.first_name AS delivery_address_first_name, + delivery_address.last_name AS delivery_address_last_name, + delivery_address.state AS delivery_address_state + FROM orders + JOIN addresses billing_address ON billing_address.id = orders.billing_address_id + LEFT JOIN addresses delivery_address ON delivery_address.id = orders.delivery_address_id + WHERE orders.paid = 1; + +GRANT SELECT ON v_analytics_orders2 TO datastudio; + +-- Not used +-- DROP VIEW IF EXISTS v_analytics_orders; +-- DROP VIEW IF EXISTS v_order_rows; +-- DROP VIEW IF EXISTS v_orders; +-- DROP MATERIALIZED VIEW IF EXISTS v_sales_report; +-- DROP MATERIALIZED VIEW IF EXISTS test; diff --git a/migrations/000.353.sql b/migrations/000.353.sql new file mode 100644 index 0000000..c816339 --- /dev/null +++ b/migrations/000.353.sql @@ -0,0 +1,5 @@ +-- remove order-orders foreign key from invoices + +ALTER TABLE invoices DROP CONSTRAINT order_fk; + +ALTER TABLE ONLY public.invoices ADD CONSTRAINT order_fk FOREIGN KEY (order_id) REFERENCES public.orders(id);