From 0258157a445bf4606e65c379dca5b1f51920e383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=9B=D0=B5=D0=B1?= =?UTF-8?q?=D0=B5=D0=B4=D0=B5=D0=B2?= Date: Sun, 22 Feb 2026 11:41:09 +0000 Subject: [PATCH] Update SQL schema from mag_pbi --- sql_db_mag_pbi/mag_pbi_procedures.sql | 3546 +++++++++++++++++++++++++ sql_db_mag_pbi/mag_pbi_tables.sql | 132 +- sql_db_mag_pbi/mag_pbi_views.sql | 2036 ++++++++++++++ 3 files changed, 5648 insertions(+), 66 deletions(-) diff --git a/sql_db_mag_pbi/mag_pbi_procedures.sql b/sql_db_mag_pbi/mag_pbi_procedures.sql index 68c3457..683f7a9 100644 --- a/sql_db_mag_pbi/mag_pbi_procedures.sql +++ b/sql_db_mag_pbi/mag_pbi_procedures.sql @@ -1,2 +1,3548 @@ USE [mag_pbi] GO + +/****** Object: StoredProcedure [analytics].[create_forecast_loop] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE procedure [analytics].[create_forecast_loop] as begin + DECLARE @from_month DATE = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1); + DECLARE @to_month_excl DATE = '2027-01-01'; + DECLARE @scenario_id INT = 4; + DECLARE @path NVARCHAR(255); + + DECLARE cur CURSOR LOCAL FAST_FORWARD FOR + SELECT [path] + FROM [pbi].[groups] g + WHERE [lvl] = 2 + AND g.[path] NOT LIKE '*%' -- (опционально) исключить служебные группы + + /*AND ( + g.[path] LIKE N'Р%' OR + g.[path] LIKE N'С%' OR + g.[path] LIKE N'Т%' OR + g.[path] LIKE N'У%' OR + g.[path] LIKE N'Ф%' OR + g.[path] LIKE N'Х%' OR + g.[path] LIKE N'Ц%' OR + g.[path] LIKE N'Ч%' OR + g.[path] LIKE N'Ш%' OR + g.[path] LIKE N'Щ%' OR + g.[path] LIKE N'Э%' OR + g.[path] LIKE N'Ю%' OR + g.[path] LIKE N'Я%' + )*/ + ORDER BY [path]; + + OPEN cur; + FETCH NEXT FROM cur INTO @path; + + WHILE @@FETCH_STATUS = 0 + BEGIN + PRINT CONCAT('Rebuild forecast for: ', @path); + EXEC [analytics].[sp_build_forecast_s4_by_group] + @path = @path, + @from_month = @from_month, + @to_month_excl = @to_month_excl, + @scenario_id = @scenario_id; + + FETCH NEXT FROM cur INTO @path; + END + + CLOSE cur; + DEALLOCATE cur; +END +GO + +/****** Object: StoredProcedure [analytics].[create_seasonality_groups] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE analytics.[create_seasonality_groups] as +BEGIN + /* 1) Таблица результата */ + IF NOT EXISTS ( + SELECT 1 + FROM sys.tables t + JOIN sys.schemas s ON s.schema_id = t.schema_id + WHERE s.name = 'analytics' AND t.name = 'seasonality_groups' + ) + BEGIN + CREATE TABLE [analytics].[seasonality_groups]( + [group_1c_id] BINARY(16) NOT NULL, + [month] TINYINT NOT NULL, -- 1..12 + [seasonal_koef] DECIMAL(18,6) NOT NULL, + CONSTRAINT [PK_seasonality_groups] PRIMARY KEY ([group_1c_id], [month]) + ); + CREATE INDEX [IX_seasonality_groups_month] + ON [analytics].[seasonality_groups]([month]); + END + + TRUNCATE TABLE [analytics].[seasonality_groups]; + /* 2) Пересчёт коэффициентов сезонности для g и g1 */ + ;WITH + -- Продажи по товарам за последние 24 месяца (кол-во) + [base_sales] AS ( + SELECT + [n].[1c_id] AS [sku_1c_id], + [gcur].[g], + [gcur].[g1], + [v].[Период] AS [dt], + CAST([v].[Количество] AS DECIMAL(18,6)) AS [qty] + FROM [mag_pbi].[pbiProd].[СводныйСебестоимость Для PBI] AS [v] + JOIN [pbi].[nomenclature] AS [n] + ON [n].[1c_id] = [v].[1c_id] + LEFT JOIN [pbi].[groups] AS [gcur] + ON [gcur].[1c_id] = [n].[1c_group] + WHERE [v].[Статья] = N'Реализация' + AND [v].[Период] >= DATEADD(YEAR, -2, CAST(GETDATE() AS date)) + ), + -- Агрегация по месяцам и уровню g (lvl=0) + [lvl0_monthly] AS ( + SELECT + [g0].[1c_id] AS [group_1c_id], + DATEFROMPARTS(YEAR([b].[dt]), MONTH([b].[dt]), 1) AS [month_start], + SUM([b].[qty]) AS [qty_m] + FROM [base_sales] AS [b] + JOIN [pbi].[groups] AS [g0] + ON [g0].[lvl] = 1 + AND [g0].[g] = [b].[g] + GROUP BY [g0].[1c_id], DATEFROMPARTS(YEAR([b].[dt]), MONTH([b].[dt]), 1) + ), + -- Агрегация по месяцам и уровню g1 (lvl=1) + [lvl1_monthly] AS ( + SELECT + [g1].[1c_id] AS [group_1c_id], + DATEFROMPARTS(YEAR([b].[dt]), MONTH([b].[dt]), 1) AS [month_start], + SUM([b].[qty]) AS [qty_m] + FROM [base_sales] AS [b] + JOIN [pbi].[groups] AS [g1] + ON [g1].[lvl] = 2 + AND [g1].[g1] = [b].[g1] + GROUP BY [g1].[1c_id], DATEFROMPARTS(YEAR([b].[dt]), MONTH([b].[dt]), 1) + ), + -- Объединяем уровни + [monthly_union] AS ( + SELECT * FROM [lvl0_monthly] + UNION ALL + SELECT * FROM [lvl1_monthly] + ), + -- Средние по «месяцу года» + [per_moy] AS ( + SELECT + [u].[group_1c_id], + MONTH([u].[month_start]) AS [month], + AVG([u].[qty_m]) AS [avg_qty_moy] + FROM [monthly_union] AS [u] + GROUP BY [u].[group_1c_id], MONTH([u].[month_start]) + ), + -- Общая средняя по группе + [overall] AS ( + SELECT + [u].[group_1c_id], + AVG([u].[qty_m]) AS [overall_avg_monthly] + FROM [monthly_union] AS [u] + GROUP BY [u].[group_1c_id] + ), + -- Черновой коэффициент + [raw_koef] AS ( + SELECT + [p].[group_1c_id], + [p].[month], + CASE + WHEN [o].[overall_avg_monthly] = 0 THEN 0 + ELSE [p].[avg_qty_moy] / [o].[overall_avg_monthly] + END AS [k_raw] + FROM [per_moy] AS [p] + JOIN [overall] AS [o] + ON [o].[group_1c_id] = [p].[group_1c_id] + ), + [norm] AS ( + SELECT + [r].[group_1c_id], + [r].[month], + [r].[k_raw] / NULLIF(AVG([r].[k_raw]) OVER (PARTITION BY [r].[group_1c_id]), 0) AS [seasonal_koef] + FROM [raw_koef] AS [r] + ) + INSERT INTO [analytics].[seasonality_groups] ([group_1c_id], [month], [seasonal_koef]) + SELECT [group_1c_id], [month], CAST([seasonal_koef] AS DECIMAL(18,6)) + FROM [norm]; + +END +GO + +/****** Object: StoredProcedure [analytics].[sp_build_deficit_proposal] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/* ======================================================================= + [analytics].[sp_build_deficit_proposal] + — Дефицит и рекомендации к заказу с учётом: + • стартовых остатков (склад + МП), + • прихода из заказов (4 статуса, включая 'Согласован'), + • прогноза по сценарию, + • НЕТ бэк-ордеров: спрос не «копится» ниже нуля, + остаток считается итеративно и не уходит в минус, + • размер заказа = прогноз окна [T .. T + @cover_months). + ======================================================================= */ +CREATE PROCEDURE [analytics].[sp_build_deficit_proposal] + @scenario_id INT = 4, -- ID сценария прогноза + @group_path NVARCHAR(255) = N'', -- path группы ('' = весь каталог) + @lead_time_m INT = 4, -- срок поставки (мес.) + @cover_months INT = 6, -- покрытие (мес.) + @from_month DATE = NULL, -- старт (1-е число месяца) + @to_month_excl DATE = '2028-01-01', -- полуинтервал [from, to) + @debug BIT = 0 +AS +BEGIN + SET NOCOUNT ON; + + /* 0) Чистим прошлые данные по сценарию */ + DELETE FROM [analytics].[deficit_proposal] WHERE scenario_id = @scenario_id; + + /* Нормализация параметров */ + SET @group_path = LTRIM(RTRIM(REPLACE(@group_path, '''', N''))); + IF @from_month IS NULL + SET @from_month = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1); + + /* 1) Календарь */ + IF OBJECT_ID('tempdb..#cal') IS NOT NULL DROP TABLE #cal; + CREATE TABLE #cal (month_start DATE NOT NULL PRIMARY KEY); + ;WITH cal AS ( + SELECT @from_month AS month_start + UNION ALL + SELECT DATEADD(MONTH, 1, month_start) + FROM cal + WHERE month_start < DATEADD(MONTH, -1, @to_month_excl) + ) + INSERT INTO #cal(month_start) + SELECT month_start FROM cal + OPTION (MAXRECURSION 32767); + + /* 2) SKU по group_path */ + IF OBJECT_ID('tempdb..#skus') IS NOT NULL DROP TABLE #skus; + CREATE TABLE #skus ( + sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, + code NVARCHAR(36) NULL, + minAvail DECIMAL(18,6) NULL + ); + INSERT INTO #skus(sku_1c_id, code, minAvail) + SELECT n.[1c_id], n.[code], n.[minAvailableQty] + FROM [pbi].[nomenclature] n + JOIN [pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE g.[path] LIKE @group_path + N'%'; + + IF NOT EXISTS (SELECT 1 FROM #skus) + BEGIN + RAISERROR(N'По path=%s не найдено SKU.', 16, 1, @group_path); + RETURN; + END + + /* 3) Прогноз по сценарию */ + IF OBJECT_ID('tempdb..#fcast') IS NOT NULL DROP TABLE #fcast; + CREATE TABLE #fcast ( + sku_1c_id BINARY(16) NOT NULL, + [month] DATE NOT NULL, + qty DECIMAL(18,3) NOT NULL, + PRIMARY KEY (sku_1c_id, [month]) + ); + INSERT INTO #fcast(sku_1c_id, [month], qty) + SELECT f.[1c_id], f.[month], f.[value] + FROM [analytics].[forecast] f + JOIN #skus s ON s.sku_1c_id = f.[1c_id] + WHERE f.[scenario_id] = @scenario_id + AND f.[month] >= @from_month + AND f.[month] < @to_month_excl; + + /* 4) Приходы из заказов (по месяцам) */ + IF OBJECT_ID('tempdb..#inb_status') IS NOT NULL DROP TABLE #inb_status; + CREATE TABLE #inb_status ( + sku_1c_id BINARY(16) NOT NULL, + [month] DATE NOT NULL, + [status] NVARCHAR(100) NOT NULL, + units DECIMAL(18,3) NOT NULL, + PRIMARY KEY (sku_1c_id, [month], [status]) + ); + INSERT INTO #inb_status(sku_1c_id, [month], [status], units) + SELECT + s.sku_1c_id, + DATEFROMPARTS(TRY_CONVERT(INT, LEFT(o.[month], 4)), + TRY_CONVERT(INT, SUBSTRING(o.[month], 6, 2)), 1), + o.[status], + SUM(COALESCE(o.[units], 0.0)) + FROM [analytics].[get_orders_by_group] o + JOIN #skus s ON s.code = o.[code] + WHERE o.[status] IN (N'В пути', N'В производстве', N'Выгружен на складе'/*, N'Согласован'*/) + AND TRY_CONVERT(INT, LEFT(o.[month], 4)) IS NOT NULL + AND TRY_CONVERT(INT, SUBSTRING(o.[month], 6, 2)) BETWEEN 1 AND 12 + GROUP BY s.sku_1c_id, + DATEFROMPARTS(TRY_CONVERT(INT, LEFT(o.[month], 4)), + TRY_CONVERT(INT, SUBSTRING(o.[month], 6, 2)), 1), + o.[status]; + + IF OBJECT_ID('tempdb..#inb') IS NOT NULL DROP TABLE #inb; + CREATE TABLE #inb ( + sku_1c_id BINARY(16) NOT NULL, + [month] DATE NOT NULL, + units DECIMAL(18,3) NOT NULL, + PRIMARY KEY (sku_1c_id, [month]) + ); + INSERT INTO #inb(sku_1c_id, [month], units) + SELECT sku_1c_id, [month], SUM(units) + FROM #inb_status + WHERE [month] >= @from_month AND [month] < @to_month_excl + GROUP BY sku_1c_id, [month]; + + /* 5) Стартовые остатки: склад + МП */ + IF OBJECT_ID('tempdb..#stock_base') IS NOT NULL DROP TABLE #stock_base; + CREATE TABLE #stock_base (sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, qty DECIMAL(18,3) NOT NULL); + INSERT INTO #stock_base(sku_1c_id, qty) + SELECT s.sku_1c_id, COALESCE(b.qty, 0.0) + FROM #skus s + LEFT JOIN ( + SELECT code, SUM(COALESCE(quantity_base,0.0)) AS qty + FROM [analytics].[get_quantity_by_group] + GROUP BY code + ) b ON b.code = s.code; + + IF OBJECT_ID('tempdb..#stock_mp') IS NOT NULL DROP TABLE #stock_mp; + CREATE TABLE #stock_mp (sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, qty DECIMAL(18,3) NOT NULL); + INSERT INTO #stock_mp(sku_1c_id, qty) + SELECT s.sku_1c_id, COALESCE(m.qty, 0.0) + FROM #skus s + LEFT JOIN ( + SELECT code, SUM(COALESCE(quantity_base,0.0)) AS qty + FROM [analytics].[get_mp_quantity_by_group] + GROUP BY code + ) m ON m.code = s.code; + + IF OBJECT_ID('tempdb..#stock0') IS NOT NULL DROP TABLE #stock0; + CREATE TABLE #stock0 (sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, qty DECIMAL(18,3) NOT NULL); + INSERT INTO #stock0(sku_1c_id, qty) + SELECT s.sku_1c_id, COALESCE(b.qty,0) + COALESCE(mp.qty,0) + FROM #skus s + LEFT JOIN #stock_base b ON b.sku_1c_id = s.sku_1c_id + LEFT JOIN #stock_mp mp ON mp.sku_1c_id = s.sku_1c_id; + + /* 6) Лента (сырой спрос/приход) */ + IF OBJECT_ID('tempdb..#tl') IS NOT NULL DROP TABLE #tl; + CREATE TABLE #tl ( + sku_1c_id BINARY(16) NOT NULL, + [month] DATE NOT NULL, + demand_m DECIMAL(18,3) NOT NULL, + inb_m DECIMAL(18,3) NOT NULL, + cum_d DECIMAL(38,3) NULL, -- кумулятив обслуженного спроса + cum_i DECIMAL(38,3) NULL, -- кумулятив прихода + net_stock DECIMAL(38,3) NULL, -- итоговый остаток месяца (>=0) + served_m DECIMAL(18,3) NULL, -- обслуженный спрос в месяце + lost_m DECIMAL(18,3) NULL, -- потерянный спрос в месяце + PRIMARY KEY (sku_1c_id, [month]) + ); + INSERT INTO #tl(sku_1c_id, [month], demand_m, inb_m) + SELECT s.sku_1c_id, c.month_start, + COALESCE(f.qty, 0.0), + COALESCE(i.units, 0.0) + FROM #skus s + CROSS JOIN #cal c + LEFT JOIN #fcast f ON f.sku_1c_id = s.sku_1c_id AND f.[month] = c.month_start + LEFT JOIN #inb i ON i.sku_1c_id = s.sku_1c_id AND i.[month] = c.month_start; + + /* 6.1) Пронумеруем месяцы (для рекурсивного расчёта без бэк-ордеров) */ + IF OBJECT_ID('tempdb..#seq') IS NOT NULL DROP TABLE #seq; + CREATE TABLE #seq ( + sku_1c_id BINARY(16) NOT NULL, + [month] DATE NOT NULL, + demand_m DECIMAL(18,3) NOT NULL, + inb_m DECIMAL(18,3) NOT NULL, + rn INT NOT NULL, + PRIMARY KEY (sku_1c_id, rn) + ); + INSERT INTO #seq(sku_1c_id, [month], demand_m, inb_m, rn) + SELECT t.sku_1c_id, t.[month], t.demand_m, t.inb_m, + ROW_NUMBER() OVER (PARTITION BY t.sku_1c_id ORDER BY t.[month]) + FROM #tl t; + + /* 6.2) Рекурсивный расчёт: served/lost/net_stock (без накопления спроса ниже нуля) */ + IF OBJECT_ID('tempdb..#flow') IS NOT NULL DROP TABLE #flow; + CREATE TABLE #flow( + sku_1c_id BINARY(16) NOT NULL, + rn INT NOT NULL, + [month] DATE NOT NULL, + demand_m DECIMAL(18,3) NOT NULL, + inb_m DECIMAL(18,3) NOT NULL, + served_m DECIMAL(18,3) NOT NULL, + lost_m DECIMAL(18,3) NOT NULL, + net_stock DECIMAL(38,3) NOT NULL, + PRIMARY KEY (sku_1c_id, rn) + ); + + ;WITH r AS ( + /* первый месяц */ + SELECT + s.sku_1c_id, s.rn, s.[month], s.demand_m, s.inb_m, + CAST( + CASE WHEN st.qty + s.inb_m >= s.demand_m + THEN s.demand_m + ELSE st.qty + s.inb_m + END + AS DECIMAL(18,3)) AS served_m, + CAST( + CASE WHEN st.qty + s.inb_m >= s.demand_m + THEN 0.0 + ELSE s.demand_m - (st.qty + s.inb_m) + END + AS DECIMAL(18,3)) AS lost_m, + CAST( + CASE WHEN st.qty + s.inb_m - s.demand_m < 0 + THEN 0 + ELSE st.qty + s.inb_m - s.demand_m + END + AS DECIMAL(38,3)) AS net_stock + FROM #seq s + JOIN #stock0 st ON st.sku_1c_id = s.sku_1c_id + WHERE s.rn = 1 + + UNION ALL + + /* последующие месяцы */ + SELECT + s.sku_1c_id, s.rn, s.[month], s.demand_m, s.inb_m, + CAST( + CASE WHEN r.net_stock + s.inb_m >= s.demand_m + THEN s.demand_m + ELSE r.net_stock + s.inb_m + END + AS DECIMAL(18,3)) AS served_m, + CAST( + CASE WHEN r.net_stock + s.inb_m >= s.demand_m + THEN 0.0 + ELSE s.demand_m - (r.net_stock + s.inb_m) + END + AS DECIMAL(18,3)) AS lost_m, + CAST( + CASE WHEN r.net_stock + s.inb_m - s.demand_m < 0 + THEN 0 + ELSE r.net_stock + s.inb_m - s.demand_m + END + AS DECIMAL(38,3)) AS net_stock + FROM r + JOIN #seq s + ON s.sku_1c_id = r.sku_1c_id + AND s.rn = r.rn + 1 + ) + INSERT INTO #flow + SELECT * FROM r + OPTION (MAXRECURSION 32767); + + /* 6.3) Обновим #tl: кумулятивы по обслуженному спросу/приходу и итоговый остаток */ + ;WITH cd AS ( + SELECT f.sku_1c_id, s.[month], + SUM(f.served_m) OVER (PARTITION BY f.sku_1c_id ORDER BY f.rn ROWS UNBOUNDED PRECEDING) AS cum_d_served, + SUM(s.inb_m) OVER (PARTITION BY s.sku_1c_id ORDER BY s.rn ROWS UNBOUNDED PRECEDING) AS cum_i_raw, + f.net_stock, f.served_m, f.lost_m + FROM #flow f + JOIN #seq s ON s.sku_1c_id = f.sku_1c_id AND s.rn = f.rn + ) + UPDATE t + SET t.cum_d = cd.cum_d_served, + t.cum_i = cd.cum_i_raw, + t.net_stock = cd.net_stock, + t.served_m = cd.served_m, + t.lost_m = cd.lost_m + FROM #tl t + JOIN cd ON cd.sku_1c_id = t.sku_1c_id AND cd.[month] = t.[month]; + + /* 7) Первый месяц дефицита T (учитываем lead_time) */ + DECLARE @start_T DATE = + DATEFROMPARTS(YEAR(DATEADD(MONTH, @lead_time_m, @from_month)), + MONTH(DATEADD(MONTH, @lead_time_m, @from_month)), 1); + + IF OBJECT_ID('tempdb..#first_def') IS NOT NULL DROP TABLE #first_def; + CREATE TABLE #first_def (sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, T DATE NULL); + + INSERT INTO #first_def(sku_1c_id, T) + SELECT d.sku_1c_id, MIN(d.[month]) AS T + FROM ( + SELECT t.sku_1c_id, t.[month] + FROM #tl t + JOIN #skus s ON s.sku_1c_id = t.sku_1c_id + WHERE t.net_stock < COALESCE(s.minAvail, 0.0) + AND t.[month] >= @start_T + ) d + GROUP BY d.sku_1c_id; + + /* 8) Якоря: T, T+C, T+2C ... */ + IF OBJECT_ID('tempdb..#anchors') IS NOT NULL DROP TABLE #anchors; + CREATE TABLE #anchors ( + sku_1c_id BINARY(16) NOT NULL, + T DATE NOT NULL, + PRIMARY KEY (sku_1c_id, T) + ); + ;WITH recur AS ( + SELECT fd.sku_1c_id, fd.T + FROM #first_def fd + WHERE fd.T IS NOT NULL + + UNION ALL + SELECT r.sku_1c_id, DATEADD(MONTH, @cover_months, r.T) + FROM recur r + WHERE DATEADD(MONTH, @cover_months, r.T) < @to_month_excl + ) + INSERT INTO #anchors(sku_1c_id, T) + SELECT sku_1c_id, T + FROM recur + OPTION (MAXRECURSION 32767); + + /* 9) Подготовка строк к вставке (размер заказа = прогноз окна) */ + IF OBJECT_ID('tempdb..#rows_to_insert') IS NOT NULL DROP TABLE #rows_to_insert; + CREATE TABLE #rows_to_insert ( + [scenario_id] INT, + [group_name] NVARCHAR(255), + [1c_id] BINARY(16), + [code] NVARCHAR(36), + [place_month] DATE, + [arrival_month] DATE, + [demand_window_C] DECIMAL(18,3), + [projected_stock_at_T] DECIMAL(18,3), + [order_qty] DECIMAL(18,3) + ); + + ;WITH base AS ( + SELECT + s.sku_1c_id, + s.code, + a.T, + st.qty AS stock0, + + /* прогноз окна [T .. T+C) */ + (SELECT SUM(demand_m) + FROM #tl z + WHERE z.sku_1c_id = s.sku_1c_id + AND z.[month] >= a.T + AND z.[month] < DATEADD(MONTH, @cover_months, a.T) + ) AS demand_window, + + /* кумулятивы до T-1 (обслуженный спрос и приход) */ + (SELECT TOP (1) z.cum_i + FROM #tl z + WHERE z.sku_1c_id = s.sku_1c_id + AND z.[month] < a.T + ORDER BY z.[month] DESC + ) AS cum_i_before, + + (SELECT TOP (1) z.cum_d + FROM #tl z + WHERE z.sku_1c_id = s.sku_1c_id + AND z.[month] < a.T + ORDER BY z.[month] DESC + ) AS cum_d_before, + + /* приход именно в T */ + (SELECT SUM(inb_m) + FROM #tl z + WHERE z.sku_1c_id = s.sku_1c_id + AND z.[month] = a.T + ) AS inb_t + FROM #anchors a + JOIN #skus s ON s.sku_1c_id = a.sku_1c_id + JOIN #stock0 st ON st.sku_1c_id = s.sku_1c_id + ) + INSERT INTO #rows_to_insert + SELECT + @scenario_id, + @group_path, + b.sku_1c_id, + b.code, + DATEADD(MONTH, -@lead_time_m, b.T) AS place_month, + b.T AS arrival_month, + CAST(ISNULL(b.demand_window,0) AS DECIMAL(18,3)) AS demand_window_C, + + /* старт на T (после прихода T), снизу 0 */ + CAST( + CASE + WHEN ( ISNULL(b.stock0,0) + + ISNULL(b.cum_i_before,0) + + ISNULL(b.inb_t,0) + - ISNULL(b.cum_d_before,0) ) < 0 + THEN 0 + ELSE ( ISNULL(b.stock0,0) + + ISNULL(b.cum_i_before,0) + + ISNULL(b.inb_t,0) + - ISNULL(b.cum_d_before,0) ) + END + AS DECIMAL(18,3)) AS projected_stock_at_T, + + /* размер заказа = прогноз окна */ + CAST(ISNULL(b.demand_window,0) AS DECIMAL(18,3)) AS order_qty + FROM base AS b; + + /* 10) Вставка рекомендаций (незначащие — отбрасываем) */ + INSERT INTO [analytics].[deficit_proposal] + ([scenario_id], [group_name], [1c_id], [code], + [place_month], [arrival_month], + [demand_window_C], [projected_stock_at_T], [order_qty], + [updated_at]) + SELECT + scenario_id, group_name, [1c_id], [code], + [place_month], [arrival_month], + [demand_window_C], [projected_stock_at_T], [order_qty], + GETDATE() + FROM #rows_to_insert + WHERE [order_qty] > 0; + + /* 11) Отладка по желанию */ + IF @debug = 1 + BEGIN + SELECT TOP (200) + r.[code], r.[arrival_month], r.[place_month], + r.[projected_stock_at_T], r.[demand_window_C], r.[order_qty] + FROM #rows_to_insert r + ORDER BY r.[arrival_month], r.[code]; + END +END +GO + +/****** Object: StoredProcedure [analytics].[sp_build_forecast_s4_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_build_forecast_s4_by_group] + @path NVARCHAR(255), -- путь группы (например, N'Игрушки') + @from_month DATE = NULL, -- по умолчанию: 1-е число текущего месяца + @to_month_excl DATE = '2028-01-01', -- полуинтервал [from, to) + @scenario_id INT = 4, + @allow_fallback_all BIT = 0 -- 1 = если группа не найдена/пустая → считать весь каталог с дефолтной сезонностью +AS +BEGIN + SET NOCOUNT ON; + + ---------------------------------------------------------------- + -- Нормализация пути: убираем лишние кавычки и пробелы + ---------------------------------------------------------------- + SET @path = LTRIM(RTRIM(REPLACE(@path, '''', N''))); + + IF @from_month IS NULL + SET @from_month = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1); + + ---------------------------------------------------------------- + -- Идентификаторы групп для сезонности + ---------------------------------------------------------------- + DECLARE @season_group_id BINARY(16) = NULL; + DECLARE @DEFAULT_GROUP_ID BINARY(16) = 0x00000000000000000000000000000000; + + -- Пытаемся найти группу ровно по path + SELECT @season_group_id = g.[1c_id] + FROM [pbi].[groups] g + WHERE g.[path] = @path; + + -- Если нет точного совпадения, ищем верхний узел, начинающийся с @path + IF @season_group_id IS NULL + BEGIN + SELECT TOP (1) @season_group_id = g.[1c_id] + FROM [pbi].[groups] g + WHERE g.[path] LIKE @path + N'%' + ORDER BY g.[lvl] ASC; + END + + -- Если группу так и не нашли: по умолчанию НЕ уходим на весь каталог (защита от опечаток) + IF @season_group_id IS NULL AND @allow_fallback_all = 0 + BEGIN + RAISERROR (N'Группа с path = %s не найдена. Проверьте параметр @path или запустите с @allow_fallback_all=1 для расчёта по всему каталогу.', 16, 1, @path); + RETURN; + END + + -- Если всё-таки нужно фолбэкнуть на дефолтную сезонность + IF @season_group_id IS NULL AND @allow_fallback_all = 1 + SET @season_group_id = @DEFAULT_GROUP_ID; + + ---------------------------------------------------------------- + -- TEMP: календарь месяцев [from, to) + ---------------------------------------------------------------- + IF OBJECT_ID('tempdb..#cal') IS NOT NULL DROP TABLE #cal; + CREATE TABLE #cal (month_start DATE NOT NULL PRIMARY KEY); + + ;WITH cal AS ( + SELECT @from_month AS month_start + UNION ALL + SELECT DATEADD(MONTH, 1, month_start) + FROM cal + WHERE month_start < DATEADD(MONTH, -1, @to_month_excl) + ) + INSERT INTO #cal(month_start) + SELECT month_start FROM cal + OPTION (MAXRECURSION 32767); + + ---------------------------------------------------------------- + -- TEMP: SKU под деревом @path; если пусто и разрешён фолбэк → все SKU + ---------------------------------------------------------------- + IF OBJECT_ID('tempdb..#skus') IS NOT NULL DROP TABLE #skus; + CREATE TABLE #skus ( + sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, + code NVARCHAR(36) NULL + ); + + INSERT INTO #skus(sku_1c_id, code) + SELECT n.[1c_id], n.[code] + FROM [pbi].[nomenclature] n + JOIN [pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE g.[path] LIKE @path + N'%' + OPTION (RECOMPILE); + + IF NOT EXISTS (SELECT 1 FROM #skus) + BEGIN + IF @allow_fallback_all = 1 + BEGIN + INSERT INTO #skus(sku_1c_id, code) + SELECT n.[1c_id], n.[code] + FROM [pbi].[nomenclature] n; + SET @season_group_id = @DEFAULT_GROUP_ID; + END + ELSE + BEGIN + RAISERROR (N'По path = %s не найдено ни одного SKU. Расчёт не выполнялся.', 16, 1, @path); + RETURN; + END + END + + ---------------------------------------------------------------- + -- TEMP: ставки продаж (шт/день) + ---------------------------------------------------------------- + IF OBJECT_ID('tempdb..#rate') IS NOT NULL DROP TABLE #rate; + CREATE TABLE #rate ( + sku_1c_id BINARY(16) NOT NULL PRIMARY KEY, + rate_per_day DECIMAL(38,6) NOT NULL + ); + + INSERT INTO #rate(sku_1c_id, rate_per_day) + SELECT a.[1c_id], ISNULL(a.[Продажи шт / день],0) + FROM [analytics].[аналитика за 365 дн.] a + JOIN #skus s ON s.sku_1c_id = a.[1c_id]; + + ---------------------------------------------------------------- + -- TEMP: сезонность ТОЛЬКО по @season_group_id; если нет строк — используем дефолт + ---------------------------------------------------------------- + IF OBJECT_ID('tempdb..#season') IS NOT NULL DROP TABLE #season; + CREATE TABLE #season ( + [month] TINYINT NOT NULL PRIMARY KEY, -- 1..12 + seasonal_koef DECIMAL(18,6) NOT NULL + ); + + INSERT INTO #season([month], seasonal_koef) + /*SELECT sg.[month], sg.[seasonal_koef] + FROM [analytics].[seasonality_groups] sg + WHERE sg.[group_1c_id] = @season_group_id;*/ + + SELECT + [month] + , AVG([koef]) + FROM [mag_pbi].[analytics].[seasonality_groups_summ_1] + GROUP BY [month]; + + /*IF @@ROWCOUNT = 0 + BEGIN + INSERT INTO #season([month], seasonal_koef) + SELECT sg.[month], sg.[seasonal_koef] + FROM [analytics].[seasonality_groups] sg + WHERE sg.[group_1c_id] = @DEFAULT_GROUP_ID; + -- если и дефолта нет, #season останется пустой → в формуле будет 1.0 + END + */ + ---------------------------------------------------------------- + -- Удаляем старые строки сценария (батчами, чтобы не держать тяжёлые блокировки) + ---------------------------------------------------------------- + WHILE 1 = 1 + BEGIN + DELETE TOP (50000) f + FROM [analytics].[forecast] f + JOIN #skus s ON s.sku_1c_id = f.[1c_id] + WHERE f.[scenario_id] = @scenario_id + AND f.[month] >= @from_month + AND f.[month] < @to_month_excl; + + IF @@ROWCOUNT = 0 BREAK; + END + + ---------------------------------------------------------------- + -- Вставка прогноза: rate_per_day × дни_в_месяце × seasonal_koef(@path/@default) + ---------------------------------------------------------------- + INSERT INTO [analytics].[forecast] + ([scenario_id], [1c_id], [code], [month], [value], [updated_at], [updated_by]) + SELECT + @scenario_id, + s.sku_1c_id, + s.code, + c.month_start, + CAST(ISNULL(r.rate_per_day, 0) + * DAY(EOMONTH(c.month_start)) + * ISNULL(se.seasonal_koef, 1.0) AS DECIMAL(18,3)) AS value, + GETDATE(), + SUSER_SNAME() + FROM #skus s + CROSS JOIN #cal c + LEFT JOIN #rate r ON r.sku_1c_id = s.sku_1c_id + LEFT JOIN #season se ON se.[month] = MONTH(c.month_start) + OPTION (RECOMPILE); +END +GO + +/****** Object: StoredProcedure [analytics].[sp_create_analytics_365] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_create_analytics_365] +AS +BEGIN + /* + ... твой закомментированный блок без изменений ... + */ + + ------------------------------------------------------------- + -- 1) Базовая таблица аналитики за 365 дней + ------------------------------------------------------------- + DROP TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + + SELECT + s.[1c_id], + s.Code, + SUM(s.Количество) as [Продано шт] + INTO [mag_pbi].[analytics].[аналитика за 365 дн.] + FROM [pbiProd].[СводныйСебестоимость Для PBI] s + WHERE s.Статья = N'Реализация' + AND s.[Период] >= DATEADD(day, -365, GETDATE()) + GROUP BY [1c_id], s.Code; + + + ------------------------------------------------------------- + -- 2) Продажи шт / день + ------------------------------------------------------------- + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'Продажи шт / день') IS NULL + BEGIN + ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [Продажи шт / день] numeric(38,6) NULL; + /*ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [Продажи шт / день опт] numeric(38,6) NULL;*/ + END; + + ;WITH bounds AS ( + SELECT + CAST(DATEADD(day, -365, CAST(GETDATE() AS date)) AS date) AS start_date, + CAST(GETDATE() AS date) AS end_date + ), + days365 AS ( + SELECT + t.[_IDRREF] AS [1c_id], + SUM(t.[ostatok]) AS days_on_sale_365 + --SUM(t.[ostatok10]) AS days_on_sale_365_opt + FROM [pbi].[w_ostatok_da_net] t + CROSS JOIN bounds b + WHERE t.[dt] >= b.start_date + AND t.[dt] < b.end_date -- исключаем текущий день + GROUP BY t.[_IDRREF] + ) + UPDATE a + SET + + [Продажи шт / день] = + CASE + WHEN d.days_on_sale_365 > 0 + THEN CAST(a.[Продано шт] AS numeric(38,6)) / CAST(d.days_on_sale_365 AS numeric(38,6)) + ELSE NULL + END + + /*[Продажи шт / день опт] = + CASE + WHEN d.days_on_sale_365_opt > 0 + THEN CAST(a.[Продано шт] AS numeric(38,6)) / CAST(d.days_on_sale_365_opt AS numeric(38,6)) + ELSE NULL + END*/ + + FROM [analytics].[аналитика за 365 дн.] a + LEFT JOIN days365 d + ON d.[1c_id] = a.[1c_id]; + + + + ------------------------------------------------------------- + -- 3) Остаток дней продаж + ------------------------------------------------------------- + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'Остаток дней продаж') IS NULL + BEGIN + ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [Остаток дней продаж] numeric(38,6) NULL; + /*ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [Остаток дней продаж опт] numeric(38,6) NULL;*/ + END; + + UPDATE a + SET + [Остаток дней продаж] = + CASE + WHEN a.[Продажи шт / день] > 0 + THEN sb.[Остаток склад + МП, шт] / a.[Продажи шт / день] + ELSE NULL + END + + /*[Остаток дней продаж опт] = + CASE + WHEN a.[Продажи шт / день опт] > 0 + THEN sb.[Остаток склад + МП, шт] / a.[Продажи шт / день опт] + ELSE NULL + END*/ + FROM [analytics].[аналитика за 365 дн.] a + LEFT JOIN ( + SELECT + n.[1c_id], + s.[Остаток склад + МП, шт] + FROM [mag_pbi].[analytics].[stock_balance] s + INNER JOIN [mag_pbi].[pbi].[nomenclature] n + ON n.artic_id = s.artic_id + ) sb + ON sb.[1c_id] = a.[1c_id]; + + + + + ------------------------------------------------------------- + -- 4) Сумма продаж, учетка, ТН (год) + ------------------------------------------------------------- + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'Продажи / год, руб.') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Продажи / год, руб.] decimal(38,2) NULL; + END; + + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'учетная сумма / год, руб.') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [учетная сумма / год, руб.] decimal(38,2) NULL; + END; + + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'ТН / год, руб.') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [ТН / год, руб.] decimal(38,2) NULL; + END; + + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'Стоимость МП год, руб.') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Стоимость МП год, руб.] decimal(38,2) NULL; + END; + + IF COL_LENGTH('analytics.аналитика за 365 дн.', '%ТН год, руб.') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [%ТН год, руб.] decimal(38,2) NULL; + END; + + DECLARE @end date = CAST(GETDATE() AS date); -- сегодня (не включаем) + DECLARE @start date = DATEADD(day, -365, @end); -- 365 дней назад + + ;WITH Y AS ( + SELECT + v.[1c_id], + SUM(v.[Сумма продаж]) AS sales_year, + SUM(v.[Учетная сумма]) AS acct_year, + SUM(v.[Стоимость обработки]) AS cost_mp, + SUM(v.[Торговая надбавка]) AS tn_year + FROM [analytics].[Продажи_Учёт_Маржа_по_дням] v + WHERE v.[d] >= @start AND v.[d] < @end + GROUP BY v.[1c_id] + ) + UPDATE a + SET + a.[Продажи / год, руб.] = COALESCE(Y.sales_year, 0), + a.[учетная сумма / год, руб.] = COALESCE(Y.acct_year, 0), + a.[ТН / год, руб.] = COALESCE(Y.tn_year, 0), + a.[Стоимость МП год, руб.] = COALESCE(Y.cost_mp, 0), + a.[%ТН год, руб.] = CASE + WHEN NULLIF(COALESCE(Y.acct_year, 0), 0) IS NULL THEN NULL + ELSE + CAST(COALESCE(Y.tn_year, 0) AS decimal(19,6)) + / CAST(NULLIF(Y.acct_year, 0) AS decimal(19,6)) + END + FROM [mag_pbi].[analytics].[аналитика за 365 дн.] AS a + LEFT JOIN Y + ON Y.[1c_id] = a.[1c_id]; + + + ------------------------------------------------------------- + -- 5) Дней в продаже / год и / квартал + ------------------------------------------------------------- + SET @end = CAST(GETDATE() AS date); + + DECLARE @startY date = DATEADD(day, -365, @end); + DECLARE @startQ date = DATEADD(month, -3, @end); + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Дней в продаже / год') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Дней в продаже / год] bigint NULL; + END; + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Дней в продаже / квартал') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Дней в продаже / квартал] bigint NULL; + END; + + ;WITH daysY AS ( + SELECT [_IDRREF] AS [1c_id], + COUNT_BIG(*) AS days_in_sale_year + FROM [pbi].[w_ostatok_da_net] + WHERE [dt] >= @startY AND [dt] < @end + AND [ostatok] >= 1 + GROUP BY [_IDRREF] + ), + daysQ AS ( + SELECT [_IDRREF] AS [1c_id], + COUNT_BIG(*) AS days_in_sale_quarter + FROM [pbi].[w_ostatok_da_net] + WHERE [dt] >= @startQ AND [dt] < @end + AND [ostatok] >= 1 + GROUP BY [_IDRREF] + ), + days AS ( + SELECT COALESCE(y.[1c_id], q.[1c_id]) AS [1c_id], + y.days_in_sale_year, + q.days_in_sale_quarter + FROM daysY y + FULL OUTER JOIN daysQ q ON q.[1c_id] = y.[1c_id] + ) + UPDATE a + SET + a.[Дней в продаже / год] = d.days_in_sale_year, + a.[Дней в продаже / квартал] = d.days_in_sale_quarter + FROM [mag_pbi].[analytics].[аналитика за 365 дн.] a + LEFT JOIN days d + ON d.[1c_id] = a.[1c_id]; + + ------------------------------------------------------------- + -- 6) Сумма продаж, учетка, ТН (квартал) + ------------------------------------------------------------- + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'Продажи / квартал, руб.') IS NULL + BEGIN + ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [Продажи / квартал, руб.] decimal(38,2) NULL; + END; + + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'учетная сумма / квартал, руб.') IS NULL + BEGIN + ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [учетная сумма / квартал, руб.] decimal(38,2) NULL; + END; + + IF COL_LENGTH('analytics.аналитика за 365 дн.', 'ТН / квартал, руб.') IS NULL + BEGIN + ALTER TABLE [analytics].[аналитика за 365 дн.] + ADD [ТН / квартал, руб.] decimal(38,2) NULL; + END; + + SET @start = DATEADD(month, -3, @end); + + ;WITH Q AS ( + SELECT + v.[1c_id], + SUM(v.[Сумма продаж]) AS sales_q, + SUM(v.[Учетная сумма]) AS acct_q, + SUM(v.[Торговая надбавка]) AS tn_q + FROM [analytics].[Продажи_Учёт_Маржа_по_дням] v + WHERE v.[d] >= @start AND v.[d] < @end + GROUP BY v.[1c_id] + ) + UPDATE a + SET + a.[Продажи / квартал, руб.] = Q.sales_q, + a.[учетная сумма / квартал, руб.] = Q.acct_q, + a.[ТН / квартал, руб.] = Q.tn_q + FROM [analytics].[аналитика за 365 дн.] AS a + LEFT JOIN Q + ON Q.[1c_id] = a.[1c_id]; + + + ------------------------------------------------------------- + -- 7) ТН / месяц (по текущей скорости) + ------------------------------------------------------------- + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'ТН / месяц, руб.') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [ТН / месяц, руб.] decimal(38,6) NULL; + END; + + UPDATE a + SET a.[ТН / месяц, руб.] = + ISNULL(a.[ТН / год, руб.], 0) + / NULLIF(a.[Продано шт], 0) + * ISNULL(a.[Продажи шт / день], 0) + * 30 + FROM [mag_pbi].[analytics].[аналитика за 365 дн.] a; + + + ------------------------------------------------------------------------------------- + -- 8) ДОПОЛНИТЕЛЬНО: Оплаченный остаток и рентабельности (ROIC и по остатку в руб.) + -- (год назад, квартал назад и на будущий год) по 12-месячному окну + ------------------------------------------------------------------------------------- + + -- новые колонки + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Оплаченный остаток') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Оплаченный остаток] decimal(38,2) NULL; + END; + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Рентабельность / год') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Рентабельность / год] decimal(38,6) NULL; + END; + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Рентабельность / квартал') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Рентабельность / квартал] decimal(38,6) NULL; + END; + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Рентабельность / будущий год') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Рентабельность / будущий год] decimal(38,6) NULL; + END; + + -- новые поля рентабельности по остатку в рублях (сразу в %) + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Рентабельность по остатку / год') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Рентабельность по остатку / год] decimal(38,6) NULL; + END; + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Рентабельность по остатку / квартал') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Рентабельность по остатку / квартал] decimal(38,6) NULL; + END; + + IF COL_LENGTH('mag_pbi.analytics.аналитика за 365 дн.', 'Рентабельность по остатку / будущий год') IS NULL + BEGIN + ALTER TABLE [mag_pbi].[analytics].[аналитика за 365 дн.] + ADD [Рентабельность по остатку / будущий год] decimal(38,6) NULL; + END; + + --------------------------------------------------------- + -- 8.1 Окно 12 полных месяцев + --------------------------------------------------------- + DECLARE @mp_today date = CAST(GETDATE() AS date); + DECLARE @mp_lastFullMonth date = EOMONTH(DATEADD(month, -1, @mp_today)); + DECLARE @mp_firstMonthStart date = DATEADD( + month, -11, + DATEFROMPARTS(YEAR(@mp_lastFullMonth), MONTH(@mp_lastFullMonth), 1) + ); + DECLARE @mp_curMonthStart date = @mp_firstMonthStart; + + IF OBJECT_ID('tempdb..#mp_months') IS NOT NULL DROP TABLE #mp_months; + CREATE TABLE #mp_months ( + MonthStart date NOT NULL PRIMARY KEY + ); + + WHILE @mp_curMonthStart <= DATEFROMPARTS(YEAR(@mp_lastFullMonth), MONTH(@mp_lastFullMonth), 1) + BEGIN + INSERT INTO #mp_months (MonthStart) VALUES (@mp_curMonthStart); + SET @mp_curMonthStart = DATEADD(month, 1, @mp_curMonthStart); + END; + + --------------------------------------------------------- + -- 8.2 Набор SKU из аналитики 365 + --------------------------------------------------------- + IF OBJECT_ID('tempdb..#mp_s') IS NOT NULL DROP TABLE #mp_s; + CREATE TABLE #mp_s( + [1c_id] binary(16) NOT NULL, + code nchar(11) NOT NULL, + CONSTRAINT PK_mp_s PRIMARY KEY ([1c_id], code) + ); + + INSERT INTO #mp_s([1c_id], code) + SELECT DISTINCT a.[1c_id], a.[Code] + FROM [mag_pbi].[analytics].[аналитика за 365 дн.] a; + + --------------------------------------------------------- + -- 8.3 Внешние остатки + --------------------------------------------------------- + IF OBJECT_ID('tempdb..#mp_ext_stock') IS NOT NULL DROP TABLE #mp_ext_stock; + CREATE TABLE #mp_ext_stock( + Dt date NOT NULL, + code nchar(11) NOT NULL, + qty numeric(18,3) NOT NULL, + CONSTRAINT PK_mp_ext_stock PRIMARY KEY (Dt, code) + ); + + INSERT INTO #mp_ext_stock (Dt, code, qty) + SELECT + CAST(o.[Дата обновления] AS date) AS Dt, + o.code, + SUM(o.[Количество]) AS qty + FROM analytics.[Внешние остатки] o + JOIN #mp_s s + ON s.code = o.code + GROUP BY CAST(o.[Дата обновления] AS date), o.code; + + --------------------------------------------------------- + -- 8.4 Приходы (Закупка / Приход) + --------------------------------------------------------- + IF OBJECT_ID('tempdb..#mp_incoming') IS NOT NULL DROP TABLE #mp_incoming; + CREATE TABLE #mp_incoming( + MonthStart date NOT NULL, + [1c_id] binary(16) NOT NULL, + qty numeric(18,3) NOT NULL, + CONSTRAINT PK_mp_incoming PRIMARY KEY (MonthStart, [1c_id]) + ); + + INSERT INTO #mp_incoming (MonthStart, [1c_id], qty) + SELECT + DATEFROMPARTS(YEAR(s.[Период]), MONTH(s.[Период]), 1) AS MonthStart, + s.[1c_id], + SUM(s.[Количество]) AS qty + FROM pbiProd.[СводныйСебестоимость Для PBI] s + JOIN #mp_s sf + ON sf.[1c_id] = s.[1c_id] + WHERE s.[Статья] = N'Закупка' + AND s.[Вид операции] = N'Приход' + AND s.[Период] >= @mp_firstMonthStart + GROUP BY + DATEFROMPARTS(YEAR(s.[Период]), MONTH(s.[Период]), 1), + s.[1c_id]; + + --------------------------------------------------------- + -- 8.5 Обязательства по месяцам + --------------------------------------------------------- + IF OBJECT_ID('tempdb..#mp_obligations') IS NOT NULL DROP TABLE #mp_obligations; + CREATE TABLE #mp_obligations( + MonthStart date NOT NULL, + [1c_id] binary(16) NOT NULL, + obligation numeric(18,2) NOT NULL, + CONSTRAINT PK_mp_obligations PRIMARY KEY (MonthStart, [1c_id]) + ); + + -- 8.5 Обязательства: считаем по manufacturer_payment_stage (поддержка 2, 3 и более этапов) + -- Этап «оплачен», если конец месяца M >= дата прихода + days. Сумма этапа = full_sum * percent/100. + -- Два шага через CTE, чтобы избежать Msg 8124 (correlated subquery с несколькими внешними ссылками). + ;WITH base_oblig AS ( + SELECT + m.MonthStart, + inc.MonthStart AS inc_month, + inc.[1c_id], + inc.qty * n2.[Цена учетная, руб] AS full_sum, + EOMONTH(inc.MonthStart) AS inc_eom, + EOMONTH(m.MonthStart) AS eval_eom, + man.id AS manufacturer_id + FROM #mp_months m + JOIN #mp_incoming inc ON 1 = 1 + JOIN pbi.nomenclature n2 ON n2.[1c_id] = inc.[1c_id] + LEFT JOIN analytics.manufacturers man ON man.[manufacturer] = n2.Производитель + ), + oblig_with_paid AS ( + SELECT + b.MonthStart, + b.eval_eom, + b.inc_eom, + b.[1c_id], + b.full_sum, + ISNULL(SUM( + CASE WHEN b.eval_eom >= DATEADD(day, st.[days], b.inc_eom) + THEN b.full_sum * st.[percent] / 100.0 ELSE 0 END + ), 0) AS paid_to_month + FROM base_oblig b + LEFT JOIN analytics.manufacturer_payment_stage st ON st.manufacturer_id = b.manufacturer_id + GROUP BY b.MonthStart, b.inc_month, b.[1c_id], b.full_sum, b.eval_eom, b.inc_eom, b.manufacturer_id + ), + ObligRows AS ( + SELECT + MonthStart, + [1c_id], + CASE + WHEN eval_eom < inc_eom THEN 0 + WHEN full_sum - paid_to_month > 0 THEN full_sum - paid_to_month + ELSE 0 + END AS ObligationPerIncoming + FROM oblig_with_paid + ) + INSERT INTO #mp_obligations (MonthStart, [1c_id], obligation) + SELECT + MonthStart, + [1c_id], + SUM(ObligationPerIncoming) AS obligation + FROM ObligRows + GROUP BY + MonthStart, + [1c_id]; + + --------------------------------------------------------- + -- 8.6 ТН по месяцам + --------------------------------------------------------- + IF OBJECT_ID('tempdb..#mp_tn_monthly') IS NOT NULL DROP TABLE #mp_tn_monthly; + + CREATE TABLE #mp_tn_monthly( + MonthStart date NOT NULL, + [1c_id] binary(16) NOT NULL, + tn_amount numeric(18,2) NULL, + CONSTRAINT PK_mp_tn_monthly PRIMARY KEY (MonthStart, [1c_id]) + ); + + INSERT INTO #mp_tn_monthly (MonthStart, [1c_id], tn_amount) + SELECT + DATEFROMPARTS(YEAR(p.[d]), MONTH(p.[d]), 1) AS MonthStart, + p.[1c_id], + SUM(ISNULL(p.[Торговая надбавка],0)) AS tn_amount + FROM [mag_pbi].[analytics].[Продажи_Учёт_Маржа_по_дням] p + JOIN #mp_s s + ON s.[1c_id] = p.[1c_id] + WHERE p.[d] >= @mp_firstMonthStart + AND p.[d] <= @mp_lastFullMonth + GROUP BY + DATEFROMPARTS(YEAR(p.[d]), MONTH(p.[d]), 1), + p.[1c_id]; + + --------------------------------------------------------- + -- 8.7 Помесячный план по всем SKU (остаток, оплаченный остаток, ТН, рубли-дни, остаток учетка руб) + --------------------------------------------------------- + IF OBJECT_ID('tempdb..#mp_plan') IS NOT NULL DROP TABLE #mp_plan; + + SELECT + s.[1c_id], + s.code, + m.MonthStart, + [Остаток шт] = + ISNULL(intStock.quantity, 0) + ISNULL(ext.qty, 0), + [Остаток учетка руб] = + (ISNULL(intStock.quantity, 0) + ISNULL(ext.qty, 0)) + * ISNULL(n.[Цена учетная, руб], 0), + [Оплаченный остаток] = + CAST( + CASE + WHEN paid_raw < 0 THEN 0 + ELSE paid_raw + END + AS decimal(18,2) + ), + [ТН] = ISNULL(tn.tn_amount, 0), + [рубли-дни] = + CAST( + CASE + WHEN paid_raw < 0 THEN 0 + ELSE paid_raw + END * DAY(EOMONTH(m.MonthStart)) + AS decimal(18,2) + ) + INTO #mp_plan + FROM #mp_months m + CROSS JOIN #mp_s s + OUTER APPLY ( + SELECT TOP (1) w1.quantity + FROM [mag_pbi].[pbi].[w_ostatok_da_net] w1 + WHERE w1._IDRREF = s.[1c_id] + AND w1.dt <= EOMONTH(m.MonthStart) + ORDER BY w1.dt DESC + ) AS intStock + LEFT JOIN #mp_ext_stock ext + ON ext.code = s.code + AND ext.Dt = EOMONTH(m.MonthStart) + LEFT JOIN #mp_obligations ob + ON ob.[1c_id] = s.[1c_id] + AND ob.MonthStart = m.MonthStart + LEFT JOIN [mag_pbi].[pbi].[nomenclature] n + ON n.[1c_id] = s.[1c_id] + LEFT JOIN #mp_tn_monthly tn + ON tn.[1c_id] = s.[1c_id] + AND tn.MonthStart = m.MonthStart + CROSS APPLY ( + SELECT + (ISNULL(intStock.quantity, 0) + ISNULL(ext.qty, 0)) + * ISNULL(n.[Цена учетная, руб], 0) + - ISNULL(ob.obligation, 0) AS paid_raw + ) p; + + --------------------------------------------------------- + -- 8.8 Агрегаты по SKU: ROIC (год/квартал/будущий) + рентабельность по остатку (год/квартал/будущий) + --------------------------------------------------------- + + -- старт квартала (последние 3 месяца окна) + DECLARE @mp_q_start date = DATEADD( + month, -2, + DATEFROMPARTS(YEAR(@mp_lastFullMonth), MONTH(@mp_lastFullMonth), 1) + ); + + ;WITH AggYear AS ( + SELECT + p.[1c_id], + tn_year = SUM(p.[ТН]), + rd_year = SUM(p.[рубли-дни]), + avg_cap_year = AVG(NULLIF(p.[Остаток учетка руб], 0.0)) + FROM #mp_plan p + GROUP BY p.[1c_id] + ), + AggQuarter AS ( + SELECT + p.[1c_id], + tn_q = SUM(p.[ТН]), + rd_q = SUM(p.[рубли-дни]), + avg_cap_q = AVG(NULLIF(p.[Остаток учетка руб], 0.0)) + FROM #mp_plan p + WHERE p.MonthStart >= @mp_q_start + GROUP BY p.[1c_id] + ), + RoicPast AS ( + SELECT + ay.[1c_id], + RoicValue = + CASE + WHEN ay.rd_year > 0 + THEN ay.tn_year * 365.0 / ay.rd_year * 100.0 + ELSE NULL + END, + ay.tn_year, + ay.avg_cap_year + FROM AggYear ay + ), + RoicQuarterPast AS ( + SELECT + aq.[1c_id], + RoicQ = + CASE + WHEN aq.rd_q > 0 + THEN aq.tn_q * 365.0 / aq.rd_q * 100.0 + ELSE NULL + END, + aq.tn_q, + aq.avg_cap_q + FROM AggQuarter aq + ), + LastRow AS ( + SELECT + p.[1c_id], + p.[Оплаченный остаток], + p.[Остаток шт], + p.[Остаток учетка руб], + ROW_NUMBER() OVER ( + PARTITION BY p.[1c_id] + ORDER BY p.MonthStart DESC + ) AS rn + FROM #mp_plan p + ), + FutureBase AS ( + SELECT + a.[1c_id], + a.[Продажи шт / день] AS sales_per_day, + a.[Продано шт] AS sold_year, + a.[ТН / год, руб.] AS tn_year_hist, + lr.[Оплаченный остаток] AS paid_stock_now, + lr.[Остаток шт] AS q_stock, + lr.[Остаток учетка руб] AS stock_rub_now + FROM [mag_pbi].[analytics].[аналитика за 365 дн.] a + LEFT JOIN LastRow lr + ON lr.[1c_id] = a.[1c_id] + AND lr.rn = 1 + ), + FutureInputs AS ( + SELECT + f.[1c_id], + f.sales_per_day, + f.sold_year, + tn_year = COALESCE(f.tn_year_hist, rp.tn_year), + f.paid_stock_now, + f.q_stock, + f.stock_rub_now, + tn_per_unit = + CASE + WHEN f.sold_year > 0 AND COALESCE(f.tn_year_hist, rp.tn_year) IS NOT NULL + THEN COALESCE(f.tn_year_hist, rp.tn_year) / f.sold_year + ELSE NULL + END, + max_sell_1y = + CASE + WHEN f.sales_per_day IS NULL THEN NULL + ELSE f.sales_per_day * 365.0 + END + FROM FutureBase f + LEFT JOIN RoicPast rp + ON rp.[1c_id] = f.[1c_id] + ), + FutureCalc AS ( + SELECT + fi.[1c_id], + RoicFuture = + CASE + WHEN fi.paid_stock_now IS NULL OR fi.paid_stock_now <= 0 + OR fi.sales_per_day IS NULL OR fi.sales_per_day <= 0 + OR fi.tn_per_unit IS NULL + OR fi.q_stock IS NULL OR fi.q_stock <= 0 + OR fi.max_sell_1y IS NULL OR fi.max_sell_1y <= 0 + THEN NULL + ELSE + ( + ( + fi.tn_per_unit * + (CASE + WHEN fi.q_stock <= fi.max_sell_1y THEN fi.q_stock + ELSE fi.max_sell_1y + END) + ) * 365.0 + / + ( + CASE + WHEN fi.q_stock / fi.sales_per_day >= 365.0 + THEN fi.paid_stock_now * 365.0 + ELSE fi.paid_stock_now * (fi.q_stock / fi.sales_per_day) / 2.0 + END + ) * 100.0 + ) + END, + tn_future = + CASE + WHEN fi.tn_per_unit IS NULL OR fi.max_sell_1y IS NULL OR fi.q_stock IS NULL + THEN NULL + ELSE + fi.tn_per_unit * + (CASE + WHEN fi.q_stock <= fi.max_sell_1y THEN fi.q_stock + ELSE fi.max_sell_1y + END) + END, + q_future = + CASE + WHEN fi.max_sell_1y IS NULL OR fi.q_stock IS NULL THEN NULL + WHEN fi.q_stock <= fi.max_sell_1y THEN fi.q_stock + ELSE fi.max_sell_1y + END + FROM FutureInputs fi + ), + CapRentFuture AS ( + SELECT + fi.[1c_id], + RentCapFuturePct = + CASE + WHEN fc.tn_future IS NULL + OR fi.stock_rub_now IS NULL OR fi.stock_rub_now <= 0 + OR fi.q_stock IS NULL OR fi.q_stock <= 0 + OR fc.q_future IS NULL OR fc.q_future <= 0 + THEN NULL + ELSE + CASE + WHEN (fi.stock_rub_now * (1.0 - (fc.q_future / fi.q_stock) / 2.0)) <= 0 + THEN NULL + ELSE + fc.tn_future + / (fi.stock_rub_now * (1.0 - (fc.q_future / fi.q_stock) / 2.0)) + * 100.0 + END + END + FROM FutureInputs fi + LEFT JOIN FutureCalc fc + ON fc.[1c_id] = fi.[1c_id] + ) + UPDATE a + SET + a.[Рентабельность / год] = rp.RoicValue, + a.[Рентабельность / квартал] = rq.RoicQ, + a.[Оплаченный остаток] = lr.[Оплаченный остаток], + a.[Рентабельность / будущий год] = fc.RoicFuture, + a.[Рентабельность по остатку / год] = + CASE + WHEN rp.avg_cap_year IS NOT NULL AND rp.avg_cap_year > 0 + AND rp.tn_year IS NOT NULL + THEN (rp.tn_year / rp.avg_cap_year) * 100.0 + ELSE NULL + END, + a.[Рентабельность по остатку / квартал] = + CASE + WHEN rq.avg_cap_q IS NOT NULL AND rq.avg_cap_q > 0 + AND rq.tn_q IS NOT NULL + THEN (rq.tn_q / rq.avg_cap_q) * 100.0 + ELSE NULL + END, + a.[Рентабельность по остатку / будущий год] = cf.RentCapFuturePct + FROM [mag_pbi].[analytics].[аналитика за 365 дн.] a + LEFT JOIN RoicPast rp ON rp.[1c_id] = a.[1c_id] + LEFT JOIN RoicQuarterPast rq ON rq.[1c_id] = a.[1c_id] + LEFT JOIN LastRow lr ON lr.[1c_id] = a.[1c_id] AND lr.rn = 1 + LEFT JOIN FutureCalc fc ON fc.[1c_id] = a.[1c_id] + LEFT JOIN CapRentFuture cf ON cf.[1c_id] = a.[1c_id]; + + + ------------------------------------------------------------------------------------- + -- 9) Индекс (как был) + ------------------------------------------------------------------------------------- + CREATE NONCLUSTERED INDEX [analyticsаналитика за 365 дн.] + ON [analytics].[аналитика за 365 дн.] ([1c_id]) + INCLUDE ( + [Продажи шт / день], + [Остаток дней продаж], + [ТН / год, руб.], + [ТН / квартал, руб.], + [Рентабельность / год], + [Рентабельность / квартал], + [Дней в продаже / год], + [Дней в продаже / квартал] + ); +END +GO + +/****** Object: StoredProcedure [analytics].[sp_fill_deficit_money_request] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_fill_deficit_money_request] + @scenario_id INT = NULL -- NULL = MAX(scenario_id) из deficit_proposal +AS +SET NOCOUNT ON; + +DECLARE @scenario INT; + +IF @scenario_id IS NOT NULL AND @scenario_id > 0 + SET @scenario = @scenario_id; +ELSE + SET @scenario = (SELECT MAX(scenario_id) FROM [analytics].[deficit_proposal]); + +IF @scenario IS NULL +BEGIN + RAISERROR(N'Нет данных в deficit_proposal. Выполните sp_build_deficit_proposal.', 16, 1); + RETURN; +END + +-- Очищаем таблицу для данного сценария +DELETE FROM [analytics].[deficit_money_request] WHERE scenario_id = @scenario; + +-- Заполняем: дефицит -> номенклатура (производитель, цена) -> manufacturers -> контрагент +-- Номенклатура: pbi.v_nomenclature_full содержит все коды, Производитель, учётную цену +INSERT INTO [analytics].[deficit_money_request] ( + scenario_id, + manufacturer_id, + contractor_1c_id, + manufacturer_name, + contractor_name, + arrival_month, + amount_rub, + amount_usd, + currency, + order_qty_total, + sku_count, + updated_at +) +SELECT + @scenario AS scenario_id, + m.id AS manufacturer_id, + mcm.contractor_1c_id, + m.manufacturer AS manufacturer_name, + c.contractor_name, + CAST(FORMAT(dp.arrival_month, 'yyyy-MM-01') AS date) AS arrival_month, + SUM(dp.order_qty * ISNULL(n.[Цена учетная, руб], 0)) AS amount_rub, + SUM(dp.order_qty * ISNULL(n.[Цена учетная, usd], 0)) AS amount_usd, + CASE + WHEN SUM(dp.order_qty * ISNULL(n.[Цена учетная, usd], 0)) > + SUM(dp.order_qty * ISNULL(n.[Цена учетная, руб], 0)) * 0.01 + THEN N'USD' ELSE N'руб.' + END AS currency, + SUM(dp.order_qty) AS order_qty_total, + COUNT(DISTINCT dp.code) AS sku_count, + SYSDATETIME() AS updated_at +FROM [analytics].[deficit_proposal] dp +-- Номенклатура: все коды, производитель и учётная цена (без фильтра по группе) +INNER JOIN [mag_pbi].[pbi].[v_nomenclature_full] n + ON n.[code] = dp.code +-- Производитель: сопоставление по имени (LTRIM/RTRIM как в contractorProducer) +INNER JOIN [analytics].[manufacturers] m + ON LTRIM(RTRIM(ISNULL(n.[Производитель], N''))) = LTRIM(RTRIM(m.manufacturer)) + AND LTRIM(RTRIM(ISNULL(n.[Производитель], N''))) <> N'' +LEFT JOIN [analytics].[manufacturer_counterparty_map] mcm + ON mcm.manufacturer_id = m.id +LEFT JOIN [analytics].[v_contractors] c + ON c.contractor_1c_id = mcm.contractor_1c_id +WHERE dp.scenario_id = @scenario + AND dp.order_qty > 0 + AND (n.[Цена учетная, руб] IS NOT NULL OR n.[Цена учетная, usd] IS NOT NULL) +GROUP BY + m.id, + mcm.contractor_1c_id, + m.manufacturer, + c.contractor_name, + CAST(FORMAT(dp.arrival_month, 'yyyy-MM-01') AS date); + +-- Логируем результат +DECLARE @rows INT = @@ROWCOUNT; +PRINT CONCAT(N'analytics.sp_fill_deficit_money_request: внесено ', @rows, N' записей для scenario_id=', @scenario); +GO + +/****** Object: StoredProcedure [analytics].[sp_load_koef_groups] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_load_koef_groups] as BEGIN + +Print('Запускайте код процедуры руками') +RETURN 0 + +DROP TABLE #koef + +CREATE TABLE #koef ( + [group_1c_id] nvarchar(256) NOT NULL, + [seasonal_koef] [decimal](18, 6) NOT NULL, + [month] int NOT NULL +); + +BULK INSERT #koef +FROM '\\192.168.35.3\admin3\Обмен\powerbi\k1.csv' +WITH ( + FIRSTROW = 2, -- пропустить заголовок + FIELDTERMINATOR = ';', + ROWTERMINATOR = '\n', + CODEPAGE = '1251' -- если кириллица +); + + +-- Проверить наличие данных во вр таблице +select top 100 * from #koef + + +--DELETE FROM [analytics].[seasonality_groups] +INSERT INTO [analytics].[seasonality_groups] +SELECT + g.[1c_id], + k.month, + k.seasonal_koef +FROM #koef k +INNER JOIN pbi.groups g + ON g.[1c_id]=k.group_1c_id + + + + ------------------------------ + SET NOCOUNT ON; + +------------------------------------------------------------ +-- 1. Таблица месяцев 1..12 +------------------------------------------------------------ +IF OBJECT_ID('tempdb..#Months') IS NOT NULL DROP TABLE #Months; + +CREATE TABLE #Months ( + [month] tinyint NOT NULL PRIMARY KEY +); + +INSERT INTO #Months ([month]) +VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); + + +------------------------------------------------------------ +-- 2. База продаж 2024–2025 по g–g1 × месяц +------------------------------------------------------------ +IF OBJECT_ID('tempdb..#SalesByGroupMonth') IS NOT NULL DROP TABLE #SalesByGroupMonth; + +SELECT + g.[g], + g.[g1], + [month] = MONTH(s.[Период]), + qty = /* SUM(s.Сумма) */ SUM(s.[Количество]) +INTO #SalesByGroupMonth +FROM [mag_pbi].[pbiProd].[СводныйСебестоимость Для PBI] AS s + INNER JOIN [pbi].[nomenclature] n + ON n.[1c_id] = s.[1c_id] + INNER JOIN [pbi].[groups] g + ON g.[1c_id] = n.[1c_group] +WHERE + s.[Статья] = N'Реализация' + AND s.[Период] >= '2023-12-01' + AND s.[Период] < '2025-12-01' + AND g.[g] NOT LIKE N'*%' +GROUP BY + g.[g], + g.[g1], + MONTH(s.[Период]); + + +------------------------------------------------------------ +-- 3. Список всех g–g1, которые продавались +------------------------------------------------------------ +IF OBJECT_ID('tempdb..#GroupList') IS NOT NULL DROP TABLE #GroupList; + +SELECT DISTINCT + sbgm.[g], + sbgm.[g1] +INTO #GroupList +FROM #SalesByGroupMonth sbgm; + + +------------------------------------------------------------ +-- 4. g–g1 × все 12 месяцев (qty = 0, если продаж не было) +------------------------------------------------------------ +IF OBJECT_ID('tempdb..#AllGroupMonths') IS NOT NULL DROP TABLE #AllGroupMonths; + +SELECT + gl.[g], + gl.[g1], + m.[month], + qty = ISNULL(sbgm.qty, 0) +INTO #AllGroupMonths +FROM #GroupList gl +CROSS JOIN #Months m +LEFT JOIN #SalesByGroupMonth sbgm + ON sbgm.[g] = gl.[g] + AND sbgm.[g1] = gl.[g1] + AND sbgm.[month] = m.[month]; + + +------------------------------------------------------------ +-- 5. Общий объём продаж по g–g1 за все 12 месяцев +------------------------------------------------------------ +IF OBJECT_ID('tempdb..#GroupTotals') IS NOT NULL DROP TABLE #GroupTotals; + +SELECT + agm.[g], + agm.[g1], + total_qty = SUM(agm.qty) +INTO #GroupTotals +FROM #AllGroupMonths agm +GROUP BY + agm.[g], + agm.[g1]; + + +------------------------------------------------------------ +-- 6. Финальный результат: g, g1, koef, month +-- Сумма koef по 12 месяцам для каждого g–g1 = 1 +------------------------------------------------------------ +SELECT + agm.[g], + agm.[g1], + agm.[month], + koef = CASE + WHEN gt.total_qty = 0 THEN 0 + ELSE CAST(agm.qty AS decimal(18,6)) / NULLIF(gt.total_qty, 0) + END +--INTO analytics .seasonality_groups_summ_1 +FROM #AllGroupMonths agm +INNER JOIN #GroupTotals gt + ON gt.[g] = agm.[g] + AND gt.[g1] = agm.[g1] +ORDER BY + agm.[g], + agm.[g1], + agm.[month]; + +END +GO + +/****** Object: StoredProcedure [analytics].[sp_rebuild_stock_plan_by_arrival] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_rebuild_stock_plan_by_arrival] + @scenario_id INT, + @from_month DATE, -- например: DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1) + @to_month DATE -- последний месяц горизонта + 1 день (интервал [from, to) по месяцам) +AS +BEGIN + SET NOCOUNT ON; + + -- Безопасная рамка + IF @from_month IS NULL SET @from_month = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1); + IF @to_month IS NULL SET @to_month = DATEADD(MONTH, 12, @from_month); -- 12 мес по умолчанию + + -- Чистим целевой диапазон + DELETE FROM [analytics].[stock_plan_by_arrival] + WHERE [scenario_id] = @scenario_id + AND [arrival_month] >= @from_month + AND [arrival_month] < @to_month; + + ;WITH months AS ( -- календарь месяцев [from, to) + SELECT CAST(@from_month AS DATE) AS m + UNION ALL + SELECT DATEADD(MONTH, 1, m) FROM months WHERE DATEADD(MONTH, 1, m) < @to_month + ), + -- 1) Стартовый остаток на начало горизонта (берём последний известный quantity) + opening AS ( + SELECT w._IDRREF AS [1c_id], + n.code AS [code], + CAST(@from_month AS DATE) AS [arrival_month], + CAST( + MAX(CASE WHEN w.dt = x.max_dt THEN w.quantity END) + AS DECIMAL(18,3)) AS opening_qty + FROM [pbi].[w_ostatok_da_net] w + JOIN ( + SELECT _IDRREF, MAX(dt) AS max_dt + FROM [pbi].[w_ostatok_da_net] + WHERE dt < @from_month + GROUP BY _IDRREF + ) x ON x._IDRREF = w._IDRREF AND x.max_dt = w.dt + JOIN [pbi].[nomenclature] n ON n.[1c_id] = w._IDRREF + GROUP BY w._IDRREF, n.code + ), + -- 2) Подтвержденные приходы (ожидаемые заказы) по дате прихода → к первому дню месяца + inbound_confirmed AS ( + SELECT + o.[1c_id], + n.code, + o.month AS arrival_month, + CAST(SUM(o.units) AS DECIMAL(18,3)) AS inbound_confirmed + FROM [mag_pbi].[analytics].[get_orders_by_group] o + JOIN [pbi].[nomenclature] n ON n.[1c_id] = o.[1c_id] + WHERE o.[status] IN (N'В пути', N'В производстве', N'Выгружен на складе', N'Согласован') + AND o.month >= @from_month + AND o.month < @to_month + GROUP BY o.[1c_id], n.code, + o.month + ), + -- 3) Будущие заказы (дефицит → рекомендованные поставки) по месяцу прихода + inbound_deficit AS ( + SELECT + d.[1c_id], + d.[code], + DATEFROMPARTS(YEAR(d.[arrival_month]), MONTH(d.[arrival_month]), 1) AS arrival_month, + CAST(SUM(d.[order_qty]) AS DECIMAL(18,3)) AS inbound_deficit + FROM [analytics].[deficit_proposal] d + WHERE d.[scenario_id] = @scenario_id + AND d.[arrival_month] >= @from_month + AND d.[arrival_month] < @to_month + GROUP BY d.[1c_id], d.[code], + DATEFROMPARTS(YEAR(d.[arrival_month]), MONTH(d.[arrival_month]), 1) + ), + -- 4) Прогноз спроса по месяцам + forecast AS ( + SELECT + f.[1c_id], + f.[code], + DATEFROMPARTS(YEAR(f.[month]), MONTH(f.[month]), 1) AS arrival_month, + CAST(SUM(f.[value]) AS DECIMAL(18,3)) AS forecast_demand + FROM [analytics].[forecast] f + WHERE f.[scenario_id] = @scenario_id + AND f.[month] >= @from_month + AND f.[month] < @to_month + GROUP BY f.[1c_id], f.[code], + DATEFROMPARTS(YEAR(f.[month]), MONTH(f.[month]), 1) + ), + -- 5) Объединим каркас всех SKU × месяцы горизонта + sku_calendar AS ( + SELECT DISTINCT n.[1c_id], n.[code], m.m AS arrival_month + FROM [pbi].[nomenclature] n + CROSS JOIN months m + ), + base_union AS ( + SELECT c.[1c_id], c.[code], c.[arrival_month], + COALESCE(op.opening_qty, 0) AS opening_qty, + COALESCE(ic.inbound_confirmed, 0) AS inbound_confirmed, + COALESCE(idf.inbound_deficit, 0) AS inbound_deficit, + COALESCE(fc.forecast_demand, 0) AS forecast_demand + FROM sku_calendar c + LEFT JOIN opening op ON op.[1c_id]=c.[1c_id] AND op.[code]=c.[code] AND op.[arrival_month]=@from_month + LEFT JOIN inbound_confirmed ic ON ic.[1c_id]=c.[1c_id] AND ic.[code]=c.[code] AND ic.[arrival_month]=c.[arrival_month] + LEFT JOIN inbound_deficit idf ON idf.[1c_id]=c.[1c_id] AND idf.[code]=c.[code] AND idf.[arrival_month]=c.[arrival_month] + LEFT JOIN forecast fc ON fc.[1c_id]=c.[1c_id] AND fc.[code]=c.[code] AND fc.[arrival_month]=c.[arrival_month] + WHERE c.[arrival_month] >= @from_month + AND c.[arrival_month] < @to_month + ), + -- 6) Расчёт rolling opening/closing по месяцам + projected AS ( + SELECT + @scenario_id AS scenario_id, + b.[1c_id], + b.[code], + b.[arrival_month], + -- opening: для первого месяца берем opening_qty из "opening", далее — прошлый closing + CAST( + CASE + WHEN b.[arrival_month] = @from_month + THEN b.[opening_qty] + ELSE 0 + END + AS DECIMAL(18,3)) AS opening_qty, + b.[inbound_confirmed], + b.[inbound_deficit], + b.[forecast_demand] + FROM base_union b + ) + -- Вставка построчно с расчетом closing через окно + INSERT INTO [analytics].[stock_plan_by_arrival] + ([scenario_id],[arrival_month],[1c_id],[code], + [opening_qty],[inbound_confirmed],[inbound_deficit],[forecast_demand],[closing_qty],[updated_at]) + SELECT + p.scenario_id, + p.arrival_month, + p.[1c_id], + p.[code], + -- opening по месяцу = LAG(closing) OVER (по SKU упорядочено по месяцу), для первого — opening_qty + CAST( + COALESCE( + LAG( closing_calc ) OVER (PARTITION BY p.[1c_id], p.[code] ORDER BY p.arrival_month), + p.opening_qty + ) + AS DECIMAL(18,3)) AS opening_qty, + p.inbound_confirmed, + p.inbound_deficit, + p.forecast_demand, + -- closing = opening + inbound_confirmed + inbound_deficit - forecast + CAST( + ( + COALESCE( LAG( closing_calc ) OVER (PARTITION BY p.[1c_id], p.[code] ORDER BY p.arrival_month), p.opening_qty) + + p.inbound_confirmed + + p.inbound_deficit + - p.forecast_demand + ) AS DECIMAL(18,3) + ) AS closing_qty, + SYSUTCDATETIME() + FROM ( + -- промежуточное вычисление closing для использования в LAG + SELECT + scenario_id, [1c_id], [code], arrival_month, opening_qty, inbound_confirmed, inbound_deficit, forecast_demand, + CAST(opening_qty + inbound_confirmed + inbound_deficit - forecast_demand AS DECIMAL(18,3)) AS closing_calc + FROM projected + ) p + OPTION (MAXRECURSION 0); + +END +GO + +/****** Object: StoredProcedure [analytics].[sp_recalc_roic] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_recalc_roic] + @manufacturer_id INT = NULL +AS +SET NOCOUNT ON; + +;WITH stage_agg AS ( + SELECT + manufacturer_id, + SUM([percent] / 100.0 * [days]) AS effective_deferral_days, + SUM([percent] / 100.0) AS total_percent + FROM [analytics].[manufacturer_payment_stage] + WHERE @manufacturer_id IS NULL OR manufacturer_id = @manufacturer_id + GROUP BY manufacturer_id +), +calc AS ( + SELECT + man.id, + man.days_of_sales, + man.logistics_days, + COALESCE(s.effective_deferral_days, 0) AS effective_deferral_days, + COALESCE(s.total_percent, 0) AS total_percent, + (ISNULL(man.logistics_days, 120) + ISNULL(man.days_of_sales, 180) / 2.0) AS avg_return_day + FROM [analytics].[manufacturers] man + LEFT JOIN stage_agg s ON s.manufacturer_id = man.id + WHERE @manufacturer_id IS NULL OR man.id = @manufacturer_id +), +roic_calc AS ( + SELECT + id, + CASE + WHEN total_percent <= 0 THEN NULL + WHEN (avg_return_day - effective_deferral_days) <= 0 THEN NULL + ELSE ROUND(12.0 / ((avg_return_day - effective_deferral_days) / 30.0) * 100.0, 2) + END AS new_roic + FROM calc +) +UPDATE man +SET man.roic_norm = r.new_roic +FROM [analytics].[manufacturers] man +JOIN roic_calc r ON r.id = man.id; + +SELECT @@ROWCOUNT AS updated_count; +GO + +/****** Object: StoredProcedure [analytics].[sp_report_ROI] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_report_ROI] + @scenario_id INT = 4, + @min_deficit_rub DECIMAL(18,2) = 2000, + @cutoff_month DATE = '2027-01-01', + @pathPattern NVARCHAR(400) = N'Кружево%' +AS +BEGIN + SET NOCOUNT ON; + + ;WITH stages_pivot AS ( + SELECT manufacturer_id, + MAX(CASE WHEN rn = 1 THEN [percent] END) / 100.0 AS n_percent, + MAX(CASE WHEN rn = 1 THEN days END) AS n_days, + MAX(CASE WHEN rn = 2 THEN [percent] END) / 100.0 AS m_percent, + MAX(CASE WHEN rn = 2 THEN days END) AS m_days + FROM ( + SELECT manufacturer_id, [percent], days, + ROW_NUMBER() OVER (PARTITION BY manufacturer_id ORDER BY sort_order) AS rn + FROM [analytics].[manufacturer_payment_stage] + ) t WHERE rn <= 2 + GROUP BY manufacturer_id + ), + base AS ( + SELECT + g.[path] AS grp + , n.[Производитель] + , d.place_month + , SUM(d.order_qty * ISNULL(n.[Цена учетная, руб], 0)) AS Deficit + , SUM(a.[%ТН год, руб.] * d.order_qty * ISNULL(n.[Цена учетная, руб], 0)) + / NULLIF(SUM(d.order_qty * ISNULL(n.[Цена учетная, руб], 0)), 0) AS [%ТН средн] + FROM [analytics].[deficit_proposal] d + INNER JOIN [mag_pbi].[pbi].[v_nomenclature_full] n ON n.[1c_id] = d.[1c_id] + INNER JOIN [analytics].[аналитика за 365 дн.] a ON a.[1c_id] = d.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE d.scenario_id = @scenario_id + AND ISNULL(n.[cenovaya_gruppa], N'') = N'Валютная' + AND g.[path] LIKE @pathPattern + GROUP BY g.[path], n.[Производитель], d.place_month + HAVING SUM(d.order_qty * ISNULL(n.[Цена учетная, руб], 0)) > @min_deficit_rub + ) + SELECT + b.grp AS [g] + , b.[Производитель] + , b.place_month + , b.Deficit + , b.[%ТН средн] + , b.[%ТН средн] * ISNULL(m.roic_norm, 1.36) AS [%ROI заказа] + , ISNULL(m.roic_norm, 1.36) AS [ROI normalized] + , b.[%ТН средн] * ISNULL(m.roic_norm, 1.36) * b.Deficit AS [ROI руб] + , ISNULL(sp.n_percent, 0.30) AS n_percent + , ISNULL(sp.n_days, 1) AS n_days + , ISNULL(sp.m_percent, 0.70) AS m_percent + , ISNULL(sp.m_days, 60) AS m_days + FROM base b + LEFT JOIN [analytics].[manufacturers] m + ON LTRIM(RTRIM(ISNULL(b.[Производитель], N''))) = LTRIM(RTRIM(m.manufacturer)) + AND LTRIM(RTRIM(ISNULL(b.[Производитель], N''))) <> N'' + LEFT JOIN stages_pivot sp ON sp.manufacturer_id = m.id + ORDER BY [%ROI заказа] DESC, b.grp, b.Deficit DESC; + + -- 2. Платежи по месяцам (из deficit_proposal по path — dmr не хранит path) + SELECT + FORMAT(d.arrival_month, 'yyyy-MM') AS [Дата платежа] + , SUM(d.order_qty * ISNULL(n.[Цена учетная, руб], 0)) AS [Сумма платежа] + FROM [analytics].[deficit_proposal] d + INNER JOIN [mag_pbi].[pbi].[v_nomenclature_full] n ON n.[1c_id] = d.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE d.scenario_id = @scenario_id + AND g.[path] LIKE @pathPattern + GROUP BY FORMAT(d.arrival_month, 'yyyy-MM') + ORDER BY FORMAT(d.arrival_month, 'yyyy-MM') ASC; + + -- 3. Платежи до cutoff (из deficit_proposal по path) + SELECT + SUM(d.order_qty * ISNULL(n.[Цена учетная, руб], 0)) AS [Платежи в 2026] + FROM [analytics].[deficit_proposal] d + INNER JOIN [mag_pbi].[pbi].[v_nomenclature_full] n ON n.[1c_id] = d.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE d.scenario_id = @scenario_id + AND g.[path] LIKE @pathPattern + AND d.arrival_month < @cutoff_month; + + -- 4. Прогноз выручки по месяцам + SELECT + t.[month] + , SUM(t.Выручка) AS revenue + , SUM(t.[Сумм. учет]) AS uchet + FROM ( + SELECT + f.[month] + , f.[value] * ISNULL(n.[Цена учетная, руб], 0) AS [Сумм. учет] + , f.[value] * ISNULL(n.[Цена учетная, руб], 0) * (1 + a.[%ТН год, руб.]) AS Выручка + FROM [analytics].[forecast] f + INNER JOIN [analytics].[аналитика за 365 дн.] a ON a.[1c_id] = f.[1c_id] + INNER JOIN [mag_pbi].[pbi].[nomenclature] n ON n.[1c_id] = f.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE f.scenario_id = @scenario_id + AND a.[%ТН год, руб.] > 0 + AND g.[path] LIKE @pathPattern + ) t + GROUP BY t.[month] + ORDER BY t.[month]; + + -- 5. ROIC по группе (path pattern) + ;WITH sku_in_group AS ( + SELECT + a.[1c_id] + , a.[Code] AS code + , g.[path] + , a.[Оплаченный остаток] AS PaidCapital + , a.[Рентабельность по остатку / год] AS RoicPast + FROM [analytics].[аналитика за 365 дн.] a + INNER JOIN [mag_pbi].[pbi].[v_nomenclature_full] n ON n.[1c_id] = a.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE g.[path] LIKE @pathPattern + ) + SELECT + @pathPattern AS [Фильтр path] + , SUM(PaidCapital) AS [Оплаченный остаток всего, руб] + , CASE + WHEN SUM(PaidCapital) > 0 + THEN SUM(ISNULL(PaidCapital, 0) * ISNULL(RoicPast, 0)) / SUM(PaidCapital) + ELSE NULL + END AS [Рентабельность остатка / год назад, %] + FROM sku_in_group; + + -- 6. Итоговые ROIC по всей аналитике + DECLARE @sumPaid DECIMAL(38,6); + DECLARE @sumWeightedPast DECIMAL(38,6); + DECLARE @sumWeightedFuture DECIMAL(38,6); + DECLARE @roicPastTotal DECIMAL(38,6); + DECLARE @roicFutureTotal DECIMAL(38,6); + + SELECT + @sumPaid = SUM(CAST(ISNULL(a.[Оплаченный остаток], 0) AS DECIMAL(38,6))) + , @sumWeightedPast = SUM( + CAST(ISNULL(a.[Оплаченный остаток], 0) AS DECIMAL(38,6)) + * CAST(ISNULL(a.[Рентабельность по остатку / год], 0) AS DECIMAL(38,6)) + ) + , @sumWeightedFuture = SUM( + CAST(ISNULL(a.[Оплаченный остаток], 0) AS DECIMAL(38,6)) + * CAST(ISNULL(a.[Рентабельность / будущий год], 0) AS DECIMAL(38,6)) + ) + FROM [analytics].[аналитика за 365 дн.] a + INNER JOIN [mag_pbi].[pbi].[v_nomenclature_full] n ON n.[1c_id] = a.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON g.[1c_id] = n.[1c_group] + WHERE g.[path] LIKE @pathPattern; + + SET @roicPastTotal = CASE WHEN @sumPaid > 0 THEN @sumWeightedPast / @sumPaid ELSE NULL END; + SET @roicFutureTotal = CASE WHEN @sumPaid > 0 THEN @sumWeightedFuture / @sumPaid ELSE NULL END; + + SELECT + @sumPaid AS [Оплаченный остаток всего, руб] + , @roicPastTotal AS [Рентабельность остатка / год назад всего, %] + , @roicFutureTotal AS [Рентабельность остатка / будущий год всего, %]; +END +GO + +/****** Object: StoredProcedure [analytics].[sp_report_ROI_подробно] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE procedure [analytics].[sp_report_ROI_подробно] as BEGIN +--------------------------------------------------------- +-- 0. Параметры дат: 12 полных месяцев НАЗАД +--------------------------------------------------------- +DECLARE @today date = CAST(GETDATE() AS date); +DECLARE @lastFullMonth date; +DECLARE @firstMonthStart date; +DECLARE @curMonthStart date; + +-- последний полный месяц (месяц до текущего дня) +SET @lastFullMonth = EOMONTH(DATEADD(month, -1, @today)); +-- первый из 12 полных месяцев +SET @firstMonthStart = DATEADD( + month, -11, + DATEFROMPARTS(YEAR(@lastFullMonth), MONTH(@lastFullMonth), 1) + ); +SET @curMonthStart = @firstMonthStart; + +--------------------------------------------------------- +-- 1. Список месяцев (#months) +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#months') IS NOT NULL DROP TABLE #months; + +CREATE TABLE #months ( + MonthStart date NOT NULL PRIMARY KEY +); + +WHILE @curMonthStart + <= DATEFROMPARTS(YEAR(@lastFullMonth), MONTH(@lastFullMonth), 1) +BEGIN + INSERT INTO #months (MonthStart) + VALUES (@curMonthStart); + + SET @curMonthStart = DATEADD(month, 1, @curMonthStart); +END; + +--------------------------------------------------------- +-- 2. SKU (#s) – здесь укажи нужный код товара +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#s') IS NOT NULL DROP TABLE #s; + +CREATE TABLE #s ( + [1c_id] binary(16) NOT NULL, + code nchar(11) NOT NULL +); + +INSERT INTO #s ([1c_id], code) +SELECT n.[1c_id], n.code +FROM pbi.nomenclature n +WHERE n.code = N'УТ-00176242'; -- <=== поменяй при необходимости + +--------------------------------------------------------- +-- 3. Внешние остатки (#ext_stock) – срезы на конец месяца +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#ext_stock') IS NOT NULL DROP TABLE #ext_stock; + +CREATE TABLE #ext_stock ( + Dt date NOT NULL, + code nchar(11) NOT NULL, + qty numeric(18,3) NOT NULL, + CONSTRAINT PK_ext_stock PRIMARY KEY (Dt, code) +); + +INSERT INTO #ext_stock (Dt, code, qty) +SELECT + CAST(o.[Дата обновления] AS date) AS Dt, + o.code, + SUM(o.[Количество]) AS qty +FROM analytics.[Внешние остатки] o +JOIN #s s + ON s.code = o.code +GROUP BY CAST(o.[Дата обновления] AS date), o.code; + +--------------------------------------------------------- +-- 4. Приходы (#incoming) – Закупка / Приход по месяцам +-- БЕРЁМ ТОЛЬКО ПРИХОДЫ ВНУТРИ НАШИХ 12 МЕСЯЦЕВ +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#incoming') IS NOT NULL DROP TABLE #incoming; + +CREATE TABLE #incoming ( + MonthStart date NOT NULL, -- месяц прихода (1-е число) + code nchar(11) NOT NULL, + qty numeric(18,3) NOT NULL, + CONSTRAINT PK_incoming PRIMARY KEY (MonthStart, code) +); + +INSERT INTO #incoming (MonthStart, code, qty) +SELECT + DATEFROMPARTS(YEAR(s.[Период]), MONTH(s.[Период]), 1) AS MonthStart, + n.code, + SUM(s.[Количество]) AS qty +FROM pbiProd.[СводныйСебестоимость Для PBI] s +JOIN pbi.nomenclature n + ON n.[1c_id] = s.[1c_id] +JOIN #s sfilter + ON sfilter.code = n.code +WHERE s.[Статья] = N'Закупка' + AND s.[Вид операции] = N'Приход' + AND s.[Период] >= @firstMonthStart -- отключаем старые приходы +GROUP BY + DATEFROMPARTS(YEAR(s.[Период]), MONTH(s.[Период]), 1), + n.code; + +--------------------------------------------------------- +-- 5. Части платежей по каждому приходу (#pay_parts) +-- (1-й и 2-й платёж по производителю, проценты как ДОЛИ) +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#pay_parts') IS NOT NULL DROP TABLE #pay_parts; + +CREATE TABLE #pay_parts ( + MonthStart date NOT NULL, -- месяц прихода (ключ к #incoming) + code nchar(11) NOT NULL, + pay_date date NOT NULL, -- дата платежа + amount numeric(18,2) NOT NULL +); + +-- первый платёж (n) +INSERT INTO #pay_parts (MonthStart, code, pay_date, amount) +SELECT + inc.MonthStart, + inc.code, + DATEADD(day, man.n_days - 90, EOMONTH(inc.MonthStart)) AS pay_date, + inc.qty * n.[Цена учетная, руб] * man.n_percent AS amount +FROM #incoming inc +JOIN pbi.nomenclature n + ON n.code = inc.code +JOIN analytics.manufacturers man + ON man.[manufacturer] = n.Производитель +WHERE man.n_percent IS NOT NULL + AND man.n_percent <> 0; + +-- второй платёж (m) +INSERT INTO #pay_parts (MonthStart, code, pay_date, amount) +SELECT + inc.MonthStart, + inc.code, + DATEADD(day, man.m_days - 90, EOMONTH(inc.MonthStart)) AS pay_date, + inc.qty * n.[Цена учетная, руб] * man.m_percent AS amount +FROM #incoming inc +JOIN pbi.nomenclature n + ON n.code = inc.code +JOIN analytics.manufacturers man + ON man.[manufacturer] = n.Производитель +WHERE man.m_percent IS NOT NULL + AND man.m_percent <> 0; + +--------------------------------------------------------- +-- 6. Платежи по месяцам (#payments) – для колонки [платеж] +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#payments') IS NOT NULL DROP TABLE #payments; + +CREATE TABLE #payments ( + MonthStart date NOT NULL, -- месяц платежа (1-е число) + code nchar(11) NOT NULL, + amount numeric(18,2) NOT NULL, + CONSTRAINT PK_payments PRIMARY KEY (MonthStart, code) +); + +INSERT INTO #payments (MonthStart, code, amount) +SELECT + DATEFROMPARTS(YEAR(p.pay_date), MONTH(p.pay_date), 1) AS MonthStart, + p.code, + SUM(p.amount) AS amount +FROM #pay_parts p +GROUP BY + DATEFROMPARTS(YEAR(p.pay_date), MONTH(p.pay_date), 1), + p.code; + +--------------------------------------------------------- +-- 7. Обязательства по месяцам (#obligations) +-- Считаем только по приходам (#incoming) +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#obligations') IS NOT NULL DROP TABLE #obligations; + +CREATE TABLE #obligations ( + MonthStart date NOT NULL, -- месяц, на который считаем долг + code nchar(11) NOT NULL, + obligation numeric(18,2) NOT NULL, + CONSTRAINT PK_obligations PRIMARY KEY (MonthStart, code) +); + +;WITH ObligRows AS ( + SELECT + m.MonthStart, + inc.code, + CASE + -- если месяц ещё до прихода товара – долга нет + WHEN EOMONTH(m.MonthStart) < EOMONTH(inc.MonthStart) THEN 0 + ELSE + CASE + WHEN full_sum - paid_to_month > 0 + THEN full_sum - paid_to_month + ELSE 0 + END + END AS ObligationPerIncoming + FROM #months m + JOIN #incoming inc + ON 1 = 1 -- каждая пара (месяц, приход) + JOIN pbi.nomenclature n2 + ON n2.code = inc.code + JOIN analytics.manufacturers man2 + ON man2.[manufacturer] = n2.Производитель + CROSS APPLY ( + SELECT + inc.qty * n2.[Цена учетная, руб] AS full_sum, + ( + -- оплачено к концу месяца m.MonthStart (по обоим платежам) + (CASE + WHEN man2.n_percent IS NOT NULL + AND EOMONTH(m.MonthStart) + >= DATEADD(day, man2.n_days - 90, + EOMONTH(inc.MonthStart)) + THEN inc.qty * n2.[Цена учетная, руб] * man2.n_percent + ELSE 0 + END) + + + (CASE + WHEN man2.m_percent IS NOT NULL + AND EOMONTH(m.MonthStart) + >= DATEADD(day, man2.m_days - 90, + EOMONTH(inc.MonthStart)) + THEN inc.qty * n2.[Цена учетная, руб] * man2.m_percent + ELSE 0 + END) + ) AS paid_to_month + ) calc +) +INSERT INTO #obligations (MonthStart, code, obligation) +SELECT + MonthStart, + code, + SUM(ObligationPerIncoming) AS obligation +FROM ObligRows +GROUP BY + MonthStart, + code; + +--------------------------------------------------------- +-- 8. ТН по месяцам (#tn_monthly) из Продажи_Учёт_Маржа_по_дням +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#tn_monthly') IS NOT NULL DROP TABLE #tn_monthly; + +CREATE TABLE #tn_monthly ( + MonthStart date NOT NULL, + code nchar(11) NOT NULL, + tn_amount numeric(18,2) NOT NULL, + CONSTRAINT PK_tn_monthly PRIMARY KEY (MonthStart, code) +); + +INSERT INTO #tn_monthly (MonthStart, code, tn_amount) +SELECT + DATEFROMPARTS(YEAR(p.[d]), MONTH(p.[d]), 1) AS MonthStart, + p.[Code], + SUM(p.[Торговая надбавка]) AS tn_amount +FROM [mag_pbi].[analytics].[Продажи_Учёт_Маржа_по_дням] p +JOIN #s s + ON s.code = p.[Code] +WHERE p.[d] >= @firstMonthStart + AND p.[d] <= @lastFullMonth +GROUP BY + DATEFROMPARTS(YEAR(p.[d]), MONTH(p.[d]), 1), + p.[Code]; + +--------------------------------------------------------- +-- 9. Финальный SELECT ПО МЕСЯЦАМ (прошлый год) +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#month_plan') IS NOT NULL DROP TABLE #month_plan; + +SELECT + s.[1c_id], + s.code, + n.Производитель, + n.[Цена учетная, руб], + n.[Цена учетная, руб]*(ISNULL(intStock.quantity, 0) + ISNULL(ext.qty, 0)) AS [Остаток учетка руб], + man.n_percent, + man.n_days, + man.m_percent, + man.m_days, + RIGHT('0' + CAST(MONTH(m.MonthStart) AS varchar(2)), 2) + + '-' + CAST(YEAR(m.MonthStart) AS varchar(4)) AS [месяц], -- MM-YYYY (текст) + m.MonthStart AS [MonthStart], -- реальная дата месяца + ISNULL(intStock.quantity, 0) + ISNULL(ext.qty, 0) AS [остаток], -- шт + ISNULL(inc.qty, 0) AS [приход], -- шт + ISNULL(pay.amount, 0) AS [платеж], -- руб + ISNULL(ob.obligation, 0) AS [Обязательства],-- руб + CAST( + CASE + WHEN p.paid_raw < 0 THEN 0 + ELSE p.paid_raw + END + AS numeric(18,2) + ) AS [Оплаченный остаток], -- руб + ISNULL(tn.tn_amount, 0) AS [ТН], -- торговая надбавка за месяц, руб + CAST( + CASE + WHEN p.paid_raw < 0 THEN 0 + ELSE p.paid_raw + END * DAY(EOMONTH(m.MonthStart)) + AS numeric(18,2) + ) AS [рубли-дни] -- оплаченный остаток × дней в месяце +INTO #month_plan +FROM #months m +CROSS JOIN #s s + +OUTER APPLY ( + SELECT TOP (1) w1.quantity + FROM pbi.[w_ostatok_da_net] w1 + WHERE w1._IDRREF = s.[1c_id] + AND w1.dt <= EOMONTH(m.MonthStart) + ORDER BY w1.dt DESC +) AS intStock + +LEFT JOIN #ext_stock ext + ON ext.code = s.code + AND ext.Dt = EOMONTH(m.MonthStart) + +LEFT JOIN #incoming inc + ON inc.code = s.code + AND inc.MonthStart = m.MonthStart + +LEFT JOIN pbi.nomenclature n + ON n.code = s.code + +LEFT JOIN analytics.manufacturers man + ON man.[manufacturer] = n.Производитель + +LEFT JOIN #payments pay + ON pay.code = s.code + AND pay.MonthStart = m.MonthStart + +LEFT JOIN #obligations ob + ON ob.code = s.code + AND ob.MonthStart = m.MonthStart + +LEFT JOIN #tn_monthly tn + ON tn.code = s.code + AND tn.MonthStart = m.MonthStart + +CROSS APPLY ( -- сырые оплаченные рубли (до обрезки в 0) + SELECT + (ISNULL(intStock.quantity, 0) + ISNULL(ext.qty, 0)) + * ISNULL(n.[Цена учетная, руб], 0) + - ISNULL(ob.obligation, 0) AS paid_raw +) p + +ORDER BY m.MonthStart; + +-- помесячная картина прошлого +SELECT * FROM #month_plan; + +--------------------------------------------------------- +-- 10. Рентабельность за прошлый год (ROIC как было) +--------------------------------------------------------- +DECLARE @roic_past numeric(38,6); +DECLARE @tn_year numeric(38,6); +DECLARE @ruble_days_year numeric(38,6); + +SELECT + @tn_year = SUM(t.[ТН]), + @ruble_days_year = SUM(t.[рубли-дни]) +FROM #month_plan t; + +SET @roic_past = CASE + WHEN @ruble_days_year > 0 + THEN @tn_year * 365.0 / @ruble_days_year * 100.0 + ELSE NULL + END; + +--------------------------------------------------------- +-- 10a. Рентабельность по остатку В РУБЛЯХ (год и квартал назад) +-- ТН / средний остаток учетка руб +--------------------------------------------------------- +DECLARE @rent_cap_year numeric(38,6); +DECLARE @rent_cap_quarter numeric(38,6); + +-- год: средний Остаток учетка руб по всем 12 месяцам +DECLARE @avg_cap_year numeric(38,6); + +SELECT + @avg_cap_year = AVG(NULLIF(t.[Остаток учетка руб], 0.0)) +FROM #month_plan t; + +IF @avg_cap_year IS NOT NULL AND @avg_cap_year > 0 AND @tn_year IS NOT NULL + SET @rent_cap_year = @tn_year / @avg_cap_year; +ELSE + SET @rent_cap_year = NULL; + +-- квартал: последние 3 месяца окна +DECLARE @q_start date = DATEADD( + month, -2, + DATEFROMPARTS(YEAR(@lastFullMonth), MONTH(@lastFullMonth), 1) + ); +DECLARE @tn_q numeric(38,6); +DECLARE @avg_cap_q numeric(38,6); + +SELECT + @tn_q = SUM(t.[ТН]), + @avg_cap_q = AVG(NULLIF(t.[Остаток учетка руб], 0.0)) +FROM #month_plan t +WHERE t.MonthStart >= @q_start; + +IF @avg_cap_q IS NOT NULL AND @avg_cap_q > 0 AND @tn_q IS NOT NULL + SET @rent_cap_quarter = @tn_q / @avg_cap_q; +ELSE + SET @rent_cap_quarter = NULL; + +--------------------------------------------------------- +-- 11. Рентабельность остатка на будущий год (ROIC вперёд) +--------------------------------------------------------- + +-- 11.1. Текущий SKU и его продажи / день +DECLARE @sku_1c_id binary(16); +SELECT TOP(1) @sku_1c_id = [1c_id] FROM #s; + +DECLARE @sales_per_day numeric(38,6); -- Продажи шт / день +DECLARE @sold_year numeric(38,6); -- Продано шт за последние 12 мес + +-- берём скорость продаж из аналитики за 365 дней (если есть) +SELECT + @sales_per_day = a.[Продажи шт / день] +FROM [mag_pbi].[analytics].[аналитика за 365 дн.] a +WHERE a.[1c_id] = @sku_1c_id; + +-- продано шт за наши 12 месяцев (по себестоимости) +SELECT + @sold_year = SUM(s.[Количество]) +FROM pbiProd.[СводныйСебестоимость Для PBI] s +WHERE s.[1c_id] = @sku_1c_id + AND s.[Статья] = N'Реализация' + AND s.[Период] >= @firstMonthStart + AND s.[Период] <= @lastFullMonth; + +IF (@sales_per_day IS NULL OR @sales_per_day = 0) AND @sold_year IS NOT NULL +BEGIN + -- fallback, если ещё не прогоняли sp_create_analytics_365 + SET @sales_per_day = @sold_year / 365.0; +END; + +-- 11.2. Маржа на штуку по истории +DECLARE @tn_per_unit numeric(38,6); + +SET @tn_per_unit = CASE + WHEN @sold_year IS NOT NULL AND @sold_year > 0 + THEN @tn_year / @sold_year + ELSE NULL + END; + +-- 11.3. Текущий оплаченный остаток, остаток шт и остаток учетка руб (последний месяц окна) +DECLARE @q_stock numeric(18,6); -- текущий остаток шт +DECLARE @paid_stock_today numeric(18,6); -- оплаченный остаток в руб +DECLARE @stock_rub_today numeric(18,6); -- остаток учетка руб на конец окна + +SELECT TOP(1) + @q_stock = [остаток], + @paid_stock_today = [Оплаченный остаток], + @stock_rub_today = [Остаток учетка руб] +FROM #month_plan +ORDER BY MonthStart DESC; -- последний из 12 месяцев = @lastFullMonth + +-- 11.4. Сколько успеем продать за будущий год и какая будет ТН + +DECLARE @q_future numeric(18,6); -- сколько штук реально успеем продать за год +DECLARE @tn_future numeric(18,6); -- ожидаемая ТН за будущий год + +IF @sales_per_day IS NOT NULL AND @sales_per_day > 0 +BEGIN + DECLARE @max_sell_1y numeric(18,6); + SET @max_sell_1y = @sales_per_day * 365.0; + + SET @q_future = CASE + WHEN @q_stock IS NULL THEN 0 + WHEN @q_stock <= @max_sell_1y THEN @q_stock + ELSE @max_sell_1y + END; +END +ELSE +BEGIN + SET @q_future = 0; +END; + +IF @tn_per_unit IS NOT NULL + SET @tn_future = @tn_per_unit * @q_future; +ELSE + SET @tn_future = NULL; + +-- 11.5. Будущие рубли-дни и ROIC вперёд + +DECLARE @days_to_sell numeric(18,6); +DECLARE @ruble_days_future numeric(18,6); +DECLARE @roic_future numeric(38,6); + +IF @sales_per_day IS NOT NULL AND @sales_per_day > 0 AND @q_stock IS NOT NULL + SET @days_to_sell = @q_stock / @sales_per_day; +ELSE + SET @days_to_sell = NULL; + +IF @days_to_sell IS NULL OR @paid_stock_today IS NULL OR @paid_stock_today <= 0 OR @tn_future IS NULL +BEGIN + SET @roic_future = NULL; +END +ELSE +BEGIN + IF @days_to_sell >= 365.0 + -- остаток будет лежать весь год + SET @ruble_days_future = @paid_stock_today * 365.0; + ELSE + -- остаток линейно уходит до нуля за days_to_sell + SET @ruble_days_future = @paid_stock_today * @days_to_sell / 2.0; + + IF @ruble_days_future > 0 + SET @roic_future = @tn_future * 365.0 / @ruble_days_future * 100.0; + ELSE + SET @roic_future = NULL; +END; + +--------------------------------------------------------- +-- 11.6. Рентабельность по остатку В РУБЛЯХ на будущий год +-- (ТН_future / средний остаток учетка руб в горизонте) +--------------------------------------------------------- +DECLARE @rent_cap_future numeric(38,6); + +IF @stock_rub_today IS NULL OR @stock_rub_today <= 0 + OR @q_stock IS NULL OR @q_stock <= 0 + OR @q_future IS NULL OR @q_future <= 0 + OR @tn_future IS NULL +BEGIN + SET @rent_cap_future = NULL; +END +ELSE +BEGIN + DECLARE @avg_cap_future numeric(38,6); + + -- считаем, что капитал уходит линейно пропорционально количеству: + -- капитал "на продажу" = stock_rub_today * (q_future / q_stock) + -- средний капитал = stock_rub_today - 0.5 * капитал_на_продажу + SET @avg_cap_future = + @stock_rub_today * (1.0 - (@q_future / @q_stock) / 2.0); + + IF @avg_cap_future > 0 + SET @rent_cap_future = @tn_future / @avg_cap_future; + ELSE + SET @rent_cap_future = NULL; +END; + +--------------------------------------------------------- +-- 11.7. Таблица будущего по месяцам (#future_plan) — как было +--------------------------------------------------------- +IF OBJECT_ID('tempdb..#future_plan') IS NOT NULL DROP TABLE #future_plan; + +CREATE TABLE #future_plan ( + PeriodStart date, + PeriodEnd date, + DaysInPeriod int, + QtyStart numeric(18,6), + Sold numeric(18,6), + QtyEnd numeric(18,6), + PaidCapitalAvg numeric(18,6), + RubleDays numeric(18,6), + TN_period numeric(18,6), + ROIC_period numeric(38,6) +); + +DECLARE + @f_start date, + @f_end date, + @days int, + @rem_qty numeric(18,6), + @qty_start numeric(18,6), + @qty_end numeric(18,6), + @sold numeric(18,6), + @capital_start numeric(18,6), + @capital_end numeric(18,6), + @capital_avg numeric(18,6), + @tn_period numeric(18,6), + @ruble_days_m numeric(18,6), + @roic_m numeric(38,6), + @cum_days int; + +SET @rem_qty = ISNULL(@q_stock, 0); +SET @f_start = @today; +SET @cum_days = 0; + +WHILE @cum_days < 365 AND @rem_qty > 0 AND @sales_per_day IS NOT NULL AND @sales_per_day > 0 +BEGIN + -- конец периода = конец месяца, в котором f_start + SET @f_end = EOMONTH(@f_start); + SET @days = DATEDIFF(day, @f_start, @f_end) + 1; + + -- не выходим за 365 дней горизонта + IF @cum_days + @days > 365 + BEGIN + SET @days = 365 - @cum_days; + SET @f_end = DATEADD(day, @days - 1, @f_start); + END; + + SET @qty_start = @rem_qty; + + DECLARE @can_sell numeric(18,6); + SET @can_sell = @sales_per_day * @days; + + SET @sold = CASE + WHEN @rem_qty <= @can_sell THEN @rem_qty + ELSE @can_sell + END; + + SET @qty_end = @qty_start - @sold; + + IF @q_stock IS NOT NULL AND @q_stock > 0 AND @paid_stock_today IS NOT NULL + BEGIN + SET @capital_start = @paid_stock_today * (@qty_start / @q_stock); + SET @capital_end = @paid_stock_today * (@qty_end / @q_stock); + END + ELSE + BEGIN + SET @capital_start = 0; + SET @capital_end = 0; + END; + + SET @capital_avg = (@capital_start + @capital_end) / 2.0; + + IF @tn_per_unit IS NOT NULL + SET @tn_period = @tn_per_unit * @sold; + ELSE + SET @tn_period = NULL; + + SET @ruble_days_m = @capital_avg * @days; + + IF @ruble_days_m > 0 AND @tn_period IS NOT NULL + SET @roic_m = @tn_period * 365.0 / @ruble_days_m * 100.0; + ELSE + SET @roic_m = NULL; + + INSERT INTO #future_plan ( + PeriodStart, PeriodEnd, DaysInPeriod, + QtyStart, Sold, QtyEnd, + PaidCapitalAvg, RubleDays, TN_period, ROIC_period + ) + VALUES ( + @f_start, @f_end, @days, + @qty_start, @sold, @qty_end, + @capital_avg, @ruble_days_m, @tn_period, @roic_m + ); + + SET @rem_qty = @qty_end; + SET @cum_days = @cum_days + @days; + SET @f_start = DATEADD(day, 1, @f_end); + + IF @cum_days >= 365 BREAK; +END; + +--------------------------------------------------------- +-- 12. Итог: прошлое и будущее + рентабельность по остатку (руб) +--------------------------------------------------------- +SELECT + @roic_past AS [ROIC за год назад], + @roic_future AS [ROIC на будущий год], + @rent_cap_year AS [Рентабельность по остатку (руб) / год назад], + @rent_cap_quarter AS [Рентабельность по остатку (руб) / квартал назад], + @rent_cap_future AS [Рентабельность по остатку (руб) / будущий год]; + +-- Таблица будущего по месяцам / периодам (как было) +SELECT * FROM #future_plan ORDER BY PeriodStart; + +END +GO + +/****** Object: StoredProcedure [analytics].[sp_run_deficit_all_skus] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [analytics].[sp_run_deficit_all_skus] + @scenario_id INT + as BEGIN + DELETE FROM [analytics].[deficit_proposal] where scenario_id = @scenario_id + + EXEC [analytics].[sp_build_deficit_proposal] + @scenario_id = @scenario_id, + @group_path = N'', -- пусто = все группы + @lead_time_m = 4, + @cover_months = 6, + @from_month = '2025-10-01', + @to_month_excl = '2028-01-01', + @debug = 0; -- чтобы не заспамить Messages +END +GO + +/****** Object: StoredProcedure [analytics].[sp_загрузка_прогноза_закупки] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ + +CREATE PROCEDURE [analytics].[sp_загрузка_прогноза_закупки] AS BEGIN + + SET NOCOUNT ON; + + IF OBJECT_ID('tempdb..#plan2026') IS NOT NULL + DROP TABLE #plan2026; + + CREATE TABLE #plan2026 ( + code nvarchar(50) NOT NULL, + opt decimal(18,2) NULL, + mp decimal(18,2) NULL, + updated_by nvarchar(100) NULL + ); + + -- уникальный индекс по коду, дубли игнорируем + CREATE UNIQUE INDEX UX_plan2026_code + ON #plan2026(code) + WITH (IGNORE_DUP_KEY = ON); + + BULK INSERT #plan2026 + FROM '\\192.168.35.3\admin3\Обмен\powerbi\plan2026.csv' + WITH ( + FIRSTROW = 2, -- пропускаем заголовок + FIELDTERMINATOR = ';', + ROWTERMINATOR = '\n', + CODEPAGE = '1251', -- или 1251, если файл не в UTF-8 + TABLOCK + ); + + -- Проверка + SELECT COUNT(*) AS total_rows, + COUNT(DISTINCT code) AS distinct_codes + FROM #plan2026; + + -- Проверка + SELECT TOP (20) * + FROM #plan2026 + + + SELECT + month + , avg([koef]) + FROM [mag_pbi].[analytics].[seasonality_groups_summ_1] + GROUP by month + order by month + + + + + ------------------------------------------------------------ + -- 1. Средняя сезонность по месяцам → #Seasonality + ------------------------------------------------------------ + IF OBJECT_ID('tempdb..#Seasonality') IS NOT NULL + DROP TABLE #Seasonality; + + SELECT + [month] + , koef = AVG([koef]) + INTO #Seasonality + FROM [mag_pbi].[analytics].[seasonality_groups_summ_1] + GROUP BY [month]; + + ------------------------------------------------------------ + -- 2. Почистить сценарий 8 (если нужно пересчитать) + ------------------------------------------------------------ + DELETE FROM [mag_pbi].[analytics].[forecast] + WHERE scenario_id = 8; + + ------------------------------------------------------------ + -- 3. Записать прогноз в forecast для scenario_id = 8 + -- value = opt_месяц + mp_месяц + ------------------------------------------------------------ + INSERT INTO [mag_pbi].[analytics].[forecast] ( + scenario_id + , [1c_id] + , [code] + , [month] + , [value] + , [updated_at] + , [updated_by] + , [opt] + , [mp] + ) + SELECT + 8 AS scenario_id + , n.[1c_id] + , p.[code] + , DATEFROMPARTS(2026, s.[month], 1) AS [month] + , CAST( (p.opt * s.koef) + (p.mp * s.koef) AS decimal(18,3)) AS [value] + , GETDATE() AS updated_at + , p.[updated_by] AS updated_by + , CAST(p.opt * s.koef AS decimal(18,3)) AS [opt] + , CAST(p.mp * s.koef AS decimal(18,3)) AS [mp] + FROM #plan2026 AS p + INNER JOIN [mag_pbi].[pbi].[nomenclature] AS n + ON n.[code] = p.[code] + CROSS JOIN #Seasonality AS s; + -- всего строк и разных кодов + + + --EXEC [analytics].[sp_build_deficit_proposal] @scenario_id = 8 + /* + /****** Script for SelectTopNRows command from SSMS ******/ + INSERT INTO [mag_pbi].[analytics].[forecast] ( + scenario_id + , [1c_id] + , [code] + , [month] + , [value] + , [updated_at] + , [updated_by] + , [opt] + , [mp] + ) + SELECT + 8 AS scenario_id + ,[1c_id] + ,[code] + ,[month] + ,[value] + ,[updated_at] + ,[updated_by] + ,[opt] + ,[mp] + FROM [mag_pbi].[analytics].[forecast] + WHERE scenario_id = 5 AND code not in (SELECT code FROM [mag_pbi].[analytics].[forecast] WHERE scenario_id = 8 ) + */ + + --EXEC [analytics].[sp_fill_deficit_money_request] @scenario_id = 8 + +END +GO + +/****** Object: StoredProcedure [analytics].[usp_CreateForecastBasesKs] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE analytics.usp_CreateForecastBasesKs +AS +BEGIN + SET NOCOUNT ON; + + -- Удаляем вьюху, если существует + IF OBJECT_ID('analytics.ForecastBasesKs', 'V') IS NOT NULL + DROP VIEW analytics.ForecastBasesKs; + + -- Создаём заново + EXEC(' + CREATE VIEW [analytics].[ForecastBasesKs] AS + WITH MaxDate AS ( + SELECT MAX(Период) AS max_date + FROM [pbi].[Себестоимость] + WHERE Статья = ''реализация'' + ), + LastFullMonth AS ( + SELECT + YEAR(DATEADD(MONTH, -1, max_date)) AS last_year, + MONTH(DATEADD(MONTH, -1, max_date)) AS last_month + FROM MaxDate + ), + -- 1. Продажи по SKU × месяц + Sales AS ( + SELECT + artic_id, + YEAR(Период) AS Год, + MONTH(Период) AS Месяц, + SUM(Количество) AS total_sales + FROM [pbi].[Себестоимость] + WHERE Статья = ''реализация'' + GROUP BY artic_id, YEAR(Период), MONTH(Период) + ), + -- 2. Дни в продаже + Stock AS ( + SELECT + artic_id, + YEAR(dt) AS Год, + MONTH(dt) AS Месяц, + SUM(CASE WHEN ostatok = 1 THEN 1 ELSE 0 END) AS days_available + FROM [pbi].[w_ostatok_da_net] + GROUP BY artic_id, YEAR(dt), MONTH(dt) + ), + -- 3. База + Base AS ( + SELECT + s.artic_id, + n.code, + n.description, + s.Год, + s.Месяц, + s.total_sales, + st.days_available, + sg.seasonal_koef, + (s.total_sales / NULLIF(sg.seasonal_koef,0)) AS Normalized_sales, + CASE WHEN st.days_available > 19 THEN 1 ELSE 0 END AS valid_month, + CASE WHEN st.days_available > 19 + THEN (s.total_sales / NULLIF(sg.seasonal_koef,0)) + ELSE NULL END AS normalized_valid_sales + FROM Sales s + LEFT JOIN Stock st + ON s.artic_id = st.artic_id + AND s.Год = st.Год + AND s.Месяц = st.Месяц + JOIN [pbi].[nomenclature] n + ON s.artic_id = n.artic_id + JOIN [analytics].[seasonality_groups] sg + ON n.[1c_group] = sg.group_1c_id + AND s.Месяц = sg.month + ), + Windowed AS ( + SELECT + b.*, + ROW_NUMBER() OVER (PARTITION BY b.artic_id ORDER BY (b.Год*100 + b.Месяц) DESC) AS rn_desc + FROM Base b + ), + Aggregates AS ( + SELECT + w.artic_id, + AVG(CASE WHEN rn_desc <= 12 THEN normalized_valid_sales END) AS Base_12M, + CASE + WHEN MIN(CASE WHEN rn_desc <= 3 THEN valid_month END) = 1 + THEN AVG(CASE WHEN rn_desc <= 3 THEN normalized_valid_sales END) + ELSE NULL + END AS Base_3M + FROM Windowed w + CROSS JOIN LastFullMonth lm + WHERE (w.Год*100 + w.Месяц) <= (lm.last_year*100 + lm.last_month) + GROUP BY w.artic_id + ), + TrendData AS ( + SELECT + w.artic_id, + ROW_NUMBER() OVER (PARTITION BY w.artic_id ORDER BY (w.Год*100 + w.Месяц)) - 1 AS t, + LOG(w.normalized_valid_sales) AS ln_sales + FROM Windowed w + CROSS JOIN LastFullMonth lm + WHERE (w.Год*100 + w.Месяц) > (lm.last_year*100 + lm.last_month - 200) + AND (w.Год*100 + w.Месяц) <= (lm.last_year*100 + lm.last_month) + AND w.normalized_valid_sales > 0 + ), + TrendAgg AS ( + SELECT + artic_id, + COUNT(*) AS n_obs, + EXP( (AVG(t*ln_sales) - AVG(t)*AVG(ln_sales)) / NULLIF(AVG(t*t) - AVG(t)*AVG(t),0) ) AS g_raw + FROM TrendData + GROUP BY artic_id + HAVING COUNT(*) >= 6 + ), + TrendFinal AS ( + SELECT + artic_id, + POWER( + CASE + WHEN POWER(g_raw, 12) < 0.7 THEN 0.7 + WHEN POWER(g_raw, 12) > 1.5 THEN 1.5 + ELSE POWER(g_raw, 12) + END, + 1.0/12 + ) AS Ktrend + FROM TrendAgg + ), + YoYpairs AS ( + SELECT + w.artic_id, + (w.Год*100 + w.Месяц) AS ym, + w.normalized_valid_sales AS v2, + LAG(w.normalized_valid_sales, 12) OVER ( + PARTITION BY w.artic_id ORDER BY (w.Год*100 + w.Месяц) + ) AS v1 + FROM Windowed w + CROSS JOIN LastFullMonth lm + WHERE (w.Год*100 + w.Месяц) <= (lm.last_year*100 + lm.last_month) + ), + YoYratios AS ( + SELECT artic_id, (v2 / v1) AS ratio + FROM YoYpairs + WHERE v1 > 0 AND v2 > 0 + ), + YoYFinal AS ( + SELECT DISTINCT + artic_id, + CASE + WHEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratio) + OVER (PARTITION BY artic_id) < 0.7 THEN 0.7 + WHEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratio) + OVER (PARTITION BY artic_id) > 1.5 THEN 1.5 + ELSE PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratio) + OVER (PARTITION BY artic_id) + END AS Kgrowth_YoY, + COUNT(ratio) OVER (PARTITION BY artic_id) AS cnt_pairs + FROM YoYratios + ), + YoYFiltered AS ( + SELECT artic_id, Kgrowth_YoY + FROM YoYFinal + WHERE cnt_pairs >= 3 + ) + SELECT + n.artic_id, + n.code, + n.description, + a.Base_12M, + a.Base_3M, + CASE + WHEN a.Base_3M IS NOT NULL THEN a.Base_3M + ELSE a.Base_12M + END AS Base_Selected, + tf.Ktrend, + yf.Kgrowth_YoY + FROM pbi.nomenclature n + LEFT JOIN Aggregates a ON n.artic_id = a.artic_id + LEFT JOIN TrendFinal tf ON n.artic_id = tf.artic_id + LEFT JOIN YoYFiltered yf ON n.artic_id = yf.artic_id; + '); + +END; +GO + +/****** Object: StoredProcedure [analytics].[usp_InsertForecasts] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE analytics.usp_InsertForecasts +AS +BEGIN + SET NOCOUNT ON; + + -- Удаляем старые прогнозы + DELETE FROM analytics.forecast + WHERE scenario_id IN (5, 6); + + -- Чистим временные таблицы + IF OBJECT_ID('tempdb..#Params') IS NOT NULL DROP TABLE #Params; + IF OBJECT_ID('tempdb..#Calendar') IS NOT NULL DROP TABLE #Calendar; + + -- #Params + SELECT DATEFROMPARTS( + YEAR(DATEADD(MONTH, -1, MAX(Период))), + MONTH(DATEADD(MONTH, -1, MAX(Период))), + 1 + ) AS LastMonth + INTO #Params + FROM pbi.Себестоимость + WHERE Статья = 'реализация'; + + -- #Calendar + SELECT DATEFROMPARTS(YEAR(d), MONTH(d), 1) AS MonthStart + INTO #Calendar + FROM ( + SELECT TOP (1000) + DATEADD(MONTH, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), + (SELECT LastMonth FROM #Params)) AS d + FROM master..spt_values + ) x + WHERE d <= '2026-12-01'; + + -- Вставка Trend (5) + INSERT INTO analytics.forecast (scenario_id, [1c_id], code, [month], value, updated_at, updated_by) + SELECT + 5, + n.[1c_id], + f.code, + c.MonthStart, + CAST( + ROUND( + f.Base_Selected * sg.seasonal_koef * + POWER(f.Ktrend, DATEDIFF(MONTH, p.LastMonth, c.MonthStart)), + 0 + ) AS numeric(18,0) + ), + GETDATE(), + SUSER_SNAME() + FROM analytics.ForecastBasesKs f + JOIN pbi.nomenclature n ON f.artic_id = n.artic_id + CROSS JOIN #Params p + JOIN #Calendar c ON c.MonthStart > p.LastMonth + JOIN analytics.seasonality_groups sg + ON n.[1c_group] = sg.group_1c_id + AND sg.[month] = MONTH(c.MonthStart) + WHERE f.Base_Selected IS NOT NULL + AND f.Ktrend IS NOT NULL; + + -- Вставка YoY (6) + INSERT INTO analytics.forecast (scenario_id, [1c_id], code, [month], value, updated_at, updated_by) + SELECT + 6, + n.[1c_id], + f.code, + c.MonthStart, + CAST( + ROUND( + f.Base_Selected * sg.seasonal_koef * f.Kgrowth_YoY, + 0 + ) AS numeric(18,0) + ), + GETDATE(), + SUSER_SNAME() + FROM analytics.ForecastBasesKs f + JOIN pbi.nomenclature n ON f.artic_id = n.artic_id + CROSS JOIN #Params p + JOIN #Calendar c ON c.MonthStart > p.LastMonth + JOIN analytics.seasonality_groups sg + ON n.[1c_group] = sg.group_1c_id + AND sg.[month] = MONTH(c.MonthStart) + WHERE f.Base_Selected IS NOT NULL + AND f.Kgrowth_YoY IS NOT NULL; + +END; +GO + +/****** Object: StoredProcedure [analytics].[Подготовка таблицы продаж к прогнозу] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE analytics.[Подготовка таблицы продаж к прогнозу] as +BEGIN + /* ========= ПАРАМЕТРЫ ========= */ + DECLARE @FromDate date = '2023-01-01'; + DECLARE @ToDate date = CAST(GETDATE() AS date); + + /* ========= ВСПОМОГАТЕЛЬНЫЕ: НЕДЕЛЯ С ПОНЕДЕЛЬНИКА ========= */ + IF OBJECT_ID('tempdb..#dates') IS NOT NULL DROP TABLE #dates; + WITH d AS ( + SELECT @FromDate AS d + UNION ALL SELECT DATEADD(day,1,d) FROM d WHERE d < @ToDate + ) + SELECT d AS [date], + DATEADD(day, - (DATEPART(weekday,d) + @@DATEFIRST + 5) % 7, d) AS week_start + INTO #dates + FROM d + OPTION (MAXRECURSION 0); + + CREATE INDEX IX_dates_week ON #dates(week_start); + + /* ========= 1) ПРОДАЖИ (только положительные) ========= */ + IF OBJECT_ID('tempdb..#sales_raw') IS NOT NULL DROP TABLE #sales_raw; + + SELECT + CAST(s.[Период] AS date) AS [date], + s.[1c_id] AS sku_id, + CAST(s.[КоличествоУпаковок] AS decimal(18,4)) AS qty + INTO #sales_raw + FROM [pbiProd].[СводныйСебестоимость Для PBI] s + WHERE + s.[Статья] = N'Реализация' + AND s.[Вид операции] = N'Расход' + AND s.[КоличествоУпаковок] > 0 + AND s.[Период] >= @FromDate + AND s.[Период] <= @ToDate; + + CREATE INDEX IX_sales_raw ON #sales_raw(sku_id, [date]); + + /* ========= 2) ФИЛЬТРУЕМ ПРОДАЖИ ПО НАЛИЧИЮ (ostatok=1 из pbi.w_ostatok_da_net) ========= */ + IF OBJECT_ID('tempdb..#sales_clean_daily') IS NOT NULL DROP TABLE #sales_clean_daily; + + SELECT + sr.sku_id, + sr.[date], + sr.qty + INTO #sales_clean_daily + FROM #sales_raw sr + JOIN [pbi].[w_ostatok_da_net] a + ON a.[_IDRREF] = sr.sku_id + AND a.dt = sr.[date] + AND a.ostatok = 1; + + CREATE INDEX IX_sales_clean_daily ON #sales_clean_daily(sku_id, [date]); + + /* ========= 3) АГРЕГАЦИЯ В НЕДЕЛИ ========= */ + /* 3.1 Продажи по неделям */ + IF OBJECT_ID('tempdb..#sales_weekly') IS NOT NULL DROP TABLE #sales_weekly; + + SELECT + scd.sku_id, + d.week_start, + SUM(scd.qty) AS qty_week + INTO #sales_weekly + FROM #sales_clean_daily scd + JOIN #dates d + ON d.[date] = scd.[date] + GROUP BY scd.sku_id, d.week_start; + + CREATE INDEX IX_sales_weekly ON #sales_weekly(sku_id, week_start); + + /* 3.2 Доля доступности по неделям (из pbi.w_ostatok_da_net) */ + IF OBJECT_ID('tempdb..#avail_weekly') IS NOT NULL DROP TABLE #avail_weekly; + + SELECT + a.[_IDRREF] AS sku_id, + d.week_start, + SUM(a.ostatok) AS days_available, + COUNT(*) AS days_total, + CAST(SUM(a.ostatok) * 1.0 / NULLIF(COUNT(*),0) AS decimal(6,4)) AS availability_rate + INTO #avail_weekly + FROM [pbi].[w_ostatok_da_net] a + JOIN #dates d + ON d.[date] = a.dt + WHERE a.dt BETWEEN @FromDate AND @ToDate + GROUP BY a.[_IDRREF], d.week_start; + + CREATE INDEX IX_avail_weekly ON #avail_weekly(sku_id, week_start); + + /* ========= 4) СКЛЕЙКА: оставляем недели без продаж, если товар был доступен ========= */ + IF OBJECT_ID('tempdb..#weekly_base') IS NOT NULL DROP TABLE #weekly_base; + + SELECT + COALESCE(sw.sku_id, aw.sku_id) AS sku_id, + COALESCE(sw.week_start, aw.week_start) AS week_start, + COALESCE(sw.qty_week, 0) AS qty_week, + COALESCE(aw.availability_rate, 0) AS availability_rate + INTO #weekly_base + FROM #sales_weekly sw + FULL JOIN #avail_weekly aw + ON aw.sku_id = sw.sku_id + AND aw.week_start = sw.week_start; + + CREATE INDEX IX_weekly_base ON #weekly_base(sku_id, week_start); + + /* ========= 5) МЕТАДАННЫЕ SKU (cat L1, minAvailableQty) ========= */ + IF OBJECT_ID('tempdb..#sku_meta') IS NOT NULL DROP TABLE #sku_meta; + + SELECT + n.[1c_id] AS sku_id, + n.minAvailableQty, + CAST(CASE + WHEN CHARINDEX(N' | ', g.path) > 0 + THEN LEFT(g.path, CHARINDEX(N' | ', g.path) - 1) + ELSE g.path + END AS nvarchar(200)) AS category_l1 + INTO #sku_meta + FROM [mag_pbi].[pbi].[nomenclature] n + LEFT JOIN [mag_pbi].[pbi].[groups] g + ON g.group_id = n.group_id; + + CREATE INDEX IX_sku_meta ON #sku_meta(sku_id); + + /* ========= 6) ВИТРИНА С ЛАГАМИ И ФИЧАМИ (analytics) ========= */ + IF OBJECT_ID('analytics.sales_weekly_features', 'U') IS NOT NULL + DROP TABLE analytics.sales_weekly_features; + + CREATE TABLE analytics.sales_weekly_features ( + sku_id varbinary(16) NOT NULL, + week_start date NOT NULL, + qty_week decimal(18,4) NOT NULL, + availability_rate decimal(6,4) NOT NULL, + -- календарные + year_num int NOT NULL, + month_num tinyint NOT NULL, + iso_week tinyint NOT NULL, + quarter_num tinyint NOT NULL, + dow_monday1 tinyint NOT NULL, + -- справочники + category_l1 nvarchar(200) NULL, + minAvailableQty decimal(18,4) NULL, + -- лаги + lag_w1 decimal(18,4) NULL, + lag_w2 decimal(18,4) NULL, + lag_w4 decimal(18,4) NULL, + lag_w12 decimal(18,4) NULL, + lag_w26 decimal(18,4) NULL, + lag_w52 decimal(18,4) NULL, + -- скользящие средние + ma4 decimal(18,4) NULL, + ma12 decimal(18,4) NULL, + created_at datetime2 NOT NULL DEFAULT sysutcdatetime(), + CONSTRAINT PK_sales_weekly_features PRIMARY KEY (sku_id, week_start) + ); + + WITH base AS ( + SELECT wb.sku_id, + wb.week_start, + wb.qty_week, + wb.availability_rate, + YEAR(wb.week_start) AS year_num, + MONTH(wb.week_start) AS month_num, + DATEPART(ISO_WEEK, wb.week_start) AS iso_week, + DATEPART(QUARTER, wb.week_start) AS quarter_num, + 1 AS dow_monday1 + FROM #weekly_base wb + ), + enriched AS ( + SELECT b.*, + m.category_l1, + m.minAvailableQty + FROM base b + LEFT JOIN #sku_meta m + ON m.sku_id = b.sku_id + ), + lags AS ( + SELECT + e.*, + LAG(e.qty_week, 1) OVER (PARTITION BY e.sku_id ORDER BY e.week_start) AS lag_w1, + LAG(e.qty_week, 2) OVER (PARTITION BY e.sku_id ORDER BY e.week_start) AS lag_w2, + LAG(e.qty_week, 4) OVER (PARTITION BY e.sku_id ORDER BY e.week_start) AS lag_w4, + LAG(e.qty_week, 12) OVER (PARTITION BY e.sku_id ORDER BY e.week_start) AS lag_w12, + LAG(e.qty_week, 26) OVER (PARTITION BY e.sku_id ORDER BY e.week_start) AS lag_w26, + LAG(e.qty_week, 52) OVER (PARTITION BY e.sku_id ORDER BY e.week_start) AS lag_w52, + CAST(AVG(e.qty_week) OVER ( + PARTITION BY e.sku_id + ORDER BY e.week_start + ROWS BETWEEN 4 PRECEDING AND 1 PRECEDING + ) AS decimal(18,4)) AS ma4, + CAST(AVG(e.qty_week) OVER ( + PARTITION BY e.sku_id + ORDER BY e.week_start + ROWS BETWEEN 12 PRECEDING AND 1 PRECEDING + ) AS decimal(18,4)) AS ma12 + FROM enriched e + ) + INSERT INTO analytics.sales_weekly_features ( + sku_id, week_start, qty_week, availability_rate, + year_num, month_num, iso_week, quarter_num, dow_monday1, + category_l1, minAvailableQty, + lag_w1, lag_w2, lag_w4, lag_w12, lag_w26, lag_w52, + ma4, ma12 + ) + SELECT + sku_id, week_start, qty_week, availability_rate, + year_num, month_num, iso_week, quarter_num, dow_monday1, + category_l1, minAvailableQty, + lag_w1, lag_w2, lag_w4, lag_w12, lag_w26, lag_w52, + ma4, ma12 + FROM lags; + + CREATE INDEX IX_sales_weekly_features_sku ON analytics.sales_weekly_features(sku_id, week_start); + CREATE INDEX IX_sales_weekly_features_cat ON analytics.sales_weekly_features(category_l1, week_start); +END +GO diff --git a/sql_db_mag_pbi/mag_pbi_tables.sql b/sql_db_mag_pbi/mag_pbi_tables.sql index 35b45b5..13800b4 100644 --- a/sql_db_mag_pbi/mag_pbi_tables.sql +++ b/sql_db_mag_pbi/mag_pbi_tables.sql @@ -1,29 +1,29 @@ USE [mag_pbi] GO -/****** Object: Schema [analytics] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [analytics] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [analytics] GO -/****** Object: Schema [artem] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [artem] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [artem] GO -/****** Object: Schema [ostatki] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [ostatki] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [ostatki] GO -/****** Object: Schema [pbi] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [pbi] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [pbi] GO -/****** Object: Schema [pbiProd] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [pbiProd] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [pbiProd] GO -/****** Object: Schema [sebest] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [sebest] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [sebest] GO -/****** Object: Schema [stg] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Schema [stg] Script Date: 2026-02-22 11:41:00 ******/ CREATE SCHEMA [stg] GO -/****** Object: Table [analytics].[deficit_money_request] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[deficit_money_request] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -48,7 +48,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[deficit_proposal] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[deficit_proposal] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -71,7 +71,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[forecast] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[forecast] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -93,7 +93,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[forecast_history] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[forecast_history] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -115,7 +115,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[forecast_scenarios] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[forecast_scenarios] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -134,7 +134,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[load_log_w_ostatok_da_net] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[load_log_w_ostatok_da_net] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -152,7 +152,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[manufacturer_counterparty_map] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[manufacturer_counterparty_map] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -167,7 +167,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[manufacturer_payment_stage] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[manufacturer_payment_stage] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -185,7 +185,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[manufacturers] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[manufacturers] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -202,7 +202,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[sales_weekly_features] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[sales_weekly_features] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -235,7 +235,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[seasonality_groups] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[seasonality_groups] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -246,7 +246,7 @@ CREATE TABLE [analytics].[seasonality_groups]( [month] [tinyint] NULL, [koef] [numeric(38,23)] NULL) ON [PRIMARY] GO -/****** Object: Table [analytics].[seasonality_groups_summ_1] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[seasonality_groups_summ_1] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -257,7 +257,7 @@ CREATE TABLE [analytics].[seasonality_groups_summ_1]( [month] [tinyint] NULL, [koef] [numeric(38,23)] NULL) ON [PRIMARY] GO -/****** Object: Table [analytics].[stock_balance] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[stock_balance] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -280,7 +280,7 @@ CREATE TABLE [analytics].[stock_balance]( [Остаток склад + МП + в пути + произв., упак] [numeric(26,7)] NULL, [Остаток склад + МП + в пути + произв., руб] [numeric(26,7)] NULL) ON [PRIMARY] GO -/****** Object: Table [analytics].[stock_plan_by_arrival] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[stock_plan_by_arrival] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -304,7 +304,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [analytics].[аналитика за 365 дн.] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[аналитика за 365 дн.] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -334,7 +334,7 @@ CREATE TABLE [analytics].[аналитика за 365 дн.]( [Рентабельность по остатку / квартал] [decimal(38,6)] NULL, [Рентабельность по остатку / будущий год] [decimal(38,6)] NULL) ON [PRIMARY] GO -/****** Object: Table [analytics].[прогноз из excel] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[прогноз из excel] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -347,7 +347,7 @@ CREATE TABLE [analytics].[прогноз из excel]( [user_name] [nvarchar(255)] NULL, [updated_at] [datetime] NULL) ON [PRIMARY] GO -/****** Object: Table [analytics].[срез учетных цен] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [analytics].[срез учетных цен] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -360,7 +360,7 @@ CREATE TABLE [analytics].[срез учетных цен]( [Период] [nvarchar(4000)] NULL, [количество] [numeric(21,9)] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[Turnover] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[Turnover] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -373,7 +373,7 @@ CREATE TABLE [dbo].[Turnover]( [Operation] [int] NULL, [Quantity] [int] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[content_rating] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[content_rating] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -384,7 +384,7 @@ CREATE TABLE [dbo].[content_rating]( [wb] [int] NULL, [magok] [int] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[grades_quartal] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[grades_quartal] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -395,7 +395,7 @@ CREATE TABLE [dbo].[grades_quartal]( [subject] [nvarchar(50)] NULL, [grade] [int] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[lineage_edges] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[lineage_edges] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -410,7 +410,7 @@ CREATE TABLE [dbo].[lineage_edges]( [to_type] [nvarchar(60)] NULL, [edge_source] [varchar(27)] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[lineage_objects] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[lineage_objects] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -424,7 +424,7 @@ CREATE TABLE [dbo].[lineage_objects]( [create_date] [datetime] NULL, [modify_date] [datetime] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[order_source] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[order_source] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -442,7 +442,7 @@ CREATE TABLE [dbo].[order_source]( [campaign_name] [nvarchar(500)] NULL, [banner_group_name] [nvarchar(500)] NULL) ON [PRIMARY] GO -/****** Object: Table [dbo].[site_product] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[site_product] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -459,7 +459,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [dbo].[yandex_direct_criteria_stats] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [dbo].[yandex_direct_criteria_stats] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -486,7 +486,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[GroupsOfNomenclature] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[GroupsOfNomenclature] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -502,7 +502,7 @@ CREATE TABLE [pbiProd].[GroupsOfNomenclature]( [20k] [int] NULL, [upload] [int] NULL) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[Логирование] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[Логирование] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -511,7 +511,7 @@ CREATE TABLE [pbiProd].[Логирование]( [Инфо] [nvarchar(8)] NULL, [Период] [datetime2(0)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[НоменклатураВПроизводствеПоУровням] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[НоменклатураВПроизводствеПоУровням] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -527,7 +527,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьДо2022] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьДо2022] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -579,7 +579,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьИтогиДо2022] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьИтогиДо2022] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -611,7 +611,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьОт2022] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьОт2022] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -678,7 +678,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьПроизводствоОт2022] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьПроизводствоОт2022] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -696,7 +696,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьСводныйОт2022] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьСводныйОт2022] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -759,7 +759,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьСводныйОт2022_copy_2025-03-26] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьСводныйОт2022_copy_2025-03-26] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -813,7 +813,7 @@ CREATE TABLE [pbiProd].[СебестоимостьСводныйОт2022_copy_20 [СборкаЗаказа] [numeric(21,9)] NULL, [КоличествоУпаковок] [numeric(15,3)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[СебестоимостьСводныйОт2022_copy_for_pbi] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[СебестоимостьСводныйОт2022_copy_for_pbi] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -874,7 +874,7 @@ CREATE TABLE [pbiProd].[СебестоимостьСводныйОт2022_copy_fo [Учетная сумма, usd] [decimal(21,9)] NULL, [Источник заказа] [nvarchar(50)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbiProd].[УчетнаяЦенаПоСебестоимости] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbiProd].[УчетнаяЦенаПоСебестоимости] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -885,7 +885,7 @@ CREATE TABLE [pbiProd].[УчетнаяЦенаПоСебестоимости]( [Учетная цена USD2+2] [numeric(15,9)] NULL, [Период] [datetime2(0)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[Turnover] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[Turnover] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -903,7 +903,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[content_rating] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[content_rating] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -915,7 +915,7 @@ CREATE TABLE [pbi].[content_rating]( [wb_by_ozon] [int] NULL, [magok] [int] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[direct_adv_costs] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[direct_adv_costs] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -934,7 +934,7 @@ CREATE TABLE [pbi].[direct_adv_costs]( [Расход, руб] [decimal(18,2)] NULL, [Ср. цена клика, руб] [decimal(18,2)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[direct_orders] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[direct_orders] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -947,7 +947,7 @@ CREATE TABLE [pbi].[direct_orders]( [Количество покупок] [int] NULL, [Доход, руб] [decimal(18,2)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[enums] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[enums] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -957,7 +957,7 @@ CREATE TABLE [pbi].[enums]( [value] [nvarchar(150)] NULL, [enum] [nvarchar(50)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[groups] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[groups] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -977,7 +977,7 @@ CREATE TABLE [pbi].[groups]( [план] [float] NULL, [first group] [nvarchar(36)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[nomenclatureVolumeStorehouse] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[nomenclatureVolumeStorehouse] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -990,7 +990,7 @@ CREATE TABLE [pbi].[nomenclatureVolumeStorehouse]( [volume] [numeric(15,5)] NULL, [totalVolume] [numeric(15,5)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[nomenclature] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[nomenclature] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1072,7 +1072,7 @@ CREATE TABLE [pbi].[nomenclature]( [СКО_МесячныхПродаж] [float] NULL, [minAvailableQty] [decimal(18,4)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[ostatki] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[ostatki] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1093,7 +1093,7 @@ CREATE TABLE [pbi].[ostatki]( [upakovok_ship] [numeric(38,15)] NULL, [quantity_ship] [numeric(38,15)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[ostatki_mp] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[ostatki_mp] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1107,7 +1107,7 @@ CREATE TABLE [pbi].[ostatki_mp]( [Доступно МП, упак] [decimal(18,3)] NULL, [Остаток МП, шт] [decimal(18,3)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[ostatki_short] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[ostatki_short] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1126,7 +1126,7 @@ CREATE TABLE [pbi].[ostatki_short]( [upakovok_ship] [numeric(38,15)] NULL, [quantity_ship] [numeric(38,15)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[pricelist] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[pricelist] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1139,7 +1139,7 @@ CREATE TABLE [pbi].[pricelist]( [Дата] [datetime2(0)] NULL, [_Period] [datetime2(0)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[w_ostatok_da_net] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[w_ostatok_da_net] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1159,7 +1159,7 @@ CREATE TABLE [pbi].[w_ostatok_da_net]( [ostatok_mp] [numeric(15,6)] NULL, [ostatok_all] [numeric(15,6)] NULL) ON [PRIMARY] GO -/****** Object: Table [pbi].[Себестоимость2023] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[Себестоимость2023] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1217,7 +1217,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[Себестоимость2024] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[Себестоимость2024] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1275,7 +1275,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[Себестоимость] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[Себестоимость] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1327,7 +1327,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[СебестоимостьДо2022Тест] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[СебестоимостьДо2022Тест] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1379,7 +1379,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[СебестоимостьПродажи] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[СебестоимостьПродажи] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1415,7 +1415,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[СебестоимостьПродажиОт2022] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[СебестоимостьПродажиОт2022] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1451,7 +1451,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[СебестоимостьПродажиТест] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[СебестоимостьПродажиТест] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1487,7 +1487,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[СебестоимостьСводныйОт2022Тестовый] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[СебестоимостьСводныйОт2022Тестовый] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1545,7 +1545,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [pbi].[СебестоимостьТест] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [pbi].[СебестоимостьТест] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON @@ -1597,7 +1597,7 @@ PRIMARY KEY CLUSTERED )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO -/****** Object: Table [stg].[forecast_load] Script Date: 2026-02-22 11:29:07 ******/ +/****** Object: Table [stg].[forecast_load] Script Date: 2026-02-22 11:41:00 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON diff --git a/sql_db_mag_pbi/mag_pbi_views.sql b/sql_db_mag_pbi/mag_pbi_views.sql index 68c3457..9266f11 100644 --- a/sql_db_mag_pbi/mag_pbi_views.sql +++ b/sql_db_mag_pbi/mag_pbi_views.sql @@ -1,2 +1,2038 @@ USE [mag_pbi] GO + +/****** Object: View [analytics].[deficit_orders] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[deficit_orders] AS + + SELECT + [scenario_id] as [scenario_id] + , 'Дефицит' as [status] + , d.[1c_id] + , [place_month] as [order_date] + , 'руб.' as [currency] + , d.[code] + , [order_qty] + , n.[Цена учетная, руб] as [price] + , d.order_qty * n.[Цена учетная, руб] as [sum] + , [arrival_month] + FROM [mag_pbi].[analytics].[deficit_proposal] d + INNER JOIN pbi.nomenclature n ON n.[1c_id] = d.[1c_id] +GO + +/****** Object: View [analytics].[doprekvizit] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[doprekvizit] +AS +SELECT + CASE WHEN i._Marked = 0x00 THEN 0 ELSE 1 END AS [ПометкаУдаления], + i._Type AS [ТипЗначения], + i._Fld28453 AS [ТипЗначенияВнешнейСистемы], + i._Fld17721 AS [description], + LOWER( + CONCAT( + SUBSTRING(h.hex, 25, 8), '-', + SUBSTRING(h.hex, 21, 4), '-', + SUBSTRING(h.hex, 17, 4), '-', + SUBSTRING(h.hex, 1, 4), '-', + SUBSTRING(h.hex, 5, 12) + ) + ) AS [uid], + i._Fld28554 AS [ИмяВоВнешнейСистеме], + CASE i._Fld28553 WHEN 0x01 THEN 1 ELSE 0 END AS [ВыгружатьВоВнешниеСистемы], + CASE i._Fld33511 WHEN 0x01 THEN 1 ELSE 0 END AS [ВыгружатьНаСайт], + CASE i._Fld28529 WHEN 0x01 THEN 1 ELSE 0 END AS [ФильтрНаСайте], + CASE i._Fld28530 WHEN 0x01 THEN 1 ELSE 0 END AS [ОтображатьНаСайте], + CASE i._Fld27792 WHEN 0x01 THEN 1 ELSE 0 END AS [АТС_НеПроверять], + CASE i._Fld17724 WHEN 0x01 THEN 1 ELSE 0 END AS [ЗаполнятьОбязательно] +FROM MAG_2019.dbo._Chrc1109 AS i +CROSS APPLY (SELECT CONVERT(varchar(36), i._IDRRef, 2) AS hex) AS h; +GO + +/****** Object: View [analytics].[doprekvizitvalues] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[doprekvizitvalues] +AS +SELECT + n._Code AS [code], + 'DopRekvizit' AS [type], + + -- GUID r._Reference188_IDRRef в текстовом виде (uid) + LOWER( + SUBSTRING(h.hex_ref,25,8) + '-' + + SUBSTRING(h.hex_ref,21,4) + '-' + + SUBSTRING(h.hex_ref,17,4) + '-' + + SUBSTRING(h.hex_ref, 1,4) + '-' + + SUBSTRING(h.hex_ref, 5,12) + ) AS [uid], + + r._Reference188_IDRRef AS [uid_bin], + r._Fld21137RRef AS [value_bin], + r._Fld21137RRef AS [name_uid_bin], + + -- GUID r._Fld21137RRef в текстовом виде (name_uid) + LOWER( + SUBSTRING(h.hex_name,25,8) + '-' + + SUBSTRING(h.hex_name,21,4) + '-' + + SUBSTRING(h.hex_name,17,4) + '-' + + SUBSTRING(h.hex_name, 1,4) + '-' + + SUBSTRING(h.hex_name, 5,12) + ) AS [name_uid], + + c._Fld17721 AS [name], + + pbi.get_rekvizit_value( + r._Reference188_IDRRef, + r._Fld21137RRef, + r._Fld21138_TYPE, + r._Fld21138_L, + r._Fld21138_N, + r._Fld21138_T, + r._Fld21138_S, + r._Fld21138_RTRef, + r._Fld21138_RRRef + ) AS [value] +FROM MAG_2019.dbo._Reference188_VT21135X1 AS r +INNER JOIN MAG_2019.dbo._Reference188X1 AS n ON r._Reference188_IDRRef = n._IDRRef +INNER JOIN MAG_2019.dbo._Chrc1109 AS c ON c._IDRRef = r._Fld21137RRef +CROSS APPLY ( + SELECT + CONVERT(varchar(36), r._Reference188_IDRRef, 2) AS hex_ref, + CONVERT(varchar(36), r._Fld21137RRef, 2) AS hex_name +) AS h; +GO + +/****** Object: View [analytics].[ForecastBasesKs] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[ForecastBasesKs] AS +WITH MaxDate AS ( + SELECT MAX(Период) AS max_date + FROM [pbiProd].[СводныйСебестоимость Для PBI] + WHERE Статья = 'реализация' +), +LastFullMonth AS ( + SELECT + YEAR(DATEADD(MONTH, -1, max_date)) AS last_year, + MONTH(DATEADD(MONTH, -1, max_date)) AS last_month + FROM MaxDate +), + +-- 1. Продажи по SKU × месяц +Sales AS ( + SELECT + artic_id, + YEAR(Период) AS Год, + MONTH(Период) AS Месяц, + SUM(Количество) AS total_sales + FROM [pbiProd].[СводныйСебестоимость Для PBI] + WHERE Статья = 'реализация' + GROUP BY artic_id, YEAR(Период), MONTH(Период) +), + +-- 2. Дни в продаже (по флагу ostatok_all) +Stock AS ( + SELECT + artic_id, + YEAR(dt) AS Год, + MONTH(dt) AS Месяц, + SUM(CASE WHEN ostatok_all = 1 THEN 1 ELSE 0 END) AS days_available + FROM [pbi].[w_ostatok_da_net] + GROUP BY artic_id, YEAR(dt), MONTH(dt) +), + +-- 3. База: нормализованные продажи (только Основной + Маркетплейс) +Base AS ( + SELECT + s.artic_id, + n.code, + n.description, + s.Год, + s.Месяц, + s.total_sales, + st.days_available, + -- сезонность: либо родная, либо общая (по группе 0) + COALESCE(sg_main.seasonal_koef, sg_def.seasonal_koef) AS seasonal_koef, + s.total_sales / NULLIF(COALESCE(sg_main.seasonal_koef, sg_def.seasonal_koef), 0) AS Normalized_sales, + CASE WHEN st.days_available > 19 THEN 1 ELSE 0 END AS valid_month, + CASE WHEN st.days_available > 19 + THEN s.total_sales / NULLIF(COALESCE(sg_main.seasonal_koef, sg_def.seasonal_koef), 0) + ELSE NULL + END AS normalized_valid_sales + FROM Sales s + LEFT JOIN Stock st + ON s.artic_id = st.artic_id + AND s.Год = st.Год + AND s.Месяц = st.Месяц + JOIN [pbi].[nomenclature] n + ON s.artic_id = n.artic_id + LEFT JOIN [analytics].[seasonality_groups] sg_main + ON n.[1c_group] = sg_main.group_1c_id + AND s.Месяц = sg_main.[month] + LEFT JOIN [analytics].[seasonality_groups] sg_def + ON sg_def.group_1c_id = 0x00000000000000000000000000000000 + AND sg_def.[month] = s.Месяц + WHERE n.Статус IN ('Основной', 'Маркетплейс') +), + +-- 4. Пронумеровка месяцев (только до последнего полного месяца) +Windowed AS ( + SELECT + b.*, + ROW_NUMBER() OVER ( + PARTITION BY b.artic_id + ORDER BY (b.Год*100 + b.Месяц) DESC + ) AS rn_desc + FROM Base b + CROSS JOIN LastFullMonth lm + WHERE (b.Год*100 + b.Месяц) <= (lm.last_year*100 + lm.last_month) +), + +-- 4b. Последний валидный месяц (строгий, для контроля) +LastValid AS ( + SELECT artic_id, normalized_valid_sales AS Base_LastMonth + FROM ( + SELECT + artic_id, + normalized_valid_sales, + ROW_NUMBER() OVER ( + PARTITION BY artic_id + ORDER BY (Год*100 + Месяц) DESC + ) AS rn + FROM Windowed + WHERE valid_month = 1 + AND normalized_valid_sales IS NOT NULL + ) x + WHERE rn = 1 +), + +-- 5. Строгие базы (12M, 3M) – только по валидным месяцам +StrictAggregates AS ( + SELECT + w.artic_id, + AVG(CASE WHEN rn_desc <= 12 AND valid_month = 1 THEN normalized_valid_sales END) AS Base_12M, + CASE + WHEN MIN(CASE WHEN rn_desc <= 3 THEN valid_month END) = 1 + THEN AVG(CASE WHEN rn_desc <= 3 THEN normalized_valid_sales END) + ELSE NULL + END AS Base_3M + FROM Windowed w + GROUP BY w.artic_id +), + +-- 6. Irregular-база: средняя нормализованная продажа за последние 12 календарных месяцев, +-- только по месяцам с total_sales > 0 +IrregularBase AS ( + SELECT + w.artic_id, + AVG(w.Normalized_sales) AS Base_Irregular + FROM Windowed w + CROSS JOIN LastFullMonth lm + WHERE (w.Год * 12 + w.Месяц) > (lm.last_year * 12 + lm.last_month - 12) -- последние 12 месяцев + AND (w.Год * 12 + w.Месяц) <= (lm.last_year * 12 + lm.last_month) + AND w.total_sales > 0 + AND w.Normalized_sales IS NOT NULL + GROUP BY w.artic_id +), + +-- 7. TREND (регрессия по ln(sales), окно ~24 мес по валидным) +TrendData AS ( + SELECT + w.artic_id, + ROW_NUMBER() OVER ( + PARTITION BY w.artic_id + ORDER BY (w.Год*100 + w.Месяц) + ) - 1 AS t, + LOG(w.normalized_valid_sales) AS ln_sales + FROM Windowed w + CROSS JOIN LastFullMonth lm + WHERE (w.Год*100 + w.Месяц) > (lm.last_year*100 + lm.last_month - 200) + AND (w.Год*100 + w.Месяц) <= (lm.last_year*100 + lm.last_month) + AND w.normalized_valid_sales > 0 +), +TrendAgg AS ( + SELECT + artic_id, + COUNT(*) AS n_obs, + EXP( + (AVG(t*ln_sales) - AVG(t)*AVG(ln_sales)) + / NULLIF(AVG(t*t) - AVG(t)*AVG(t), 0) + ) AS g_raw + FROM TrendData + GROUP BY artic_id + HAVING COUNT(*) >= 6 +), +TrendFinal AS ( + SELECT + artic_id, + POWER( + CASE + WHEN POWER(g_raw, 12) < 0.7 THEN 0.7 + WHEN POWER(g_raw, 12) > 1.5 THEN 1.5 + ELSE POWER(g_raw, 12) + END, + 1.0/12 + ) AS Ktrend + FROM TrendAgg +) + +-- === ФИНАЛ (одна строка на активный SKU) === +SELECT + n.artic_id, + n.code, + n.description, + -- строгие базы + sa.Base_12M, + sa.Base_3M, + ib.Base_Irregular, + -- единая выбранная база + CASE + WHEN sa.Base_3M IS NOT NULL THEN sa.Base_3M + WHEN sa.Base_12M IS NOT NULL THEN sa.Base_12M + ELSE ib.Base_Irregular + END AS Base_Selected, + lv.Base_LastMonth, + tf.Ktrend +FROM pbi.nomenclature n +LEFT JOIN StrictAggregates sa ON n.artic_id = sa.artic_id +LEFT JOIN IrregularBase ib ON n.artic_id = ib.artic_id +LEFT JOIN LastValid lv ON n.artic_id = lv.artic_id +LEFT JOIN TrendFinal tf ON n.artic_id = tf.artic_id +WHERE n.Статус IN ('Основной', 'Маркетплейс'); +GO + +/****** Object: View [analytics].[get_analytics_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[get_analytics_by_group] +AS +SELECT + n.code + , a.[Остаток дней продаж] + , a.[Дней в продаже / год] + , a.[Дней в продаже / квартал] + , a.[Продажи шт / день] + , a.[ТН / год, руб.] + , a.[ТН / квартал, руб.] + , a.[ТН / месяц, руб.] + , a.[Стоимость МП год, руб.] + , a.[%ТН год, руб.] + , a.[учетная сумма / год, руб.] + , a.[Оплаченный остаток] + , a.[Рентабельность / год] + , a.[Рентабельность / квартал] + , a.[Рентабельность / будущий год] + , [Рентабельность по остатку / год] + , [Рентабельность по остатку / квартал] + , [Рентабельность по остатку / будущий год] +FROM + analytics.[аналитика за 365 дн.] AS a + INNER JOIN pbi.nomenclature AS n ON n.[1c_id] = a.[1c_id] + INNER JOIN pbi.groups AS g ON n.[1c_group] = g.[1c_id] +WHERE (g.g NOT LIKE '*%') +GO + +/****** Object: View [analytics].[get_forecast_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[get_forecast_by_group] as +SELECT + n.code as code + ,f.[scenario_id] + ,FORMAT(f.[month], 'yyyy-MM-01') AS [month] + ,f.[value] as quantity_base + ,g.path +FROM [mag_pbi].[analytics].forecast f + INNER JOIN mag_pbi.pbi.nomenclature n /*номенклатура*/ + ON n.[1c_id] = f.[1c_id] + INNER JOIN mag_pbi.pbi.groups g + ON n.[1c_group] = g.[1c_id] +WHERE g.g not like '*%' AND [value] > 0 +GO + +/****** Object: View [analytics].[get_forecast_scenarios] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[get_forecast_scenarios] as +SELECT [scenario_id] + ,[name] + ,[description] + ,[created_by] + FROM [mag_pbi].[analytics].[forecast_scenarios] + WHERE active = 1 +GO + +/****** Object: View [analytics].[get_mp_quantity_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE view [analytics].[get_mp_quantity_by_group] as + + + + SELECT + t.code + , [Узел] + , [Склад] + , g.path + , [Доступное кол-во] as quantity + , [Доступное кол-во] + * + (case + (SELECT TOP 1 upakovka FROM pbi.[БазоваяУпаковка] up WHERE t.[1c_id] = up._OwnerID_RRRef) + when 0 then 1 + when null then 1 + else (SELECT TOP 1 upakovka FROM pbi.[БазоваяУпаковка] up WHERE t.[1c_id] = up._OwnerID_RRRef) + end) + as quantity_base + + --, (SELECT TOP 1 [Доступное кол-во] FROM [mag_pbi].[analytics].[Внешние остатки] v WHERE v.[code]=t.[code] AND v.[Узел]=t.[Узел] AND v.[Склад]=t.[Склад] ORDER BY [Дата обновления] DESC) as quantity + FROM [mag_pbi].[analytics].[Внешние остатки] as t + INNER JOIN [mag_pbi].[pbi].[groups] g ON t.group_id = g.[1c_id] + WHERE t.[Дата обновления] >= FORMAT(GETDATE(), 'yyyy-MM-dd') +GO + +/****** Object: View [analytics].[get_mpcosts_monthly_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE view [analytics].[get_mpcosts_monthly_by_group] as +SELECT + sales.date + , n.code as code + , g.path + , sum(sales.sum) as sum +FROM +( + select + FORMAT([date], 'yyyy-MM') as date + , s.Сумма as sum + , s.[1c_id] + + FROM [mag_pbi].[pbi].[Стоимость обработки заказа] s + +) as sales +INNER JOIN [mag_pbi].[pbi].nomenclature n + ON n.[1c_id] = sales.[1c_id] +INNER JOIN [mag_pbi].[pbi].[groups] g ON n.[1c_group] = g.[1c_id] + +GROUP BY sales.date, n.code, g.path +GO + +/****** Object: View [analytics].[get_nomenclature_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE view [analytics].[get_nomenclature_by_group] as + SELECT + n.code as code, + n.description as 'description', + n.artic as artic, + g.path, + --concat('https://media.magok.ru/', f._Fld21201) as 'photo', + n.photo, + n.Производитель as 'manufacturer', + n.Бренд as 'brand', + n.[1c_id] as [1C_id], + n.[Статус] as status, + n.[АБС статус] as ABC + , wb._Fld28246 as [WB] + , wbip._Fld28246 as [WBIP] + , ozon._Fld28246 as [OZON] + , ozonip._Fld28246 as [OZONIP] + --, factory.Количество as factoryQuantity + --, way.Количество as onwayQuantity + , n.[max_year_quantity] + , n.[max_quarter_quantity] + , n.[Цена учетная, руб] + , n.[Цена учетная, usd] + , n.[СКО_МесячныхПродаж] + , n.cenovaya_gruppa + from [mag_pbi].[pbi].nomenclature n /*номенклатура*/ + --INNER JOIN [mag_reports].[sales].[w_groups] g + INNER JOIN mag_pbi.pbi.groups g + ON n.[1c_group] = g.[1c_id] + /*LEFT JOIN [mag_2019].[dbo]._Reference191X1 f /*номенклатураПрисоедФайлы*/ + ON f._IDRRef = n._Fld21086RRef*/ + LEFT JOIN [MAG_2019].[dbo].[_InfoRg28243X1] wbip -- идентификаторы объектов во внешних системах + ON wbip.[_Fld28244_RRRef] = n.[1c_id] AND wbip._Fld28245RRef = 0x997FB49691D57EFD11ED51180696FB46 + + LEFT JOIN [MAG_2019].[dbo].[_InfoRg28243X1] ozonip -- идентификаторы объектов во внешних системах + ON ozonip.[_Fld28244_RRRef] = n.[1c_id] AND ozonip._Fld28245RRef = 0x9987B49691D57EFD11EED582B1EEAA3C + + LEFT JOIN [MAG_2019].[dbo].[_InfoRg28243X1] ozon -- идентификаторы объектов во внешних системах + ON ozon.[_Fld28244_RRRef] = n.[1c_id] AND ozon._Fld28245RRef = 0xAEC3B496910DCFD611EC0EF79C3B458F + + LEFT JOIN [MAG_2019].[dbo].[_InfoRg28243X1] wb -- идентификаторы объектов во внешних системах + ON wb.[_Fld28244_RRRef] = n.[1c_id] AND wb._Fld28245RRef = 0xAEC3B496910DCFD611EC000B54C819F4 + /* + LEFT JOIN [mag_pbi].[pbi].[Заказо_в_производстве] factory + ON factory.[1C_id] = n.[1c_id] + LEFT JOIN [mag_pbi].[pbi].[Заказо_в_пути] way + ON way.[1C_id] = n.[1c_id] + */ + --WHERE n._Folder = 1 + --AND g.path like 'Игрушки%' +/* + SELECT + n.code + , n.description + , n.artic + , g.path + , n.photo + FROM [mag_pbi].[pbi].[nomenclature] n + INNER JOIN [mag_reports].[sales].[w_groups] g + ON n.group_id = g.group_id +*/ +GO + +/****** Object: View [analytics].[get_orders_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE view [analytics].[get_orders_by_group] as + SELECT + z.[Статус] as status + ,z.[Номер заказа поставщику] as order_number + ,z.[1C_id] + ,z.[Дата заказа поставщику] as order_date + ,z.Валюта as currency + , n._code as 'code' + ,[Кол. упаковок] as packages + ,z.Количество as units + ,[Цена] as price + ,[Сумма в руб.] as 'sum' + , z.Сумма as amount + ,FORMAT([Желаемая дата], 'yyyy-MM') as 'month' + ,g.path + FROM [mag_pbi].[analytics].[Заказы] z + INNER JOIN [mag_2019].[dbo]._Reference188X1 n /*номенклатура*/ ON n._IDRRef = z.[1c_id] + INNER JOIN [mag_pbi].[pbi].[groups] g ON n._ParentIDRRef = g.[1c_id] + --WHERE [Статус]='В пути' OR [Статус] = 'В производстве' OR [Статус] = 'Выгружен на складе' +WHERE + z.Статус NOT IN ('Тех. заказ', 'Подтвержден' ,'Закрыт') +GO + +/****** Object: View [analytics].[get_orders_list] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[get_orders_list] AS +SELECT + DATEADD(YEAR, -2000, z._Date_Time) AS [Дата заказа поставщику], + CAST(DATEADD(YEAR, -2000, z._Fld3420) AS DATE) AS [Желаемая дата поступления], + z._Number AS [Номер заказа поставщику], + + p._Description AS [Партнер], + r._Description AS [Контрагент], + + CASE z._Fld3417RRef + WHEN 0xB9440E49408A17534955319EBF0DAE60 THEN N'Согласован' + WHEN 0x99FD3E66AA3EFB074984044D5A69CFD5 THEN N'В производстве' + WHEN 0x973A5675AC6A17F64DA37EC6C22FC12C THEN N'Частично отгружен' + WHEN 0xA55F81415BA33BC24A053ED26C6EC02E THEN N'Заказ отменён' + WHEN 0xA87A8B13710A30B447DFF1614E84D167 THEN N'В пути и произв.' + WHEN 0x8542BD023FE7B70E4613087D853F26E4 THEN N'Полностью отгружен' + WHEN 0xB38AD6232E2D17D44287D9924E5E6DF2 THEN N'Нет в заявке на оплату' + WHEN 0xB2A33CF1C728AF3463F20D54AE5A0BC THEN N'Заявка в процессе' + ELSE N'Неизвестно' + END AS [Статус], + + v._Description AS [Валюта], + z._Fld3418 AS [Сумма], + + CASE v._Description + WHEN 'USD' THEN z._Fld3418 * (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency='USD2') + ELSE z._Fld3418 * (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency=v._Description) + END AS [Сумма в руб], + + ISNULL(man.[manufacturer], N'Не найдено') AS manufacturer, + ISNULL(man.[ROI_norm], 136) / 100 AS roi_year_normalized, + man.[n_percent], + man.[n_days], + man.[m_percent], + man.[m_days], + + CASE WHEN z._Fld3418 = 0 THEN 0 + ELSE ( + SELECT SUM(zak.[Сумма] * a.[%ТН год, руб.]) + FROM [analytics].[Заказы] zak + INNER JOIN [analytics].[аналитика за 365 дн.] a ON a.[1c_id] = zak.[1C_id] + WHERE zak.[Номер заказа поставщику] = z._Number + ) / z._Fld3418 + END AS [average_year_turnover], + + z._Fld3432 AS comment + +FROM MAG_2019.dbo._Document408X1 AS z +LEFT JOIN MAG_2019.dbo._Reference215X1 AS p ON p._IDRRef = z._Fld3409RRef -- Партнёр +LEFT JOIN MAG_2019.dbo._Reference168 AS r ON r._IDRRef = z._Fld3410RRef -- Контрагент +LEFT JOIN MAG_2019.dbo._Reference50 AS v ON v._IDRRef = z._Fld3414RRef -- Валюта +LEFT JOIN [analytics].[manufacturer_counterparty_map] map ON map.contractor_1c_id = r._IDRRef +LEFT JOIN [analytics].[v_manufacturers_roi_compat] man ON man.id = map.manufacturer_id + +WHERE z._Posted = 1 + AND z._Marked = 0 + AND z._Fld3417RRef <> 0xA55F81415BA33BC24A053ED26C6EC02E -- не «Заказ отменён» + AND z._Fld3417RRef <> 0x8542BD023FE7B70E4613087D853F26E4 -- не «Полностью отгружен» + AND z._Fld3417RRef <> 0x973A5675AC6A17F64DA37EC6C22FC12C; -- не «Частично отгружен» +GO + +/****** Object: View [analytics].[get_quantity_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE view [analytics].[get_quantity_by_group] as + SELECT + n.Code as code + , s._Description as sklad + , s.[Категория] as [Категория склада] + --, sum( [_Fld17491]*(case _RecordKind when 0 then 1 when 1 then -1 end) ) as quantity + , convert( decimal(10,2), sum( [_Fld17491]*(case _RecordKind when 0 then 1 when 1 then -1 end) ) ) as quantity_base + , convert( + decimal(10,2), sum( [_Fld17491]*(case _RecordKind when 0 then 1 when 1 then -1 end) ) + / + (case + (SELECT TOP 1 upakovka FROM pbi.[БазоваяУпаковка] up WHERE n.[1c_id] = up._OwnerID_RRRef) + when 0 then 1 + when null then 1 + else (SELECT TOP 1 upakovka FROM pbi.[БазоваяУпаковка] up WHERE n.[1c_id] = up._OwnerID_RRRef) + end) + ) as quantity + , g.path + FROM [mag_2019].[dbo].[_AccumRg17484] t /*регистр товары на складах*/ + INNER JOIN [mag_pbi].[pbi].nomenclature n /*номенклатура*/ ON n.[1c_id] = t._Fld17485RRef + INNER JOIN [mag_pbi].[pbi].[groups] g ON n.[1c_group] = g.[1c_id] + INNER JOIN [mag_pbi].[pbi].[sklad_2019] s /*склад*/ ON s._IDRRef = t._Fld17488RRef + WHERE s.[Категория]='Хранение' OR s.[Категория]='Фасовка' OR s.[Категория] = 'Розничная точка' --g.path like 'Игрушки%' + GROUP BY n.code, s._Description, s.[Категория], g.path, n.[1c_id] +GO + +/****** Object: View [analytics].[get_sales_monthly_by_group] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +/* +select + sum([Сумма]) + , (SELECT sum([Сумма]) FROM [mag_pbi].[pbi].[Стоимость обработки заказа] obr WHERE obr.[1c_id] = s.[1c_id]) +FROM [mag_pbi].[pbiProd].[СебестоимостьСводныйОт2022] s +WHERE [Вид операции]='Расход' AND [Статья]='Реализация' + AND code = 'УТ-00210548' +GROUP BY s.[1c_id] +*/ +CREATE view [analytics].[get_sales_monthly_by_group] as +SELECT + sales.date + , n._Code as code + , g.path + , sum(sales.sum) as sum + , sum(sales.quantity) as quantity + , sum(sales.quantity_base) as quantity_base +FROM +( + select + FORMAT([Период], 'yyyy-MM') as date + , s.Сумма as sum + , s.[1c_id] + , s.Количество as quantity_base + , s.КоличествоУпаковок as quantity + FROM [mag_pbi].[pbiProd].[СебестоимостьСводныйОт2022] s + WHERE [Вид операции]='Расход' AND [Статья]='Реализация' +) as sales +INNER JOIN [mag_2019].[dbo]._Reference188X1 n + ON n._IDRRef = sales.[1c_id] +INNER JOIN [mag_pbi].[pbi].[groups] g ON n._ParentIDRRef = g.[1c_id] + +GROUP BY sales.date, n._Code, g.path +GO + +/****** Object: View [analytics].[images] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[images] +AS +SELECT + n._Code AS [КодУТ], + + -- GUID r._IDRRef -> текст (КартинкаИД) + LOWER( + SUBSTRING(h.hex_r,25,8) + '-' + + SUBSTRING(h.hex_r,21,4) + '-' + + SUBSTRING(h.hex_r,17,4) + '-' + + SUBSTRING(h.hex_r, 1,4) + '-' + + SUBSTRING(h.hex_r, 5,12) + ) AS [КартинкаИД], + + -- Путь к файлу + CONCAT('media.magok.ru/', r._Fld21201) AS [Путь], + + CASE WHEN r._Fld28532 = 0x01 THEN 1 ELSE 0 END AS [Основное], + ISNULL(v._Description, N'') AS [ВнешняяСистема], + CASE WHEN r._Marked = 0x00 THEN 0 ELSE 1 END AS [ПометкаУдаления], + + -- GUID n._IDRRef -> текст (НоменклатураИД) + LOWER( + SUBSTRING(h.hex_n,25,8) + '-' + + SUBSTRING(h.hex_n,21,4) + '-' + + SUBSTRING(h.hex_n,17,4) + '-' + + SUBSTRING(h.hex_n, 1,4) + '-' + + SUBSTRING(h.hex_n, 5,12) + ) AS [НоменклатураИД] +FROM MAG_2019.dbo._Reference191X1 AS r +INNER JOIN MAG_2019.dbo._Reference188X1 AS n + ON n._IDRRef = r._Fld21192RRef +LEFT JOIN MAG_2019.dbo._Node28072X1 AS v + ON v._IDRRef = r._Fld28611RRef +CROSS APPLY ( + SELECT + CONVERT(varchar(36), r._IDRRef, 2) AS hex_r, + CONVERT(varchar(36), n._IDRRef, 2) AS hex_n +) AS h; +GO + +/****** Object: View [analytics].[income_expence] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE view [analytics].[income_expence] as +SELECT + t.*, + CONCAT(t.[Номер документа], ' ', t.[Дата]) as 'Номер_Дата' +FROM + -- См. WHERE в самом низу + -- WHERE g <> 'Прочие перемещения ДС' AND [Статья ДДС] <> 'Закупка_Приобретение валюты' +( + SELECT + '' as 'Получатель' + , c.[path] as 'path' + , case WHEN c.g1='Конвертация валюты' THEN 'Закупка' ELSE c.first_group END as g + , c.g1 + , c.g2 + , c.g3 + , c.g4 + , c._Description as 'Статья ДДС' + , e.value as 'operation' + , convert(date, DATEADD(year, -2000, [_Period]), 104) as 'Дата' + , FORMAT(DATEADD(year, -2000, [_Period]), 'yyyy') as 'Год' + , FORMAT(DATEADD(year, -2000, [_Period]), 'MM') as 'Месяц' + ,case _RecordKind when 1 then -acc._Fld16165 / 1000 when 0 then acc._Fld16165 / 1000 end as 'Сумма' + ,case _RecordKind when 1 then -acc._Fld16166 / 1000 when 0 then acc._Fld16166 / 1000 end as 'Сумма упр(приход)' + ,case _RecordKind when 1 then -acc._Fld16167 / 1000 when 0 then acc._Fld16167 / 1000 end as 'Сумма регл(приход)' + , org._Description as 'organization' + , rs._Description as 'schet' + , 'Безнал' as 'type' + , (SELECT _DESCRIPTION FROM [MAG_2019].[dbo].[_Reference50] /*валюты*/ v WHERE v._IDRRef = rs._Fld18073RRef) as 'valuta' + , case acc._RecorderTRef + WHEN 0x000001FD THEN + (SELECT d._Number FROM MAG_2019.dbo._Document509 d WHERE d._IDRRef = acc._RecorderRRef ) + WHEN 0x000001E1 THEN + (SELECT d._Number FROM MAG_2019.dbo._Document481 d WHERE d._IDRRef = acc._RecorderRRef ) + WHEN 0x000001F1 THEN + (SELECT d._Number FROM MAG_2019.dbo._Document497 d WHERE d._IDRRef = acc._RecorderRRef ) + WHEN 0x00000181 THEN + (SELECT d._Number FROM MAG_2019.dbo._Document385 d WHERE d._IDRRef = acc._RecorderRRef ) + END as [Номер документа] + + FROM [mag_2019].[dbo].[_AccumRg16162] acc /* регистр денежные средства б/н */ + LEFT JOIN [MAG_2019].[dbo].[_Reference198X1] org ON org._IDRRef = acc._Fld16163RRef/*справочник организации*/ + LEFT JOIN [MAG_2019].[dbo].[_Reference47] rs ON rs._IDRRef = acc._Fld16164RRef/* справочник банковские счета */ + LEFT JOIN [mag_reports].[costs].[costs_groups] c ON c._IDRref = acc._Fld16171RRef /* статья ДДС */ + LEFT JOIN mag_reports.dbo.enums e ON e._IDRref = acc._Fld16170RRef AND e.enum = 'Хоз. операции'/*Перечисление хозяйственная операция*/ + WHERE 1=1 + --AND path not like '%Прочие перемещения ДС%' + -- WHERE path is not null + /*and path not like '%Сдача денежных средств в банк (в рублях)%' + and path not like '%Перевод ДС ИП - ЧП%' + and path not like '%Прочие перемещения ДС %' + and path not like '%Расходы | расход%' + */ + + UNION all + + SELECT + ( SELECT _Description FROM [MAG_2019].dbo._Reference168 /* контрагенты */ WHERE _IDRRef = + (SELECT top 1 _Fld3891RRef FROM [MAG_2019].dbo._Document416 /* заявка на расход ДС */ d416 WHERE d416._IDRref = /*ro_tbl._Fld7773RRef*/ + (SELECT top 1 _Document495_IDRRef FROM [MAG_2019].dbo._Document495_VT7759 ro_tbl /* Расходный кассовый ордер табл */ WHERE ro_tbl._Document495_IDRRef = ro._IDRRef ) + ) + ) + as 'Получатель' + , c.[path] as 'path' + , case WHEN c.g1='Конвертация валюты' THEN 'Закупка' ELSE c.first_group END as g + , c.g1 + , c.g2 + , c.g3 + , c.g4 + , c._Description as 'Статья ДДС' + , e.value as 'operation' + , convert(date, DATEADD(year, -2000, [_Period]), 104) as 'Дата' + , FORMAT(DATEADD(year, -2000, [_Period]), 'yyyy') as 'Год' + , FORMAT(DATEADD(year, -2000, [_Period]), 'MM') as 'Месяц' + ,case _RecordKind when 1 then -_Fld16220 / 1000 when 0 then _Fld16220 / 1000 end as 'Сумма' + ,case _RecordKind when 1 then -acc._Fld16221 / 1000 when 0 then acc._Fld16221 / 1000 end as 'Сумма упр(приход)' + ,case _RecordKind when 1 then -acc._Fld16222 / 1000 when 0 then acc._Fld16222 / 1000 end as 'Сумма регл(приход)' + , org._Description + , k._Description + ,'Наличные' as 'type' + ,(SELECT _DESCRIPTION FROM [MAG_2019].[dbo].[_Reference50] /*валюты*/ v WHERE v._IDRRef = k._Fld20385RRef) as 'valuta' + , case acc._RecorderTRef + WHEN 0x000001EF THEN + (SELECT d._Number FROM MAG_2019.dbo._Document495 d WHERE d._IDRRef = acc._RecorderRRef ) + WHEN 0x000001E5 THEN + (SELECT d._Number FROM MAG_2019.dbo._Document485 d WHERE d._IDRRef = acc._RecorderRRef ) + WHEN 0x000001F1 THEN + (SELECT d._Number FROM MAG_2019.dbo._Document497 d WHERE d._IDRRef = acc._RecorderRRef ) + WHEN 0x00000181 THEN + (SELECT d._Number FROM MAG_2019.dbo._Document385 d WHERE d._IDRRef = acc._RecorderRRef ) + END as [Номер документа] + FROM [mag_2019].[dbo].[_AccumRg16217] acc /* регистр денежные средства нал */ + LEFT JOIN [MAG_2019].[dbo].[_Reference198X1] org ON org._IDRRef = acc._Fld16218RRef/*справочник организации*/ + LEFT JOIN [MAG_2019].[dbo].[_Reference147] k /* кассы */ ON k._IDRRef = acc._Fld16219RRef + + LEFT JOIN [mag_reports].[costs].[costs_groups] c ON c._IDRref = acc._Fld16224RRef + LEFT JOIN mag_reports.dbo.enums e ON e._IDRref = acc._Fld16223RRef AND e.enum = 'Хоз. операции'/*Перечисление хозяйственная операция*/ + + LEFT JOIN [MAG_2019].dbo._Document495 ro /* Расходный кассовый ордер */ ON ro._IDRRef = acc._RecorderRRef + WHERE + 1=1 + --AND path not like '%Прочие перемещения ДС%' + --path is not null + /*and path not like '%Сдача денежных средств в банк (в рублях)%' + and path not like '%Перевод ДС ИП - ЧП%' + and path not like '%Прочие перемещения ДС %' + and path not like '%Расходы | расход%'*/ + +/* + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-01-01', 0, -652685 / 1000 , -652685 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-02-01', 0, -847900 / 1000 , -847900 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-03-01', 0, -856435 / 1000 ,- 856435 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-04-01', 0, -974905 / 1000 , -974905 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-05-01', 0, -977626 / 1000 , -977626 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-06-01', 0, -662517 / 1000 , -662517 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-07-01', 0, -748000 / 1000 , -748000 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-08-01', 0, -877971 / 1000 , -877971 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-09-01', 0, -946906 / 1000 , -946906 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-10-01', 0, -1325939 / 1000 , -1325939 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-11-01', 0, -1172364 / 1000 , -1172364 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2019-12-01', 0, -946108 / 1000 , -946108 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-01-01', 0, -955189 / 1000 , -955189 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-02-01', 0, -987967 / 1000 , -987967 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-03-01', 0, -1092812 / 1000 , -1092812 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-04-01', 0, -600712 / 1000 , -600712 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-05-01', 0, -886494 / 1000 , -886494 / 1000 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-06-01', 0, -950 , -950 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-07-01', 0, -958.5 , -958.5 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-08-01', 0, -987.2 , -987.2 , '', '', '', 'руб.', '' + + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-09-01', 0, -1034 , -1034 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-10-01', 0, -1119 , -1119 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-11-01', 0, -1291 , -1291 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2020-12-01', 0, -1112 , -1112 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-01-01', 0, -1019 , -1019 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-02-01', 0, -1188 , -1188 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-03-01', 0, -1446 , -1446 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-04-01', 0, -1330 , -1330 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-05-01', 0, -927 , -927 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-06-01', 0, -1140 , -1140 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-07-01', 0, -881 , -881 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-08-01', 0, -1238 , -1238 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-09-01', 0, -1403 , -1403 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-10-01', 0, -1495 , -1495 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-11-01', 0, -1043 , -1043 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2021-12-01', 0, -1197 , -1197 , '', '', '', 'руб.', '' + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-01-01', 0, -1405 , -1405 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-02-01', 0, -1418 , -1418 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-03-01', 0, -1254 , -1254 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-04-01', 0, -1461 , -1461 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-05-01', 0, -1275 , -1275 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-06-01', 0, -1502 , -1502 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-07-01', 0, -1524 , -1524 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-08-01', 0, -1384 , -1384 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-09-01', 0, -1623 , -1623 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-10-01', 0, -1699 , -1699 , '', '', '', 'руб.', '' union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-11-01', 0, -1963 , -1963 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2022-12-01', 0, -1743 , -1743 , '', '', '', 'руб.', ''union all + + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-01-01', 0, -1560 , -1560 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-02-01', 0, -1727 , -1727 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-03-01', 0, -2104 , -2104 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-04-01', 0, -1504 , -1504 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-05-01', 0, -1674 , -1674 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-06-01', 0, -1503 , -1503 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-07-01', 0, -1582 , -1582 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-08-01', 0, -1569 , -1569 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-09-01', 0, -2104 , -2104 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-10-01', 0, -2104 , -2104 , '', '', '', 'руб.', '' union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-11-01', 0, -2104 , -2104 , '', '', '', 'руб.', '' union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2023-12-01', 0, -2104 , -2104 , '', '', '', 'руб.', '' + + union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-01-01', 0, -1611 , -1611 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-02-01', 0, -1759 , -1759 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-03-01', 0, -1853 , -1853 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-04-01', 0, -1718 , -1718 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-05-01', 0, -1516 , -1516 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-06-01', 0, -1682 , -1682 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-07-01', 0, -1669 , -1669 , '', '', '', 'руб.', ''union all + + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-08-01', 0, -1669 , -1669 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-09-01', 0, -1709 , -1709 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-10-01', 0, -1899 , -1899 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-11-01', 0, -2228 , -2228 , '', '', '', 'руб.', ''union all + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2024-12-01', 0, -2320 , -2320 , '', '', '', 'руб.', '' + + union all --2025 + select '', 'Зарплата|Топы' , 'Зарплата', 'Топы', '', '', '', 'ТОП_Оплата труда', 'Выдача ДС подотчетнику', '2025-01-01', 0, -1604 , -1604 , '', '', '', 'руб.', ''--union all + */ +) as t +WHERE g <> 'Прочие перемещения ДС' AND [Статья ДДС] <> 'Закупка_Приобретение валюты' +GO + +/****** Object: View [analytics].[nomenclature] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW analytics.nomenclature as +SELECT + LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), n._IDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), n._IDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), n._IDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), n._IDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), n._IDRRef, 2),5,12) ))as artic_id + , n._IDRRef as '1c_id' + , n._Code as code + , CASE + WHEN n._Fld21101RRef=0x80C5305A3A00E12B11E5845202CA01FB THEN 'Рублевая' + WHEN n._Fld21101RRef=0x80C5305A3A00E12B11E584520AEC30EC THEN 'Валютная' + ELSE 'Неопределено' + END as cenovaya_gruppa + + , n._Description as description /*Наименование*/ + , n._Fld21043 as artic /*Артикул*/ + , n._Fld21053RRef as vid_nomen + , cast( (SELECT _Description FROM [MAG_2019].[dbo].[_Reference260] pr WHERE pr._IDRRef = n._Fld21079RRef) as nvarchar(max)) as 'Производитель' + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), n._ParentIDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), n._ParentIDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), n._ParentIDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), n._ParentIDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), n._ParentIDRRef, 2),5,12) ))as group_id + + , n._ParentIDRRef as '1c_group' + --, isnull(us._Description, 'Менеджер') as [manager] + + , qr._Fld27045 as 'card' + , concat('https://media.magok.ru/', f._Fld21201) as 'photo' + , 2019 as base + , n._Fld21046 as [Знаменатель веса] + , n._Fld21049 as [Числитель веса] + + , n._Fld21089 as [Знаменатель объема] + , n._Fld21092 as [Числитель объема] + , n._Fld33413 as [id magok] + + + , (SELECT TOP 1 upakovka FROM pbi.[БазоваяУпаковка] up WHERE n._IDRRef = up._OwnerID_RRRef) as 'Базовая упаковка' + , (select r._Description from [MAG_2019].[dbo].[_Reference69] /*виды ном*/ r WHERE r._IDRRef = n._Fld21053RRef) as [Вид номенклатуры] + + from + [mag_2019].[dbo]._Reference188X1 n /*номенклатура*/ + LEFT JOIN [mag_2019].[dbo].[_InfoRg27043X1] /* Регистр сведений QR коды */ qr ON qr._Fld27044RRef = n._IDRRef + LEFT JOIN [mag_2019].[dbo]._Reference191X1 f /*номенклатураПрисоедФайлы*/ + ON f._IDRRef = n._Fld21086RRef + WHERE n._Folder = 1 +GO + +/****** Object: View [analytics].[v_contractors] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +-- ----------------------------------------------------------------------------- +-- 1. Представления для списков из 1С +-- ----------------------------------------------------------------------------- + +-- Контрагенты: [pbi].[ПартнерыКонтрагенты] уже существует (из _Reference168) +-- Для удобства создаём представление analytics.v_contractors с search-friendly полями + +CREATE VIEW [analytics].[v_contractors] AS + +SELECT + c._IDRRef AS contractor_1c_id, -- бинарный ключ 1С + LOWER(CONCAT( + SUBSTRING(CONVERT(nvarchar(36), c._IDRRef, 2), 25, 8), '-', + SUBSTRING(CONVERT(nvarchar(36), c._IDRRef, 2), 21, 4), '-', + SUBSTRING(CONVERT(nvarchar(36), c._IDRRef, 2), 17, 4), '-', + SUBSTRING(CONVERT(nvarchar(36), c._IDRRef, 2), 1, 4), '-', + SUBSTRING(CONVERT(nvarchar(36), c._IDRRef, 2), 5, 12) + )) AS contractor_id, -- строковый id для API/поиска + c._Description AS contractor_name +FROM [MAG_2019].[dbo].[_Reference168] c +WHERE c._Marked = 0; +GO + +/****** Object: View [analytics].[v_manufacturer_counterparty_mapping] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +-- Представление для API: map + manufacturer + contractor/producer (из 1С) +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 + +/****** Object: View [analytics].[v_manufacturers_roi_compat] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +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 + +/****** Object: View [analytics].[v_producers] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +-- Производители из справочника 1С _Reference260 +CREATE VIEW [analytics].[v_producers] AS +SELECT + pr._IDRRef AS producer_1c_id, -- бинарный ключ 1С + LOWER(CONCAT( + SUBSTRING(CONVERT(nvarchar(36), pr._IDRRef, 2), 25, 8), '-', + SUBSTRING(CONVERT(nvarchar(36), pr._IDRRef, 2), 21, 4), '-', + SUBSTRING(CONVERT(nvarchar(36), pr._IDRRef, 2), 17, 4), '-', + SUBSTRING(CONVERT(nvarchar(36), pr._IDRRef, 2), 1, 4), '-', + SUBSTRING(CONVERT(nvarchar(36), pr._IDRRef, 2), 5, 12) + )) AS producer_id, -- строковый id для API/поиска + pr._Description AS producer_name +FROM [MAG_2019].[dbo].[_Reference260] pr +WHERE pr._Marked = 0; +GO + +/****** Object: View [analytics].[Бюджет ДДС] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[Бюджет ДДС] as + +SELECT + DATEADD(year, -2000,[_Period]) as 'Месяц план' + , [_Fld28390RRef] as '1c_project_id' + --, CONVERT(VARCHAR(64), [_Fld28390RRef], 1) + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), [_Fld28390RRef], 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28390RRef], 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28390RRef], 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28390RRef], 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28390RRef], 2),5,12) )) as 'project id' + ,[_Fld28391] as 'Сумма' + , dds._Description as 'Статья ДДС' + , dds._IDRRef as '1c_dds_id' + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),5,12) )) as 'dds id' + , CASE budget._Fld33808Rref + WHEN 0xB3F668344C8DBA57427B6BC0D450CEA1 THEN 'Наличные' + WHEN 0xB5530D030E40BC264A41E266D1E84B1A THEN 'Безнал' + END as [Форма оплаты] +FROM [MAG_2019].[dbo].[_InfoRg28389] budget /* РегистрСведений.БюджетДДС */ + LEFT JOIN [MAG_2019].[dbo].[_Reference316] dds /*Справочник.СтатьиДвиженияДенежныхСредств*/ ON dds._IDRRef = budget.[_Fld33803RRef] + +--WHERE _Active = 1 +GO + +/****** Object: View [analytics].[Внешние остатки] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[Внешние остатки] as +SELECT nod._Description AS [Узел] + , ost._Fld33601 AS [Тип] + , ost._Fld33595 AS [Склад] + , DATEADD(YEAR, -2000, ost._Fld33596) AS [Дата обновления] + , [_Fld28683RRef] as [1c_id] + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), [_Fld28683RRef], 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28683RRef], 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28683RRef], 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), [_Fld28683RRef], 2),1,4),'-',SUBSTRING ( convert(nvarchar(36),[_Fld28683RRef], 2),5,12) )) + as [artic_id] + , n.code AS [code] + , n.[1c_group] as [group_id] + , ost._Fld33599 AS [id_внешний] + , ost._Fld33602 AS [Количество] + , ost._Fld33603 AS [Доступное кол-во] + +FROM [MAG_2019].[dbo].[_InfoRg28682X1] AS ost /* РегистрСведений.ОстаткиТоваровВоВнешнихСистемах */ + LEFT JOIN [mag_pbi].[pbi].[nomenclature] n ON n.[1c_id] = ost._Fld28683RRef /* Справочник.Номенклатура */ + LEFT JOIN [MAG_2019].[dbo].[_Node28072X1] nod ON nod._IDRRef = ost._Fld28684RRef /* ПланОбмена.ВнешниеСистемы */ +GO + +/****** Object: View [analytics].[Где товар] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[Где товар] as + SELECT + [1c_id] + , [artic_id] + , [Где товар] + , quantity + FROM [analytics].[Товары на складах] +UNION ALL + SELECT + [1c_id] + , [artic_id] + , [Где товар] + , quantity + FROM [analytics].[Остатки МП] +UNION ALL + SELECT + [1c_id] + , [artic_id] + , [Где товар] + , Резерв as quantity + FROM [ostatki].[РезервыМПиОПТ] + +UNION ALL + + SELECT + [1c_id] + , [artic_id] + , [Где товар] + , Количество as quantity + FROM [pbi].[Заказо_в_пути]-- where [Номер заказа поставщику] = 'АНУТ-003313' + +UNION ALL + + SELECT + [1c_id] + , [artic_id] + , [Где товар] + , Количество as quantity + FROM [pbi].[Заказо_в_производстве] +GO + +/****** Object: View [analytics].[Где товар с упаковками] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE view analytics.[Где товар с упаковками] as +SELECT [1c_id] + ,t.[artic_id] + ,[Где товар] + ,[quantity] as Штук + , case WHEN upak.upakovka <>0 then t.quantity / upak.upakovka + else 0 END as Упаковок + , upak.вес + , Высота + , Глубина + , Ширина + , Объем + FROM [mag_pbi].[analytics].[Где товар] t + INNER JOIN [mag_pbi].[pbi].[БазоваяУпаковка] upak + ON t.[1c_id] = upak.[_IDRRef] +GO + +/****** Object: View [analytics].[Группы_статей_ДДС] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE view [analytics].[Группы_статей_ДДС] as + WITH DirectReports([Статья ддс], g, g1,g2,g3,g4,[1c_id],[id], [_ParentIDRRef], lvl, [path]/*Name, Title, EmployeeID, EmployeeLevel, Sort*/) + AS (SELECT + CONVERT(varchar(255), e.[_Description]), + CONVERT(varchar(255),e.[_Description]), --g + CONVERT(varchar(255),''), --g1 + CONVERT(varchar(255),''), --g2 + CONVERT(varchar(255),''), --g3 + CONVERT(varchar(255),''), --g4 + + e._IDRRef, + LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), _IDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),5,12) )), + e._ParentIDRRef, + 1, + CONVERT(varchar(255), e.[_Description]) + FROM [mag_2019].[dbo].[_Reference316] AS e + WHERE e._ParentIDRRef = 0x00000000000000000000000000000000 AND e._Marked = 0 + UNION ALL + SELECT CONVERT(varchar(255), /*REPLICATE ('| ' , lvl) +*/ e._Description), + CONVERT(varchar(255),d.g), +/*g1*/ CASE lvl + 1 WHEN 2 THEN CONVERT(varchar(255),e._Description) ELSE CONVERT(varchar(255),d.g1) END, +/*g2*/ CASE lvl + 1 WHEN 3 THEN CONVERT(varchar(255),e._Description) ELSE CONVERT(varchar(255),d.g2) END, +/*g3*/ CASE lvl + 1 WHEN 4 THEN CONVERT(varchar(255),e._Description) ELSE CONVERT(varchar(255),d.g3) END, +/*g4*/ CASE lvl + 1 WHEN 5 THEN CONVERT(varchar(255),e._Description) ELSE CONVERT(varchar(255),d.g4) END, + + e._IDRRef, + LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), _IDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), _IDRRef, 2),5,12) )), + e._ParentIDRRef, + lvl + 1, + CONVERT (varchar(255), RTRIM(path) + ' | ' + e._Description) + FROM [mag_2019].[dbo].[_Reference316] AS e + INNER JOIN DirectReports AS d ON e._ParentIDRRef = d.[1c_id] + WHERE e._Marked = 0 + ) + SELECT * + FROM DirectReports + --ORDER BY Sort +GO + +/****** Object: View [analytics].[Заказы] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[Заказы] +AS +SELECT + DATEADD(YEAR, -2000, z._Date_Time) AS [Дата заказа поставщику], + z._Number AS [Номер заказа поставщику], + t._Fld3473RRef AS [1C_id], + + LOWER( + SUBSTRING(CONVERT(nvarchar(36), p._IDRRef, 2), 25, 8) + '-' + + SUBSTRING(CONVERT(nvarchar(36), p._IDRRef, 2), 21, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), p._IDRRef, 2), 17, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), p._IDRRef, 2), 1, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), p._IDRRef, 2), 5, 12) + ) AS partner_id, + + r._Description AS Контрагент, + + CASE z._Fld3417RRef + WHEN 0xB9440E49408A17534955319EBF0DAE60 THEN 'Согласован' + WHEN 0x99FD3E66AA3EFB074984044D5A69CFD5 THEN 'В пути' + WHEN 0x973A5675AC6A17F64DA37EC6C22FC12C THEN 'Подтвержден' + WHEN 0xA55F81415BA33BC24A053ED26C6EC02E THEN 'Закрыт' + WHEN 0xA87A8B13710A30B447DFF1614E84D167 THEN 'В производстве' + WHEN 0x8542BD023FE7B70E4613087D853F26E4 THEN 'Тех. заказ' + WHEN 0xB38AD6232E2D17D44287D9924E5E6DF2 THEN 'На согласовании' + WHEN 0xB2A33CF1C7286AF3463F20D54AE5A0BC THEN 'Выгружен на складе' + ELSE 'Неизвестно' + END AS Статус, + + t._Fld3473RRef AS nom_1c_id, + n._Description AS Наименование, + n._Code AS code, + n._Fld21043 AS Артикул, + + LOWER( + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 25, 8) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 21, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 17, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 1, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 5, 12) + ) AS artic_id, + + t._Fld3477 AS Количество, + CONVERT(decimal(10, 2), t._Fld3477 / pack.base_pack) AS [Кол. упаковок], + + t._Fld3480 AS Цена, + t._Fld3481 AS Сумма, + + g.g, + g.path, + + v._Description AS Валюта, + CASE v._Description + WHEN 'USD' THEN _Fld3481 * (SELECT rate FROM [mag_pbi].[analytics].[Курсы валют на сегодня] WHERE currency='USD2') + ELSE _Fld3481 * (SELECT rate FROM [mag_pbi].[analytics].[Курсы валют на сегодня] WHERE currency=v._Description) + END AS 'Сумма в руб.', + + CASE + WHEN z._Fld3420 < '4000' THEN DATEADD(MONTH, 4, GETDATE()) + ELSE DATEADD(YEAR, -2000, z._Fld3420) + END + as 'Желаемая дата', + z._Fld3432 as 'Комментарий' + +FROM MAG_2019.dbo._Document408X1 AS z -- Документ заказ поставщику +INNER JOIN MAG_2019.dbo._Document408_VT3470X1 AS t ON t._Document408_IDRRef = z._IDRRef -- табличная часть +LEFT JOIN MAG_2019.dbo._Reference215X1 AS p ON p._IDRRef = z._Fld3409RRef -- Справочник.Партнеры +LEFT JOIN MAG_2019.dbo._Reference168 AS r ON r._IDRRef = z._Fld3410RRef -- Справочник.Контрагенты +INNER JOIN MAG_2019.dbo._Reference188X1 AS n ON n._IDRRef = t._Fld3473RRef -- Номенклатура +LEFT JOIN MAG_2019.dbo._Reference50 AS v ON v._IDRRef = z._Fld3414RRef -- Справочник.Валюты +INNER JOIN pbi.groups AS g ON n._ParentIDRRef = g.[1c_id] -- группы + +OUTER APPLY ( + SELECT TOP 1 + ISNULL(NULLIF(up.upakovka, 0), 1) AS base_pack + FROM pbi.БазоваяУпаковка up + WHERE up._OwnerID_RRRef = t._Fld3473RRef +) AS pack + +WHERE + z._Posted = 1 + AND z._Marked = 0 + AND t._Fld3491RRef = 0 + --AND g NOT LIKE '*Внутр%' + --AND z._Fld3417RRef <> 0xA55F81415BA33BC24A053ED26C6EC02E /* Не закрыт */ + --AND z._Fld3417RRef <> 0x8542BD023FE7B70E4613087D853F26E4 /* Не Тех. заказ */ + --AND z._Fld3417RRef <> 0x973A5675AC6A17F64DA37EC6C22FC12C /* Не Подтвержден */ +GO + +/****** Object: View [analytics].[ЗаказыВЗаявках] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[ЗаказыВЗаявках] +AS +SELECT + CONVERT(date, DATEADD(YEAR, -2000, z._Date_Time)) AS [Дата заказа поставщику], + z._Number AS [Номер заказа поставщику], + + /* заявка из ТЧ */ + CASE WHEN za._IDRRef IS NOT NULL THEN t._Fld34117RRef END AS [Заявка_1c_id], + ISNULL(za._Number, N'Без заявки') AS [Номер заявки], + CASE + WHEN za._IDRRef IS NOT NULL THEN CONVERT(date, DATEADD(YEAR, -2000, za._Date_Time)) + END AS [Дата заявки], + + /* Контрагент (текст) */ + r._Description AS [Контрагент], + + /* cagent_id (строка GUID) из 1С-ссылки контрагента */ + LOWER( + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 25, 8) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 21, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 17, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 1, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 5, 12) + ) AS cagent_id, + + pc.partner_1cid, + pc.partner_id, + + CASE z._Fld3417RRef + WHEN 0xB9440E49408A17534955319EBF0DAE60 THEN N'Согласован' + WHEN 0x99FD3E66AA3EFB074984044D5A69CFD5 THEN N'В пути' + WHEN 0x973A5675AC6A17F64DA37EC6C22FC12C THEN N'Подтвержден' + WHEN 0xA55F81415BA33BC24A053ED26C6EC02E THEN N'Закрыт' + WHEN 0xA87A8B13710A30B447DFF1614E84D167 THEN N'В производстве' + WHEN 0x8542BD023FE7B70E4613087D853F26E4 THEN N'Тех. заказ' + WHEN 0xB38AD6232E2D17D44287D9924E5E6DF2 THEN N'На согласовании' + WHEN 0xB2A33CF1C7286AF3463F20D54AE5A0BC THEN N'Выгружен на складе' + ELSE N'Неизвестно' + END AS [Статус], + + /* номенклатура */ + t._Fld3473RRef AS nom_1c_id, + + /* nom_1c_id в нужном формате */ + LOWER( + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 25, 8) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 21, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 17, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 1, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), t._Fld3473RRef, 2), 5, 12) + ) AS artic_id, + + n._Description AS [Наименование], + n._Code AS code, + n._Fld21043 AS [Артикул], + + t._Fld3477 AS [Количество], + CONVERT(decimal(10, 2), t._Fld3477 / pack.base_pack) AS [Кол. упаковок], + + t._Fld3480 AS [Цена], + t._Fld3481 AS [Сумма], + + g.g, + g.path, + + /* Валюта + Сумма в руб. */ + v._Description AS [Валюта], + z._Fld3414RRef AS currency_id, + CASE v._Description + WHEN 'USD' THEN t._Fld3481 * ( + SELECT rate + FROM [analytics].[Курсы валют на сегодня] + WHERE currency = 'USD2' + ) + ELSE t._Fld3481 * ( + SELECT rate + FROM [analytics].[Курсы валют на сегодня] + WHERE currency = v._Description + ) + END AS [Сумма в руб.] + +FROM [MAG_2019].dbo._Document408X1 z +JOIN [MAG_2019].dbo._Document408_VT3470X1 t + ON t._Document408_IDRRef = z._IDRRef + +LEFT JOIN [MAG_2019].dbo._Document34036 za + ON za._IDRRef = t._Fld34117RRef + +LEFT JOIN [MAG_2019].dbo._Reference168 r + ON r._IDRRef = z._Fld3410RRef + +LEFT JOIN [pbi].[ПартнерыКонтрагенты] pc + ON pc.cagent_id = LOWER( + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 25, 8) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 21, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 17, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 1, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r._IDRRef, 2), 5, 12) + ) + +JOIN [MAG_2019].dbo._Reference188X1 n + ON n._IDRRef = t._Fld3473RRef + +LEFT JOIN [MAG_2019].dbo._Reference50 v + ON v._IDRRef = z._Fld3414RRef + +LEFT JOIN [pbi].[groups] g + ON n._ParentIDRRef = g.[1c_id] + +OUTER APPLY ( + SELECT TOP 1 + ISNULL(NULLIF(up.upakovka, 0), 1) AS base_pack + FROM [pbi].[БазоваяУпаковка] up + WHERE up._OwnerID_RRRef = t._Fld3473RRef +) AS pack + +WHERE + z._Posted = 1 + AND z._Marked = 0 + AND t._Fld3491RRef = 0; +GO + +/****** Object: View [analytics].[Заявки_без_проекта_неоплачено] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[Заявки_без_проекта_неоплачено] as +SELECT [Номер заявки] + ,[Дата создания] + ,[Дата оплаты план] + ,[Статус] + ,[Валюта] + ,[Статья ДДС] + ,[1c_dds_id] + ,[dds id] + ,[Сумма] + ,[Сумма в руб.] + ,[Оплачено] + ,[Хоз. операция] + ,[Комментарий заявки] + ,[Комментарий расшифровки] + ,[Партнер] + ,[Получатель] + ,[Форма оплаты] + ,[organization] + ,[project id] + ,[1c_project_id] + FROM [mag_pbi].[analytics].[Заявки_на_оплату_по_табличной_части] + WHERE [Оплачено]=0 AND [project id] is null AND [Дата оплаты план] >= '2024-06-01' +GO + +/****** Object: View [analytics].[Заявки_на_оплату] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[Заявки_на_оплату] +AS SELECT + [_Number] as 'Номер заявки' + , _Document416_IDRRef + ,DATEADD(year, -2000, [_Fld3902]) as 'Дата оплаты план' + , CASE + WHEN [_Fld3880RRef]= 0x96388D3803D0E2B243682753FD602008 THEN 'Согласована' + WHEN [_Fld3880RRef] = 0xA53B783FB8E84C2D4A977FB197BB9B6A THEN 'Не согласована' + WHEN [_Fld3880RRef] = 0xB22A4A3C82F7B70D452E0F89A2703597 THEN 'К оплате' + WHEN [_Fld3880RRef] = 0x9EB3FD405C68C64C42B491437EDE1CAB THEN 'Отклонена' + END as 'Статус' + , [_Fld3882] as 'Сумма' + , case spv._Description + WHEN 'USD' THEN [_Fld3882] * (SELECT rate FROM [mag_pbi].[analytics].[Курсы валют на сегодня] WHERE currency='USD2') + ELSE [_Fld3882] * (SELECT rate FROM [mag_pbi].[analytics].[Курсы валют на сегодня] WHERE currency=spv._Description) + END + as 'Сумма в руб.' + , CASE WHEN (SELECT + SUM(CASE WHEN [_RecordKind] = 0 THEN [_Fld16211] ELSE -[_Fld16211] END) AS summ + FROM [MAG_2019].[dbo].[_AccumRg16206] -- РегистрНакопления.ДенежныеСредстваКВыплате + WHERE [_Fld16207_RRRef] = _Document416_IDRRef + ) = 0 THEN 1 ELSE 0 END as 'Оплачено' + , spv._Description as 'Валюта документа' + ,DATEADD(year, -2000, [_Date_Time]) as [Дата создания] + --,DATEADD(year, -2000, [_Fld3890]) as 'Дата оплаты желат' + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), dr._Fld3957RRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), dr._Fld3957RRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), dr._Fld3957RRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), dr._Fld3957RRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), dr._Fld3957RRef, 2),5,12) ))as partner_id + , (SELECT _description FROM [mag_2019].[dbo]._Reference215X1 prt /*партнеры*/ WHERE prt._IDRRef = dr._Fld3957RRef) as 'Партнер' + , (SELECT _Description FROM [mag_2019].[dbo]._Reference168 kt /*контрагенты*/ WHERE kt._IDRRef = r._Fld3891RRef)as 'Получатель' + ,[_Fld3900] as 'Комментарий' + , (SELECT _Description FROM [MAG_2019].[dbo].[_Reference316] dds /*Справочник.СтатьиДвиженияДенежныхСредств*/ WHERE dds._IDRRef = r._Fld3904RRef) as 'Статья ДДС' + , e.value as 'Хоз. операция' + FROM [MAG_2019].[dbo].[_Document416] r /*ЗаявкаНаРасходованиеДенежныхСредств */ + LEFT JOIN [MAG_2019].[dbo].[_Document416_VT3955] dr /*Документ.ЗаявкаНаРасходованиеДенежныхСредств.ТабличнаяЧасть.РасшифровкаПлатежа*/ ON r._IDRRef = dr._Document416_IDRRef + LEFT JOIN mag_pbi.pbi.enums e ON e._IDRref = r.[_Fld3881RRef] AND e.enum = 'Хоз. операции'/*Перечисление хозяйственная операция*/ + LEFT JOIN [MAG_2019].[dbo].[_Reference50] spv ON spv._IDRRef = r.[_Fld3883RRef] /*Справочник.Валюты */ + + + --LEFT JOIN [MAG_2019].[dbo].[_AccumRg16206] + WHERE /*[_Fld3881RRef]=0xB96DB293C2F88D8C46DF79811923F574 AND */ r.[_Posted] = 0x01 AND r._Marked = 0x00 +GO + +/****** Object: View [analytics].[Заявки_на_оплату_по_табличной_части] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE view [analytics].[Заявки_на_оплату_по_табличной_части] as +SELECT + z._Number as 'Номер заявки' + --, z._Posted, z_t._Fld3964RRef, z._IDRRef + , DATEADD(year, -2000, z.[_Date_Time]) as [Дата создания] + --, DATEADD(year, -2000,z.[_Fld3902]) as 'Дата оплаты план' + --, CONVERT(datetime2, FORMAT(DATEADD(year, -2000, [_Fld3902]),'yyyy-MM-dd'), 120) as 'Дата оплаты план' + ,DATEADD(year, -2000, [_Fld3902]) as 'Дата оплаты план' + , CASE + WHEN z.[_Fld3880RRef]= 0x96388D3803D0E2B243682753FD602008 THEN 'Согласована' + WHEN z.[_Fld3880RRef] = 0xA53B783FB8E84C2D4A977FB197BB9B6A THEN 'Не согласована' + WHEN z.[_Fld3880RRef] = 0xB22A4A3C82F7B70D452E0F89A2703597 THEN 'К оплате' + WHEN z.[_Fld3880RRef] = 0x9EB3FD405C68C64C42B491437EDE1CAB THEN 'Отклонена' + END as 'Статус' + , spv._Description as 'Валюта' + , dds._Description as 'Статья ДДС' + , dds._IDRRef as '1c_dds_id' + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), dds._IDRRef, 2),5,12) ))as 'dds id' + , z_t._Fld3959 as 'Сумма' + , case spv._Description + WHEN 'USD' THEN _Fld3959 * (SELECT rate FROM [mag_pbi].[analytics].[Курсы валют на сегодня] WHERE currency='USD2') + ELSE _Fld3959 * (SELECT rate FROM [mag_pbi].[analytics].[Курсы валют на сегодня] WHERE currency=spv._Description) + END + as 'Сумма в руб.' + , CASE WHEN (SELECT + SUM(CASE WHEN [_RecordKind] = 0 THEN [_Fld16211] ELSE -[_Fld16211] END) AS summ + FROM [MAG_2019].[dbo].[_AccumRg16206] -- РегистрНакопления.ДенежныеСредстваКВыплате + WHERE [_Fld16207_RRRef] = _Document416_IDRRef + ) = 0 THEN 1 ELSE 0 END as 'Оплачено' + , e.value as 'Хоз. операция' + , z.[_Fld3900] as 'Комментарий заявки' + , z_t.[_Fld3968] as 'Комментарий расшифровки' + , (SELECT _description FROM [mag_2019].[dbo]._Reference215X1 prt /*партнеры*/ WHERE prt._IDRRef = z_t._Fld3957RRef) as 'Партнер' + , (SELECT _Description FROM [mag_2019].[dbo]._Reference168 kt /*контрагенты*/ WHERE kt._IDRRef = z._Fld3891RRef)as 'Получатель' + , case when org._Description = 'АНТУРАЖ ЛТД ООО' then 'Безнал' ELSE 'Наличные' END as 'Форма оплаты' + , org._Description as 'organization' + , p.id as 'project id' + , p.[1c_id] as '1c_project_id' +FROM [MAG_2019].[dbo].[_Document416_VT3955] z_t /*Документ.ЗаявкаНаРасходованиеДенежныхСредств.ТабличнаяЧасть.РасшифровкаПлатежа*/ + INNER JOIN [MAG_2019].[dbo].[_Document416] z /* Документ.ЗаявкаНаРасходованиеДенежныхСредств */ + ON z._IDRRef = z_t._Document416_IDRRef + LEFT JOIN mag_pbi.pbi.enums e ON e._IDRref = z.[_Fld3881RRef] AND e.enum = 'Хоз. операции'/*Перечисление хозяйственная операция*/ + LEFT JOIN [MAG_2019].[dbo].[_Reference50] spv ON spv._IDRRef = z.[_Fld3883RRef] /*Справочник.Валюты */ + LEFT JOIN [MAG_2019].[dbo].[_Reference316] dds /*Справочник.СтатьиДвиженияДенежныхСредств*/ ON dds._IDRRef = z_t._Fld3964RRef + LEFT JOIN [MAG_2019].[dbo].[_Reference198X1] org ON org._IDRRef = z._Fld3879RRef/*справочник организации*/ + LEFT JOIN [mag_pbi].[analytics].[Проекты] p + ON p.[1c_id] = [_Fld28407RRef] +WHERE z._Posted = 1 AND z._Marked = 0x00 + AND z.[_Fld3880RRef] <> 0x9EB3FD405C68C64C42B491437EDE1CAB +GO + +/****** Object: View [analytics].[ЗаявкиТовары] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[ЗаявкиТовары] AS + +WITH req AS ( + SELECT + z._IDRRef AS zayavka_id, + CONVERT(date, DATEADD(YEAR, -2000, z._Date_Time)) AS zayavka_date, + z._Number AS zayavka_number, + z._Fld34044RRef AS zayavka_status_ref, + z._Fld34039RRef AS partner_1c_id, + z._Fld34040RRef AS contractor_1c_id, + CONVERT(decimal(18, 2), z._Fld34051) AS summa_doc, + z._Fld34045RRef AS valuta_ref, + CASE + WHEN z._Fld34118 = '00010101' THEN NULL + ELSE CONVERT(date, DATEADD(YEAR, -2000, z._Fld34118)) + END AS data_postupleniya, + t._LineNo34053 AS line_no, + t._Fld34054RRef AS nom_1c_id, + CONVERT(decimal(18, 3), t._Fld34056) AS qty_initial, + CONVERT(decimal(18, 2), t._Fld34059) AS summa_line + FROM MAG_2019.dbo._Document34036 z + JOIN MAG_2019.dbo._Document34036_VT34052 t ON t._Document34036_IDRRef = z._IDRRef + WHERE z._Posted = 1 AND z._Marked = 0 +), +deduct AS ( + SELECT + tpo._Fld34117RRef AS zayavka_id, + tpo._Fld3473RRef AS nom_1c_id, + SUM(CONVERT(decimal(18, 3), tpo._Fld3477)) AS qty_deduct + FROM MAG_2019.dbo._Document408X1 po + JOIN MAG_2019.dbo._Document408_VT3470X1 tpo ON tpo._Document408_IDRRef = po._IDRRef + WHERE + po._Posted = 1 + AND po._Marked = 0 + AND tpo._Fld3491RRef = 0 + AND po._Fld3417RRef IN ( + 0x99FD3E66AA3EFB074984044D5A69CFD5, /* В пути */ + 0xA55F81415BA33BC24A053ED26C6EC02E, /* Закрыт */ + 0xB2A33CF1C7286AF3463F20D54AE5A0BC, /* Выгружен на складе */ + 0x97B9E76E7BCACEF3450504B1FAFC3230 /* Принят */ + ) + GROUP BY tpo._Fld34117RRef, tpo._Fld3473RRef +) + +SELECT + r.zayavka_date AS [Дата заявки], + r.zayavka_number AS [Номер заявки], + CASE r.zayavka_status_ref + WHEN 0xB9D8F6098E165A4945FD453A8394D9A6 THEN N'Планируется' + WHEN 0x89144CF303169EA446E30A9CFAC257D1 THEN N'На согласовании' + WHEN 0x8734648F71AB3BE645DCAC11CF62F9AE THEN N'Выполнено' + WHEN 0xA6CC3F7ADAD37C7D473BFD1D132A96E8 THEN N'В производстве' + ELSE N'Неизвестно' + END AS [Статус заявки], + prt._Description AS [Партнер], + ctg._Description AS [Контрагент], + val._Description AS [Валюта], + + /* ── Сумма документа ── */ + r.summa_doc AS [Сумма документа], + CASE val._Description + WHEN 'USD' THEN r.summa_doc * + (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency = 'USD2') + ELSE r.summa_doc * + (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency = val._Description) + END AS [Сумма документа в руб], + + r.data_postupleniya AS [Дата поступления], + ISNULL(man.manufacturer, N'Не найдено') AS manufacturer, + ISNULL(man.ROI_norm, 136) / 100.0 AS roi_year_normalized, + man.n_percent, + man.n_days, + man.m_percent, + man.m_days, + r.line_no AS line_no, + r.nom_1c_id AS nom_1c_id, + LOWER( + SUBSTRING(CONVERT(nvarchar(36), r.nom_1c_id, 2), 25, 8) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r.nom_1c_id, 2), 21, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r.nom_1c_id, 2), 17, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r.nom_1c_id, 2), 1, 4) + '-' + + SUBSTRING(CONVERT(nvarchar(36), r.nom_1c_id, 2), 5, 12) + ) AS artic_id, + n._Description AS [Номенклатура], + n._Code AS code, + n._Fld21043 AS [Артикул], + g.g, + g.path, + + /* ── Количество начальное ── */ + r.qty_initial AS [Количество начальное], + CONVERT(decimal(18, 3), r.qty_initial / pack.base_pack) + AS [Кол. упаковок начальное], + + /* ── Количество заказано (вычет) ── */ + ISNULL(d.qty_deduct, 0) AS [Количество заказано (вычет)], + CONVERT(decimal(18, 3), ISNULL(d.qty_deduct, 0) / pack.base_pack) + AS [Кол. упаковок заказано (вычет)], + + /* ── Количество текущее ── */ + CONVERT(decimal(18, 3), r.qty_initial - ISNULL(d.qty_deduct, 0)) + AS [Количество текущее], + CONVERT(decimal(18, 3), (r.qty_initial - ISNULL(d.qty_deduct, 0)) / pack.base_pack) + AS [Кол. упаковок текущее], + + /* ── Сумма строки начальная ── */ + r.summa_line AS [Сумма строки], + CASE val._Description + WHEN 'USD' THEN r.summa_line * + (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency = 'USD2') + ELSE r.summa_line * + (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency = val._Description) + END AS [Сумма строки в руб], + + /* ── Сумма строки текущая (пропорционально текущему количеству) ── */ + CASE + WHEN r.qty_initial = 0 THEN CONVERT(decimal(18, 2), 0) + ELSE CONVERT(decimal(18, 2), + r.summa_line / r.qty_initial * (r.qty_initial - ISNULL(d.qty_deduct, 0))) + END AS [Сумма строки текущая], + CASE val._Description + WHEN 'USD' THEN + CASE WHEN r.qty_initial = 0 THEN 0 + ELSE r.summa_line / r.qty_initial * (r.qty_initial - ISNULL(d.qty_deduct, 0)) END * + (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency = 'USD2') + ELSE + CASE WHEN r.qty_initial = 0 THEN 0 + ELSE r.summa_line / r.qty_initial * (r.qty_initial - ISNULL(d.qty_deduct, 0)) END * + (SELECT rate FROM [analytics].[Курсы валют на сегодня] WHERE currency = val._Description) + END AS [Сумма строки текущая в руб] + +FROM req r +JOIN MAG_2019.dbo._Reference188X1 n ON n._IDRRef = r.nom_1c_id +LEFT JOIN MAG_2019.dbo._Reference215X1 prt ON prt._IDRRef = r.partner_1c_id +LEFT JOIN MAG_2019.dbo._Reference168 ctg ON ctg._IDRRef = r.contractor_1c_id +LEFT JOIN MAG_2019.dbo._Reference50 val ON val._IDRRef = r.valuta_ref +LEFT JOIN analytics.manufacturer_counterparty_map map ON map.contractor_1c_id = r.contractor_1c_id +LEFT JOIN analytics.v_manufacturers_roi_compat man ON man.id = map.manufacturer_id +LEFT JOIN pbi.[groups] g ON n._ParentIDRRef = g.[1c_id] +OUTER APPLY ( + SELECT TOP 1 ISNULL(NULLIF(up.upakovka, 0), 1) AS base_pack + FROM pbi.[БазоваяУпаковка] up + WHERE up._OwnerID_RRRef = r.nom_1c_id +) AS pack +LEFT JOIN deduct d ON d.zayavka_id = r.zayavka_id AND d.nom_1c_id = r.nom_1c_id; +GO + +/****** Object: View [analytics].[Курсы валют на сегодня] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******//* +SELECT TOP (1000) [_Period] + ,[_Fld13219RRef] + ,[_Fld13220] + ,[_Fld13221] + --,[_Fld1150] + , r._Description + FROM [MAG_2019].[dbo].[_InfoRg13218] i + INNER JOIN [MAG_2019].[dbo].[_Reference50] r + ON i._Fld13219RRef = r._IDRRef + + */ +CREATE VIEW analytics.[Курсы валют на сегодня] as + + SELECT + r._Description as currency + ,( SELECT top 1 [_Fld13220] FROM [MAG_2019].[dbo].[_InfoRg13218] i WHERE i._Fld13219RRef = r._IDRRef ORDER BY [_Period] DESC) as rate + FROM + [MAG_2019].[dbo].[_Reference50] r +GO + +/****** Object: View [analytics].[Ожидаемое_поступление] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW [analytics].[Ожидаемое_поступление] as +SELECT + d._Number as [Номер] + , CONVERT(datetime2, FORMAT(DATEADD(year, -2000, [_Date_Time]),'yyyy-MM-dd'), 120) as [Дата поступления] + , CASE _Fld5074RRef + WHEN 0xB5530D030E40BC264A41E266D1E84B1A then 'Безнал' + WHEN 0xB3F668344C8DBA57427B6BC0D450CEA1 then 'Наличные' + ELSE 'Любая' + END as [Форма оплаты] + , d._Fld5070 / 1000 as 'Сумма' + , (SELECT _Description FROM [MAG_2019].[dbo].[_Reference316] dds /*Справочник.СтатьиДвиженияДенежныхСредств*/ WHERE dds._IDRRef = d._Fld5072RRef) as 'Статья ДДС' + , (SELECT _Description FROM [MAG_2019].[dbo].[_Reference198X1] org WHERE org._IDRRef = d._Fld5069RRef) as 'Организация' + , (SELECT _Description FROM [MAG_2019].[dbo].[_Reference50] spv /*Справочник.Валюты */ WHERE spv._IDRRef = d._Fld5071RRef) as 'Валюта документа' + , d._Fld5073 as 'Назначение платежа' +FROM MAG_2019.dbo._Document443 d /* Документ.ОжидаемоеПоступлениеДенежныхСредств */ +WHERE d._Marked = 0x00 AND d._Posted = 0x01 + +/* +0xB5530D030E40BC264A41E266D1E84B1A безнал +0xB3F668344C8DBA57427B6BC0D450CEA1 нал + +*/ +GO + +/****** Object: View [analytics].[Ожидаемый расход] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[Ожидаемый расход] as + +SELECT + [Дата оплаты план] + ,[Статья ДДС] + ,[Сумма в руб.] / 1000 [Сумма в руб.] + ,[Форма оплаты] + , 'Заявка' as [Тип] + , [Хоз. операция] + FROM [mag_pbi].[analytics].[Заявки_без_проекта_неоплачено] + + UNION ALL + + SELECT [Месяц план] + ,[Статья ДДС] + ,[Сумма] / 1000 [Сумма] + ,[Форма оплаты] + , 'Бюджет' as [Тип] + , 'Бюджет' as [Хоз. операция] + FROM [mag_pbi].[analytics].[Бюджет ДДС] +GO + +/****** Object: View [analytics].[Остатки МП] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE VIEW analytics.[Остатки МП] as + SELECT + t.[Где товар], + t.artic_id, + t.[1c_id], + sum(t.quantity) as quantity + FROM ( + select + case + WHEN CHARINDEX('Ozon', [Узел])>0 then 'Ozon' + WHEN CHARINDEX('WildBerries', [Узел])>0 then 'WildBerries' + END + as 'Где товар' + , + [1c_id], + [artic_id], + sum([Доступное кол-во]) as quantity + FROM [mag_pbi].[analytics].[Внешние остатки] as t + WHERE t.[Дата обновления] >= FORMAT(GETDATE(), 'yyyy-MM-dd') + group by Узел, [1c_id], [artic_id] + ) as t + GROUP BY t.[Где товар], + t.artic_id, + t.[1c_id] +GO + +/****** Object: View [analytics].[Продажи_Учёт_Маржа_по_дням] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE VIEW [analytics].[Продажи_Учёт_Маржа_по_дням] +AS +WITH base AS ( + -- Продажи и учетная сумма (только Статья = 'Реализация') + SELECT + CAST(s.[Период] AS date) AS [d], + s.[1c_id], + s.Code, + SUM(CAST(s.[Сумма] AS decimal(38,6))) AS sales_sum, + SUM(CAST(s.[Учетная сумма, руб] AS decimal(38,6))) AS accounting_sum, + CAST(0 AS decimal(38,6)) AS ads_cost, + CAST(0 AS decimal(38,6)) AS order_cost + FROM [mag_pbi].[pbiProd].[СводныйСебестоимость Для PBI] AS s + WHERE s.[Статья] = N'Реализация' + GROUP BY CAST(s.[Период] AS date), s.[1c_id], s.Code + + UNION ALL + + -- Реклама (затраты) + SELECT + CAST(r.[Дата] AS date) AS [d], + r.[1c_id], + n.code, + CAST(0 AS decimal(38,6)) AS sales_sum, + CAST(0 AS decimal(38,6)) AS accounting_sum, + SUM(CAST(r.[Затраты, руб] AS decimal(38,6))) AS ads_cost, + CAST(0 AS decimal(38,6)) AS order_cost + FROM [mag_pbi].[pbi].[РекламаМаркетплейсы] AS r + INNER JOIN mag_pbi.pbi.nomenclature n ON r.[1c_id] = n.[1c_id] + GROUP BY CAST(r.[Дата] AS date), r.[1c_id],n.code + + UNION ALL + + + -- Стоимость обработки заказа (затраты) + SELECT + CAST(o.[date] AS date) AS [d], + o.[1c_id], + n.code, + CAST(0 AS decimal(38,6)) AS sales_sum, + CAST(0 AS decimal(38,6)) AS accounting_sum, + CAST(0 AS decimal(38,6)) AS ads_cost, + SUM(CAST(o.[Сумма] AS decimal(38,6))) AS order_cost + FROM [mag_pbi].[pbi].[Стоимость обработки заказа] AS o + INNER JOIN pbi.nomenclature n ON o.[1c_id] = n.[1c_id] + GROUP BY CAST(o.[date] AS date), o.[1c_id], n.code +) +SELECT + b.[d], + b.[1c_id], + b.Code, + SUM(b.sales_sum) AS [Сумма продаж], + SUM(b.accounting_sum) AS [Учетная сумма], + SUM(b.ads_cost) AS [Затраты на рекламу], + SUM(b.order_cost) AS [Стоимость обработки], + -- «Чистая выручка» после вычета рекламных и обработочных затрат + (SUM(b.sales_sum) - SUM(b.ads_cost) - SUM(b.order_cost)) AS [Сумма продаж (нетто)], + -- Торговая надбавка = нетто-продажи минус учетная сумма + (SUM(b.sales_sum) - SUM(b.ads_cost) - SUM(b.order_cost) - SUM(b.accounting_sum)) AS [Торговая надбавка] +FROM base b +GROUP BY b.[d], b.[1c_id],b.Code; + + + +/* +SELECT + [Период] --datetime2(0) + ,[Статья] + ,[1c_id] + ,[Количество] + ,[Сумма] + ,[Учетная сумма, руб] + FROM [mag_pbi].[pbiProd].[СводныйСебестоимость Для PBI] s + WHERE s.Статья = N'Реализация' + + SELECT + [Дата] --datetime2(0) + ,[1c_id] + ,[Затраты, руб] + FROM [mag_pbi].[pbi].[РекламаМаркетплейсы] + + SELECT + [date] --datetime2(0) + ,[1c_id] + ,[Сумма] + FROM [mag_pbi].[pbi].[Стоимость обработки заказа] + */ +GO + +/****** Object: View [analytics].[Проекты] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ + +CREATE VIEW [analytics].[Проекты] as +SELECT + + p.[_IDRRef] as '1c_id' + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), p._IDRRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), p._IDRRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), p._IDRRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), p._IDRRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), p._IDRRef, 2),5,12) )) as 'id' + , us._Description as 'Ответственный' + ,[_Code] as 'Код УТ' + ,p.[_Description] as 'Название' + ,[_Fld22715] as 'Завершен' + + ,[_Fld22711] as 'ПлановаяДатаНачала' + ,[_Fld22712] as 'ДатаНачала' + ,[_Fld22713] as 'ПлановаяДатаОкончания' + ,[_Fld22714] as 'ДатаОкончания' + ,[_Fld22716] as 'Комментарий' + +FROM [MAG_2019].[dbo].[_Reference258] p /* Справочник.Проекты */ + LEFT JOIN [MAG_2019].[dbo].[_Reference228X1] us + ON us._IDRRef = [_Fld22710RRef] +WHERE p._Marked = 0 +GO + +/****** Object: View [analytics].[Товары на складах] Script Date: 2026-02-22 11:41:00 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +/****** Script for SelectTopNRows command from SSMS ******/ +CREATE view [analytics].[Товары на складах] as + SELECT + t._Fld17485RRef as [1c_id] + , LOWER(CONCAT(SUBSTRING ( convert(nvarchar(36), t._Fld17485RRef, 2), 25,8),'-',SUBSTRING ( convert(nvarchar(36), t._Fld17485RRef, 2),21,4),'-',SUBSTRING ( convert(nvarchar(36), t._Fld17485RRef, 2),17,4),'-',SUBSTRING ( convert(nvarchar(36), t._Fld17485RRef, 2),1,4),'-',SUBSTRING ( convert(nvarchar(36), t._Fld17485RRef, 2),5,12) )) + as artic_id + , s._Description as sklad + , s.[Категория] as [Где товар] + , sum( [_Fld17491]*(case _RecordKind when 0 then 1 when 1 then -1 end) ) as quantity + FROM [mag_2019].[dbo].[_AccumRg17484] t /*регистр товары на складах*/ + --INNER JOIN [mag_2019].[dbo]._Reference188X1 n /*номенклатура*/ ON n._IDRRef = t._Fld17485RRef + --INNER JOIN [mag_pbi].[pbi].[groups] g ON n._ParentIDRRef = g.[1c_id] + INNER JOIN [mag_pbi].[pbi].[sklad_2019] s /*склад*/ ON s._IDRRef = t._Fld17488RRef + WHERE s.[Категория]='Хранение' OR s.[Категория]='Фасовка' --g.path like 'Игрушки%' + GROUP BY t._Fld17485RRef, s._Description, s.[Категория] +GO