-- ============================================================================= -- Миграция: логистика, дни продаж и этапы оплаты — на manufacturers -- manufacturer_counterparty_map — только связь manufacturer_id + contractor_1c_id (из 1С) -- -- ВАЖНО: Перед запуском выполнить migrate_map_to_contractor_1c.sql -- (удаление counterparties, переход на contractor_1c_id) -- -- ИСТОЧНИК: contractor_producer_mapping, contractor_producer_payment_stage -- (сопоставление по v_contractors, v_producers → counterparties, manufacturers) -- -- 1. manufacturers: добавить days_of_sales, logistics_days, roic_norm -- 2. manufacturer_payment_stage: новая таблица, FK на manufacturers -- 3. Миграция из contractor_producer_* в manufacturers, map, manufacturer_payment_stage -- 4. manufacturer_counterparty_map: убрать days_of_sales, logistics_days, roic_norm (если есть) -- 5. Удалить contractor_producer_*, manufacturer_counterparty_payment_stage -- ============================================================================= USE [mag_pbi] GO SET NOCOUNT ON; -- ============================================================================= -- 1. manufacturers: добавить days_of_sales, logistics_days, roic_norm -- ============================================================================= IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'days_of_sales') ALTER TABLE [analytics].[manufacturers] ADD [days_of_sales] INT NOT NULL DEFAULT 180; IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'logistics_days') ALTER TABLE [analytics].[manufacturers] ADD [logistics_days] INT NOT NULL DEFAULT 120; IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'roic_norm') ALTER TABLE [analytics].[manufacturers] ADD [roic_norm] DECIMAL(12,4) NULL; -- Миграция из manufacturers.ROI_norm (если ещё не удалена, roic_norm уже добавлена) IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'ROI_norm') AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'roic_norm') BEGIN UPDATE [analytics].[manufacturers] SET [roic_norm] = [ROI_norm] WHERE [roic_norm] IS NULL AND [ROI_norm] IS NOT NULL; END -- Удалить старые поля manufacturers (n_percent, n_days, m_percent, m_days, ROI_norm) IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'ROI_norm') ALTER TABLE [analytics].[manufacturers] DROP COLUMN [ROI_norm]; IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'n_percent') ALTER TABLE [analytics].[manufacturers] DROP COLUMN [n_percent]; IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'n_days') ALTER TABLE [analytics].[manufacturers] DROP COLUMN [n_days]; IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'm_percent') ALTER TABLE [analytics].[manufacturers] DROP COLUMN [m_percent]; IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'm_days') ALTER TABLE [analytics].[manufacturers] DROP COLUMN [m_days]; PRINT 'manufacturers: добавлены days_of_sales, logistics_days, roic_norm'; GO -- ============================================================================= -- 2. manufacturer_payment_stage — этапы оплаты, привязаны к manufacturers -- ============================================================================= IF OBJECT_ID(N'[analytics].[manufacturer_payment_stage]', N'U') IS NULL BEGIN CREATE TABLE [analytics].[manufacturer_payment_stage] ( [id] INT IDENTITY(1,1) NOT NULL, [manufacturer_id] INT NOT NULL, [name] NVARCHAR(255) NOT NULL, [days] INT NOT NULL, [percent] DECIMAL(9,4) NOT NULL, [sort_order] INT NOT NULL DEFAULT 0, CONSTRAINT [PK_manufacturer_payment_stage] PRIMARY KEY CLUSTERED ([id]), CONSTRAINT [FK_manufacturer_payment_stage] FOREIGN KEY ([manufacturer_id]) REFERENCES [analytics].[manufacturers]([id]) ON DELETE CASCADE ); CREATE NONCLUSTERED INDEX [IX_manufacturer_payment_stage_manufacturer_id] ON [analytics].[manufacturer_payment_stage]([manufacturer_id]); PRINT 'Создана таблица manufacturer_payment_stage'; END GO -- ============================================================================= -- Миграция из contractor_producer_mapping и contractor_producer_payment_stage -- (требует v_contractors, v_producers; manufacturer_counterparty_map с contractor_1c_id) -- ============================================================================= IF OBJECT_ID(N'[analytics].[contractor_producer_mapping]', N'U') IS NOT NULL AND OBJECT_ID(N'[analytics].[contractor_producer_payment_stage]', N'U') IS NOT NULL AND OBJECT_ID(N'[analytics].[v_contractors]', N'V') IS NOT NULL AND OBJECT_ID(N'[analytics].[v_producers]', N'V') IS NOT NULL AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'contractor_1c_id') BEGIN -- 3a. Добавить недостающие manufacturers (по именам из 1С) INSERT INTO [analytics].[manufacturers] (manufacturer, days_of_sales, logistics_days, roic_norm) SELECT t.producer_name, t.days_of_sales, t.logistics_days, t.roic_norm FROM ( SELECT LTRIM(RTRIM(p.producer_name)) AS producer_name, m.days_of_sales, m.logistics_days, m.roic_norm, ROW_NUMBER() OVER (PARTITION BY LTRIM(RTRIM(p.producer_name)) ORDER BY m.id) AS rn FROM [analytics].[contractor_producer_mapping] m JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id ) t WHERE t.rn = 1 AND NOT EXISTS (SELECT 1 FROM [analytics].[manufacturers] man WHERE LTRIM(RTRIM(man.manufacturer)) = t.producer_name); -- 3b. Обновить manufacturers (days, logistics, roic) из contractor_producer_mapping UPDATE man SET man.days_of_sales = src.days_of_sales, man.logistics_days = src.logistics_days, man.roic_norm = COALESCE(man.roic_norm, src.roic_norm) FROM [analytics].[manufacturers] man JOIN ( SELECT p.producer_name, m.days_of_sales, m.logistics_days, m.roic_norm, ROW_NUMBER() OVER (PARTITION BY LTRIM(RTRIM(p.producer_name)) ORDER BY m.id) AS rn FROM [analytics].[contractor_producer_mapping] m JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id ) src ON LTRIM(RTRIM(man.manufacturer)) = LTRIM(RTRIM(src.producer_name)) AND src.rn = 1; -- 3c. Вставить связи в manufacturer_counterparty_map (contractor_1c_id из 1С) INSERT INTO [analytics].[manufacturer_counterparty_map] (manufacturer_id, contractor_1c_id) SELECT man.id, m.contractor_1c_id FROM [analytics].[contractor_producer_mapping] m JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id JOIN [analytics].[manufacturers] man ON LTRIM(RTRIM(man.manufacturer)) = LTRIM(RTRIM(p.producer_name)) WHERE NOT EXISTS ( SELECT 1 FROM [analytics].[manufacturer_counterparty_map] mcm WHERE mcm.manufacturer_id = man.id AND mcm.contractor_1c_id = m.contractor_1c_id ); PRINT 'Миграция из contractor_producer_mapping: вставлено связей ' + CAST(@@ROWCOUNT AS NVARCHAR(10)); -- 3d. Миграция этапов в manufacturer_payment_stage (по одному набору на производителя — из первого mapping) INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order) SELECT man.id, s.name, s.[days], s.[percent], s.sort_order FROM [analytics].[contractor_producer_payment_stage] s JOIN [analytics].[contractor_producer_mapping] m ON m.id = s.mapping_id JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id JOIN [analytics].[manufacturers] man ON LTRIM(RTRIM(man.manufacturer)) = LTRIM(RTRIM(p.producer_name)) WHERE m.id = ( SELECT MIN(m2.id) FROM [analytics].[contractor_producer_mapping] m2 JOIN [analytics].[v_producers] p2 ON p2.producer_1c_id = m2.producer_1c_id WHERE LTRIM(RTRIM(p2.producer_name)) = LTRIM(RTRIM(p.producer_name)) ) AND man.id NOT IN (SELECT manufacturer_id FROM [analytics].[manufacturer_payment_stage]); PRINT 'Миграция из contractor_producer_payment_stage: вставлено этапов ' + CAST(@@ROWCOUNT AS NVARCHAR(10)); END GO -- Fallback: миграция из manufacturer_counterparty_payment_stage (если contractor_producer уже удалён) IF OBJECT_ID(N'[analytics].[manufacturer_counterparty_payment_stage]', N'U') IS NOT NULL BEGIN INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order) SELECT mcm.manufacturer_id, s.name, s.[days], s.[percent], s.sort_order FROM [analytics].[manufacturer_counterparty_payment_stage] s JOIN [analytics].[manufacturer_counterparty_map] mcm ON mcm.id = s.map_id WHERE mcm.id = (SELECT MIN(m2.id) FROM [analytics].[manufacturer_counterparty_map] m2 WHERE m2.manufacturer_id = mcm.manufacturer_id) AND mcm.manufacturer_id NOT IN (SELECT manufacturer_id FROM [analytics].[manufacturer_payment_stage]); PRINT 'Миграция из manufacturer_counterparty_payment_stage: ' + CAST(@@ROWCOUNT AS NVARCHAR(10)); END GO -- Дефолтные этапы для manufacturers без этапов (из старых n_/m_ полей, если остались — уже удалены) -- Берём manufacturers без этапов и добавляем Предоплата+Постоплата INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order) SELECT man.id, N'Предоплата', 7, 50, 0 FROM [analytics].[manufacturers] man WHERE NOT EXISTS (SELECT 1 FROM [analytics].[manufacturer_payment_stage] s WHERE s.manufacturer_id = man.id); INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order) SELECT man.id, N'Постоплата', 120, 50, 1 FROM [analytics].[manufacturers] man WHERE (SELECT COUNT(*) FROM [analytics].[manufacturer_payment_stage] s WHERE s.manufacturer_id = man.id) = 1; PRINT 'Созданы дефолтные этапы оплаты'; GO -- ============================================================================= -- 3. manufacturer_counterparty_map: убрать days_of_sales, logistics_days, roic_norm -- ============================================================================= IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'days_of_sales') ALTER TABLE [analytics].[manufacturer_counterparty_map] DROP COLUMN [days_of_sales]; IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'logistics_days') ALTER TABLE [analytics].[manufacturer_counterparty_map] DROP COLUMN [logistics_days]; IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'roic_norm') ALTER TABLE [analytics].[manufacturer_counterparty_map] DROP COLUMN [roic_norm]; PRINT 'manufacturer_counterparty_map: оставлены только manufacturer_id, counterparty_id'; GO -- ============================================================================= -- 4. Удалить manufacturer_counterparty_payment_stage и contractor_producer_* -- ============================================================================= IF OBJECT_ID(N'[analytics].[manufacturer_counterparty_payment_stage]', N'U') IS NOT NULL DROP TABLE [analytics].[manufacturer_counterparty_payment_stage]; IF OBJECT_ID(N'[analytics].[v_contractor_producer_mapping]', N'V') IS NOT NULL DROP VIEW [analytics].[v_contractor_producer_mapping]; IF OBJECT_ID(N'[analytics].[contractor_producer_payment_stage]', N'U') IS NOT NULL DROP TABLE [analytics].[contractor_producer_payment_stage]; IF OBJECT_ID(N'[analytics].[contractor_producer_mapping]', N'U') IS NOT NULL DROP TABLE [analytics].[contractor_producer_mapping]; PRINT 'Удалены manufacturer_counterparty_payment_stage и contractor_producer_*'; GO -- ============================================================================= -- 5. Представление для API (map + manufacturer + counterparty, roic из manufacturers) -- ============================================================================= IF OBJECT_ID(N'[analytics].[v_manufacturer_counterparty_mapping]', N'V') IS NOT NULL DROP VIEW [analytics].[v_manufacturer_counterparty_mapping]; GO CREATE VIEW [analytics].[v_manufacturer_counterparty_mapping] AS SELECT mcm.id, mcm.manufacturer_id, p.producer_id, man.manufacturer AS manufacturer_name, mcm.contractor_1c_id, c.contractor_id, c.contractor_name AS contractor_name, man.days_of_sales, man.logistics_days, man.roic_norm FROM [analytics].[manufacturer_counterparty_map] mcm LEFT JOIN [analytics].[manufacturers] man ON man.id = mcm.manufacturer_id LEFT JOIN [analytics].[v_contractors] c ON c.contractor_1c_id = mcm.contractor_1c_id LEFT JOIN [analytics].[v_producers] p ON LTRIM(RTRIM(p.producer_name)) = LTRIM(RTRIM(man.manufacturer)); GO PRINT 'Создано представление v_manufacturer_counterparty_mapping'; GO -- ============================================================================= -- 6. View для обратной совместимости процедур (manufacturer + roic + n_/m_) -- ============================================================================= IF OBJECT_ID(N'[analytics].[v_manufacturers_roi_compat]', N'V') IS NOT NULL DROP VIEW [analytics].[v_manufacturers_roi_compat]; GO CREATE VIEW [analytics].[v_manufacturers_roi_compat] AS SELECT man.id, man.manufacturer, man.roic_norm AS ROI_norm, n_stage.[percent] / 100.0 AS n_percent, n_stage.[days] AS n_days, m_stage.[percent] / 100.0 AS m_percent, m_stage.[days] AS m_days FROM [analytics].[manufacturers] man LEFT JOIN ( SELECT manufacturer_id, [percent], [days], ROW_NUMBER() OVER (PARTITION BY manufacturer_id ORDER BY sort_order, [days]) AS rn FROM [analytics].[manufacturer_payment_stage] ) n_stage ON n_stage.manufacturer_id = man.id AND n_stage.rn = 1 LEFT JOIN ( SELECT manufacturer_id, [percent], [days], ROW_NUMBER() OVER (PARTITION BY manufacturer_id ORDER BY sort_order, [days]) AS rn FROM [analytics].[manufacturer_payment_stage] ) m_stage ON m_stage.manufacturer_id = man.id AND m_stage.rn = 2; GO