Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Version History

« Previous Version 46 Next »

Запросы, используемые в расчетах прогнозов

check_semaphore_ready

Используется в батче ‘Отправить SMS при отсутствии семафора’. В строках возвращает те сообщения, которые система отправляет на соответствующие номера в SMS.

all_stores

Используется в модуле classes/loaders/storeDim. Загружает список магазинов в память, чтобы каждый раз не запрашивать его из базы. Периодически перезагржается модулем loaders/masterData, в зависимости от параметра options.loader.reloadMasterDataHours, который по умолчанию равен 4-м часам. Также загружает привязки магазинов к регионам, к кодам погоды, и ценовым линиям (если используются в запросе prices_by_sku_store)

select s.STORE_ID NUM, s.STORE_NAME NAME, s.REGION_ID REGION, w.WEATHER_CODE WEATHER, WHS
    from STORES s
	left join STORE_WEATHER w on s.STORE_ID=w.STORE_ID
    where s.STORE_ID in (select distinct store_id 
    from sku_range 
    where end_date is null or end_date > dateadd(d, -90, getdate()))
    order by s.REGION_ID, s.STORE_ID

STORE_WEATHER это маппинг магазина и кода региона для получения данных погоды

должно быть из значений, определенных в опции - weather - locations

new_stores

Используется в модуле classes/loaders/storeDim для того, чтобы загружать новые магазины. Также как и запрос all_stores, периодически перезагружается в память.

select n.NEW_STORE_ID, n.OLD_STORE_ID, n.COEFFICIENT
    from RPM_NEW_STORES n
    where now() between n.START_DATE and n.END_DATE
        and n.IS_ACTIVE = 1

all_regions

Используется в модуле classes/loaders/storeDim для того, чтобы загружать список регионов. Также как и запрос all_stores, периодически перезагружается в память.

select '0' NUM, 'All' NAME, null WEATHER
union all
select r.REGION_ID NUM, r.REGION_NAME NAME, w.WEATHER_CODE WEATHER 
from REGIONS r 
left join REGION_WEATHER w on r.REGION_ID=w.REGION_ID

all_groups

Используется в модуле classes/loaders/ProductDim для того чтобы загружать полный справочник товарных групп. Периодически перезагружается в память модулем loaders/masterData, в зависимости от параметра options.loader.reloadMasterDataHours, который по умолчанию равен 4-м часам.

    SELECT GROUP_ID as GRP, GROUP_NAME as NAME
    FROM GROUPS
    WHERE GROUP_ID in (
        SELECT distinct GROUP_ID
    FROM PRODUCTS P
    WHERE (P.SKU_ID in (select distinct SKU_ID from SKU_RANGE where end_date >= dateadd(d, -365, getdate())
           or end_date is null)
           or (select min(start_date) from PRICES PR where PR.sku_id=P.sku_id) >= dateadd(d, -90, getdate()) )
    )
    order by GROUP_ID

sku_group

Используется в модуле classes/loaders/ProductDim для того чтобы загружать полный справочник товаров, обычно, либо ограниченный наличием ассортиментной матрицы, либо если новый товар, определяя его по наличию первой цены в последние 30 дней. Также периодически перезагружается в память модулем loaders/masterData, в зависимости от параметра options.loader.reloadMasterDataHours, который по умолчанию равен 4-м часам.

Вместе со справочником товаров, загружает в память их закупочные цены и % НДС (для модуля Цены, формы Оптимизация цен), коэф-ты страхового запаса на позиции и привязки позиций к товарным группам

select SKU_ID SKU, GROUP_ID GRP, 
           case when ITEM_CODE is null then ARTICLE_NAME else '(' + cast(ITEM_CODE as varchar) + ') '
            + ARTICLE_NAME end NAME,
           (SELECT SS FROM SS_ADJUSTMENTS SSA WHERE SSA.SKU_ID = p.SKU_ID) SS_COEF,
           LAST_PURCHASE_PRICE LAST_PP, VAT_PERCENT VAT, 1 LINE
    from PRODUCTS p
    where SKU_ID [sku_list]
      and GROUP_ID [group_list]
      and (P.SKU_ID in (select distinct SKU_ID from SKU_RANGE where end_date >= dateadd(d, -182, getdate()) 
            or end_date is null)
            or (select min(start_date) from PRICES PR where PR.sku_id=P.sku_id) >= dateadd(d, -30, getdate()) )
      order by GROUP_ID, SKU_ID

all_suppliers

Используется в модуле classes/loaders/supplierDim для того, чтобы загружать полный справочник поставщиком. Также периодически перезагружается в память модулем loaders/masterData, в зависимости от параметра options.loader.reloadMasterDataHours, который по умолчанию равен 4-м часам.

    select SUPPLIER_ID NUM, SUPPLIER_NAME NAME
    from SUPPLIERS
    order by SUPPLIER_NAME

all_lines

Используется в модуле classes/loaders/supplierDim для того, чтобы загружать полный справочник товарный линий, которые используются в модуле Цены (форма “Оптимизация цен”, “Политики”, “Динамика ценовых индексов”. Также периодически перезагружается в память модулем loaders/masterData, в зависимости от параметра options.loader.reloadMasterDataHours, который по умолчанию равен 4-м часам.

select 1 ID, 'All lines' NAME;

sku_store_ss_coef

Используется в модуле classes/loaders/skuStoreSSCoef для того, чтобы загружать коэффициенты страхового запаса в разрезе SKU-магазин, которые имеют приоритет над коэф-тами страхового запаса в разрезе SKU или магазина.

select SKU_ID SKU, STORE_ID STORE, SS_COEF
from SKU_STORE_SS_COEF

sales_sum_stores_sum_groups

Загружает суммарные продажи по группам и магазинам для анализа на сводном уровне. Используется в модуле classes/loaders/Sales, в том случае, если и для группы и для магазина в форме Анализ проставляется значение “sum”. Исторически, этот функционал не нашел широкого применения и имеет статус “экспериментальный”.

    select WEEK, sum(STOCK_ITEM_COUNT) CNT, sum(STOCK_VOLUME) STOCK,
                 sum(TRX_VOLUME) TRX_VOL, sum(SALES_VOLUME) SALES, {price_disc_sum}
    from SALES_GROUP
    where WEEK between :start_week and :end_week
      and ((sales_volume > 0) or (stock_volume > 0))
    group by WEEK

где {price_disc_sum}
    case when sum(SALES_VOLUME)=0 then null else round(sum(SALES_VALUE)/sum(SALES_VOLUME), 2) end PRICE,
    case when sum(SALES_VOLUME)=0 then 0 else round(sum(DISCOUNT_VALUE)/sum(SALES_VOLUME), 2) end DISC


sales_by_stores_sum_groups

Загружает суммарные продажи по группам для анализа на сводном уровне, но в разрезе магазинов. Используется в модуле classes/loaders/Sales, в том случае, если только для группы (не для магазинов) в форме Анализ проставляется значение “sum”. Исторически, этот функционал не нашел широкого применения и имеет статус “экспериментальный”.

    select STORE_ID STORE, WEEK, sum(STOCK_ITEM_COUNT) CNT, 
           sum(STOCK_VOLUME) STOCK, sum(TRX_VOLUME) TRX_VOL, 
           sum(SALES_VOLUME) SALES, {price_disc_sum}
    from SALES_GROUP
    where STORE_ID [store_list]
      and WEEK between :start_week and :end_week
      and ((sales_volume > 0) or (stock_volume > 0))
    group by STORE_ID, WEEK

где {price_disc_sum}
    case when sum(SALES_VOLUME)=0 then null else round(sum(SALES_VALUE)/sum(SALES_VOLUME), 2) end PRICE,
    case when sum(SALES_VOLUME)=0 then 0 else round(sum(DISCOUNT_VALUE)/sum(SALES_VOLUME), 2) end DISC

sales_by_group_sum_stores

Загружает суммарные продажи по магазинам для анализа на сводном уровне, но в разрезе групп. Используется в модуле classes/loaders/Sales, в том случае, если только для магазинов (не для групп) в форме Анализ проставляется значение “sum”, а для SKU - значение “skip”. Исторически, этот функционал не нашел широкого применения и имеет статус “экспериментальный”.

    select STORE_ID STORE, WEEK, sum(STOCK_ITEM_COUNT) CNT, 
           sum(STOCK_VOLUME) STOCK, sum(TRX_VOLUME) TRX_VOL, 
           sum(SALES_VOLUME) SALES, {price_disc_sum}
    from SALES_GROUP
    where STORE_ID [store_list]
      and WEEK between :start_week and :end_week
      and ((sales_volume > 0) or (stock_volume > 0))
    group by STORE_ID, WEEK

где {price_disc_sum}
    case when sum(SALES_VOLUME)=0 then null else round(sum(SALES_VALUE)/sum(SALES_VOLUME), 2) end PRICE,
    case when sum(SALES_VOLUME)=0 then 0 else round(sum(DISCOUNT_VALUE)/sum(SALES_VOLUME), 2) end DISC

sales_by_sku_sum_stores

Загружает суммарные продажи по магазинам для анализа на сводном уровне, но в разрезе SKU. Используется в модуле classes/loaders/Sales, в том случае, если только для магазинов (не для групп и не для SKU) в форме Анализ проставляется значение “sum”. Исторически, этот функционал не нашел широкого применения и имеет статус “экспериментальный”.

    select WEEK, sum(STOCK_ITEM_COUNT) CNT, sum(STOCK_VOLUME) STOCK, 
                 sum(TRX_VOLUME) TRX_VOL, sum(SALES_VOLUME) SALES, {price_disc_sum}
    from SALES_GROUP
    where GROUP_ID = :group
      and WEEK between :start_week and :end_week
      and ((sales_volume > 0) or (stock_volume > 0))
    group by GROUP_ID, WEEK

где {price_disc_sum}
    case when sum(SALES_VOLUME)=0 then null else round(sum(SALES_VALUE)/sum(SALES_VOLUME), 2) end PRICE,
    case when sum(SALES_VOLUME)=0 then 0 else round(sum(DISCOUNT_VALUE)/sum(SALES_VOLUME), 2) end DISC

sales_by_group_store

Загружает продажи в разрезе группа-магазин-неделя. Используется в модуле classes/loaders/Sales, если пользователь запрашивает прогнозы в разрезе SKU-магазин, либо группа-магазин, либо если запускается батч “Расчет прогнозов” (batches/fcst_batch). Указывается отдельно для каждого клиента, чтобы можно было исключать определенные недели или другие данные. При изменении этого запроса необходимо очищать и перезагружать файловый кэш.

    SELECT STORE_ID STORE, WEEK, STOCK_ITEM_COUNT CNT, STOCK_VOLUME STOCK,
           SALES_VOLUME SALES, {price_disc}
    FROM SALES_GROUP
    WHERE STORE_ID [store_list]
      AND GROUP_ID = :group
      AND WEEK between :start_week and :end_week
      AND ((sales_volume > 0) or (stock_volume > 0))

где {price_disc}
    case when SALES_VOLUME=0 then null else round(SALES_VALUE/SALES_VOLUME, 2) end PRICE,
    case when SALES_VOLUME=0 then 0 else round(DISCOUNT_VALUE/SALES_VOLUME, 2) end DISC      

sales_by_sku_store

Загружает продажи в разрезе SKU-магазин-неделя. Используется в модуле classes/loaders/Sales, если пользователь запрашивает прогнозы в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов” (batches/fcst_batch). Указывается отдельно для каждого клиента, чтобы можно было исключать определенные недели или другие данные. При изменении этого запроса необходимо очищать и перезагружать файловый кэш.

    SELECT SKU_ID SKU, STORE_ID STORE, WEEK, STOCK_VOLUME STOCK, 
           SALES_VOLUME SALES, {price_disc}
    FROM SALES_SKU
    WHERE STORE_ID [store_list]
      AND SKU_ID [sku_list]
      AND ((sales_volume > 0) or (stock_volume > 0))
      AND WEEK between :start_week and :end_week
где {price_disc}
    case when SALES_VOLUME=0 then null else round(SALES_VALUE/SALES_VOLUME, 2) end PRICE,
    case when SALES_VOLUME=0 then 0 else round(DISCOUNT_VALUE/SALES_VOLUME, 2) end DISC      

ranges_by_sku_store

Загружает ассортиментные матрицы для расчета прогнозов. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов” (batches/fcst_batch).

    select r.sku_id SKU, r.store_id STORE,
            case when ns.start_date > r.start_date then convert(varchar, ns.start_date, 21) 
                 else convert(varchar, r.start_date, 21) 
                 end STARTD,
            case when (max(r.end_date) is null and s.CLOSE_DATE is null) then '2050-01-01'
            when (max(r.end_date) is null and s.CLOSE_DATE is not null) then convert(varchar, s.CLOSE_DATE, 21)
            when (max(r.end_date) is not null and s.CLOSE_DATE is not null 
                 and max(r.end_date) > s.CLOSE_DATE) then convert(varchar, s.CLOSE_DATE, 21)
            else convert(varchar, max(r.end_date), 21) end as ENDD
    from sku_range r
    join stores s on s.STORE_ID = r.STORE_ID and coalesce(s.WHS,0) = 0
    left join rpm_new_stores ns on ns.new_store_id = r.store_id
    where (r.end_date is null or r.end_date >= ':end_date')
      and r.STORE_ID [store_list]
      and r.SKU_ID [sku_list]
    group by r.sku_id, r.store_id, r.start_date, ns.START_DATE, s.CLOSE_DATE

presentation_by_sku_store

Загружает презентационный запас для того, чтобы эти данные подтягивались в форму “Анализ” или для расчета прогнозов. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов (batches/fcst_batch).

  	select r.sku_id SKU, r.store_id STORE, sum(r.presentation_1+presentation_2) P,
           dbo.iso_week(r.start_date) STARTW,
           case when max(r.end_date) is null then '205001'
           else dbo.iso_week(max(r.end_date)) 
           end ENDW
    from presentation_stock_history r, STORES s
    where (r.end_date is null or r.end_date >= ':end_date')
       and r.store_id = s.store_id
       and r.STORE_ID [store_list]
       and r.SKU_ID [sku_list]
       and r.PRESENTATION_1 > 0
    group by r.sku_id, r.store_id, s.close_date, r.start_date

master_fcst_by_sku_store

Загружает мастер-прогнозы и подвязанные к ним магазины. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов (batches/fcst_batch). Движок использует эти данные, чтобы пропорционально повышать или понижать прогнозы в разрезе магазинов.

select SKU_ID SKU, WEEK, FCST, FIX,
      STUFF(
         (SELECT ',' + cast(s.store_id as varchar)
          FROM master_fcst_stores s
          WHERE s.sku_id=m.sku_id and m.week=s.week 
                and m.revision=s.revision and m.all_stores=0
          FOR XML PATH ('')), 1, 1, '') STORES
from master_fcst m
where revision=0 and deleted is null
  and sku_id [sku_list]
  and week between :start_week and :end_week

future_group_store_prices

Загружает прогнозные будущие цены в разрезе группа-магазин, которые используются при расчете прогнозов, если в прогнозах включена каннибализация (предикторы grp_price или grp_price_r в файле options.json5)

    select f.WEEK, f.STORE_ID as STORE,
           sum(f.A_PRICE*f.FORECAST)/sum(f.FORECAST) PRICE, count(*) CNT
    from FCST_SKU f with (nolock) join PRODUCTS p on f.SKU_ID=p.SKU_ID
    where f.ID=(select max(ID) from FCST with (nolock) where loaded is not null)
      and f.STORE_ID [store_list]
      and p.GROUP_ID = :group
      and f.FORECAST > 0
      and f.WEEK > :end_week
      and f.WEEK <= :max_week
    group by f.WEEK, f.STORE_ID

prices_by_sku_store

Загружает прошлые и будущие цены из таблицы PRICES, которые могут быть либо в разрезе SKU-магазин, либо SKU-ценовая линия. Определяющим для выбора системой уровня либо SKU-магазин, либо SKU-ценовая линия, является наличие в результах поля STORE или PRL. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов (batches/fcst_batch).

select SKU_ID SKU, STORE_ID STORE, PRICE
	  ,convert(varchar(10), START_DATE, 120) STARTD
	  ,convert(varchar(10), END_DATE, 120) ENDD
 from PRICES
 where SKU_ID [sku_list] and STORE_ID [store_list]
   and (END_DATE is null or END_DATE 
   > convert(varchar(8), CONVERT(DATETIME, ':start_date', 126), 112))

comp_prices_by_sku

Загружает цены конкурентов, чтобы отображать их в форме Анализ, либо использовать в прогнозах. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов (batches/fcst_batch).

    select COMPETITOR COMP, SKU_ID SKU, SDATE,
      case when ABSENT=1 or (error_msg is not null and isnull(PROMO_VALUE, VALUE) is null)
      then -1 else isnull(PROMO_VALUE, VALUE) end PRICE
    from PRICE_MONITORING_DATA
    where SKU_ID [sku_list]
      and COMPETITOR [comp_list]
      and (ABSENT=1 or PROMO_VALUE is not null or VALUE is not null)
      and SDATE >= :start_date

sales_day_by_sku_store

Загружает последние продажи в разрезе SKU-магазин-день, для того, чтобы движок обрабатывал предиктор adj_day (Дневная корректировка), корректирующий прогноз на ближайшие недели на основании последних продаж. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов” (batches/fcst_batch).

select s.SKU_ID SKU, s.STORE_ID STORE, to_char(s.SDATE, 'YYYYMMDD') D,
       s.SALES_VOLUME SALES,
       s.SALES_VALUE/nullif(s.SALES_VOLUME, 0) PRICE,
       s.STOCK_VOLUME STOCK, s.TRX_VOLUME TRX_VOL
from sales_sku_day s
where s.sku_id [sku_list]
  and s.store_id [store_list]
  and s.sdate between to_date(':start_date', 'YYYY-MM-DD')
  and to_date(':end_date', 'YYYY-MM-DD')

sales_day_share_by_sku_store

Загружает доли продаж по дням недели в разрезе SKU-магазин, для того, чтобы движок обрабатывал предиктор adj_day (Дневная корректировка), корректирующий прогноз на ближайшие недели на основании последних продаж. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов” (batches/fcst_batch).

select SKU_ID SKU, STORE_ID STORE, MONDAY_SHARE MON, TUESDAY_SHARE TUE, WEDNESDAY_SHARE WED,
       THURSDAY_SHARE THU, FRIDAY_SHARE FRI, SATURDAY_SHARE SAT, SUNDAY_SHARE SUN
from sales_sku_share
where sku_id [sku_list]
  and store_id [store_list]
  and MONDAY_SHARE between 0.07 and 0.25
  and TUESDAY_SHARE between 0.07 and 0.25
  and WEDNESDAY_SHARE between 0.07 and 0.25
  and THURSDAY_SHARE between 0.07 and 0.25
  and FRIDAY_SHARE between 0.07 and 0.25
  and SATURDAY_SHARE between 0.07 and 0.25
  and SUNDAY_SHARE between 0.07 and 0.25

sales_day_share_by_group_store

Загружает доли продаж по дням недели в разрезе группа-магазин, для того, чтобы движок обрабатывал предиктор adj_day (Дневная корректировка), корректирующий прогноз на ближайшие недели на основании последних продаж, в случае, если доли продаж по дням в разрезе группа-магазин, вытягиваемые запросом sales_day_share_by_sku_store, не найдены. Используется если пользователь запрашивает расчет прогнозов в разрезе SKU-магазин, либо если запускается батч “Расчет прогнозов (batches/fcst_batch).

select STORE_ID STORE, MONDAY_SHARE MON, TUESDAY_SHARE TUE, WEDNESDAY_SHARE WED,
       THURSDAY_SHARE THU, FRIDAY_SHARE FRI, SATURDAY_SHARE SAT, SUNDAY_SHARE SUN
from sales_group_share
where group_id=:group
  and store_id [store_list]
  and MONDAY_SHARE between 0.07 and 0.25
  and TUESDAY_SHARE between 0.07 and 0.25
  and WEDNESDAY_SHARE between 0.07 and 0.25
  and THURSDAY_SHARE between 0.07 and 0.25
  and FRIDAY_SHARE between 0.07 and 0.25
  and SATURDAY_SHARE between 0.07 and 0.25
  and SUNDAY_SHARE between 0.07 and 0.25

select_max_sales_week

Используется для определения последней недели продаж, за которую имеются данные. Движок строит прогноз в прошлом до этой недели, а прогноз в будущем - только начиная с текущей недели.

 select max(week) WEEK from SALES_GROUP

after_forecasting_batch_query

Набор запросов, выполняемый после завершения батча “Расчет прогнозов”. В нем, в частности, применяются значения корректировок прогнозов из таблицы FCST_ADJUSTMENTS и проставляется дата в поле LOADED таблицы FCST.

Форма Новые SKU/группы

На страницах сайта new_sku_load и new_group_load не используется, так как не используется в routes\api.js, Т.е. все что приходит в формы страниц сайта идет через http запросы, которые описаны в routes\api.js

new_sku_load и new_group_load используются в расчетах прогнозов

new_sku_load

Извлекает список пар новый SKU/аналог и соотношение RATIO, также извлекается ID группы.
В качестве фильтров может использоваться: список новых SKU, список групп, список поставщиков и завершающая неделя.

NEW_SKU_ID - новый товар, его аналогом является OLD_SKU_ID
который относится к товарной группе GROUP_ID, поставляемый поставщиком из списка supplier_list

RATIO (диапазон значений от 0,01 до 9,99) определяет насколько сильно влияет OLD_SKU_ID на NEW_SKU_ID в расчетах, а WEEK определяет, когда это влияние закончится.

Причем между SKU и группами, есть одно отличие. Новой группе можно назначить только один аналог, а SKU можно назначить несколько.

select p.GROUP_ID GRP, n.NEW_SKU_ID NEW_ID, n.OLD_SKU_ID OLD_ID, n.RATIO
    from new_sku n, products p
    where n.new_sku_id=p.sku_id
        and n.NEW_SKU_ID [sku_list]
        and p.GROUP_ID [group_list]
        and p.SUPPLIER_ID [supplier_list]
        and n.IS_ACTIVE = 1
        and n.WEEK > :end_week

new_group_load
Извлекает список пар новый GROUP/аналог и соотношение RATIO.
В качестве фильтров может использоваться список новых GROUP и завершающая неделя.

select n.NEW_GROUP_ID NEW_ID, n.OLD_GROUP_ID OLD_ID, n.RATIO
    from new_groups n
    where n.IS_ACTIVE = 1
	  and n.NEW_GROUP_ID [group_list]
      and n.WEEK > :end_week


sku_for_group
Извлекает список SKU_ID и наименований для заданного GROUP_ID.
Возвращает результат по запросу /api/new_items/sku_for_group на странице new_items.
Данные предназначены для заполнения выпадающих списков выбора нового SKU и аналогов.

    SELECT SKU_ID SKU, GROUP_ID GRP,
           case when ITEM_CODE is null then ARTICLE_NAME else '(' +
            cast(ITEM_CODE as varchar) + ') ' +
            ARTICLE_NAME end NAME
    FROM PRODUCTS
    WHERE GROUP_ID = :group_id
    order by GROUP_ID, SKU_ID

all_new_items
Возвращает результат запроса /api/new_items/list для заполнения основной таблицы new_items. Извлекает новый SKU, наименование, ID группы, завершающую неделю и также списки аналогов и соотношений RATIO с разделителем ";". В качестве фильтра может использоваться строка поиска, как для наименования, так и одного SKU_ID.

remove_new_item
Удаляет связь заданного нового SKU с аналогами, установкой признака IS_ACTIVE в 0.
Вызывается со страницы new_items запросом /api/new_items/remove с newsku в качестве параметра.

add_new_item
Добавляет связь нового SKU с аналогом и соотношением RATIO, либо добавив новую запись в таблицу NEW_SKU, либо обновив существующую.
Вызывается со страницы new_items запросами /api/new_items/add , /api/new_items/edit и /api/new_items/create_from_file, соответственно при добавлении, редактировании и импорте из CSV.
В SQL запрос передается один новый SKU, аналог, соотношение RATIO и завершающая неделя, http запросы массив из таких записей.

all_new_groups
Возвращает результат запроса /api/new_groups/list для заполнения основной таблицы new_groups. Извлекает ID новой группы, ID аналога, соотношение RATIO и завершающую неделю. Наименования групп заполняются в браузере из словарей.

remove_new_group
Удаляет связь заданной новой группы с аналогом, установкой признака IS_ACTIVE в 0.
Вызывается со страницы new_groups запросом /api/new_groups/remove с newgroup в качестве параметра

add_new_group
Добавляет связь новой группы с аналогом и соотношением RATIO, либо добавив новую запись в таблицу new_groups, либо обновив существующую.
Вызывается со страницы new_groups запросами /api/new_groups/create.
В SQL запрос передается ID новой группы, ID аналога, соотношение RATIO и завершающая неделя, а http запрос массив из таких записей.

Форма Мастер-прогноз

master_fcst_table

master_fcst_check_fcst

master_fcst_add_fcst

master_fcst_stores_set_revision

master_fcst_delete_fcst

Форма Доп. загрузка (экспериментальная)

add_fcst_main_table

add_fcst_sku_stores

add_fcst_sku_check

add_fcst_add_record

add_fcst_add_record_stores

add_fcst_edit_record

add_fcst_delete_record

Регулировка страхового запаса

Для чего и как используется регулировка страхового запаса описано тут.

Следующие 7 запросов относятся к странице http://localhost:3000/ss_adjust "Регулировка Страхового Запаса"

Коэффициент страхового запаса можно устанавливать на уровнях:

  • SKU-Вся сеть - установленный коэффициент применяется для всех магазинов в сети - таблица SS_ADJUSTMENTS;

  • Магазин - коэффициент применяется для всех позиций в выбранном магазине - таблица STORE_SS_COEF;

  • SKU-Магазин - коэффициент применяется для конкретной пары sku-магазин - таблица SKU_STORE_SS_COEF.

Таблицы имеют похожую структуру: набор ID к которым привязывается коэффициент страхового запаса для последующего автозаказа, сам коэффициент SS_COEF numeric(9,1) и пара UPDATED_BY/UPDATED с ID менеджера и временем изменения.

Фронтовой функционал собран в:
public\javascripts\ss_adjust\main.js
public\javascripts\ss_adjust\templates.js

Серверная часть в:
classes\controllers\ssAdjust.js

Практически все запросы по модификации таблиц SS_ADJUSTMENTS/STORE_SS_COEF/SKU_STORE_SS_COEF через http запросы из api.js выведены в public\javascripts\ss_adjust\main.js

То что открывается, например по http://localhost:3000/ss_adjust , это index.html собранный из .jade шаблонов и набор .js скриптов. Для удобства, основная часть собрана в main.js.

Эти скрипты выполняются в браузере на клиентской стороне и обеспечивают визуальную составляющую, а максимум что могут, так отправлять http запросы и разбирать ответ на них. У нас все http запросы собраны в routes\api.js и тут можно найти, что из backend обработки соответствует какому запросу.

А вот содержимое api.js уже выполняется на стороне сервера и уже здесь есть доступ к базе данных.

И как раз тут видно, что все запросы /api/ss_adjust/.../ обращаются к classes\controllers\ssAdjust.js Внутри ssAdjust.js можно найти обращение к базе и используемые SQL запросы.

Фронтовой функционал собран в:
public\javascripts\ss_adjust\main.js
public\javascripts\ss_adjust\templates.js
Серверная часть в:
classes\controllers\ssAdjust.js

ss_adjustments_table_get_skus
Основной запрос наполнения таблицы таба "SKUs" ss_adjust. Назначен на /api/ss_adjust/get_skus_by_group.
Фильтр список групп. Поиск по SKU осуществляется в браузере.

    SELECT
        P.GROUP_ID,
        P.SKU_ID,
        'DEFAULT USER' MANAGER,
        SUBSTRING(CONVERT(VARCHAR, SSA.UPDATED, 120), 1, 16) UPDATED,
        SSA.SS as SKU_SS
    FROM PRODUCTS as P
    LEFT JOIN SS_ADJUSTMENTS as SSA ON P.SKU_ID = SSA.SKU_ID
    WHERE P.GROUP_ID [group_id]
    ORDER BY UPDATED DESC;

ss_adjustments_table_get_stores
Основной запрос наполнения таблицы таба "Магазины" ss_adjust. Назначен на /api/ss_adjust/data.
Фильтров нет. Поиск по названию или ID магазина осуществляется в браузере.

    SELECT 
        S.STORE_ID,
        S.STORE_NAME, 
        'DEFAULT USER' STORE_MANAGER,
        SUBSTRING(CONVERT(VARCHAR, SSA.UPDATED, 120), 1, 16) STORE_UPDATED,
        SSA.SS_COEF as STORE_SS
    FROM STORES as S
    LEFT JOIN STORE_SS_COEF as SSA ON S.STORE_ID = SSA.STORE_ID
    ORDER BY STORE_UPDATED DESC;

ss_adjustments_table_get_sku-stores
Основной запрос наполнения таблицы таба "SKUs/Магазины" ss_adjust. Назначен на /api/ss_adjust/data.
Фильтров нет. Поиск по названию или ID магазина или SKU осуществляется в браузере.
Выпадающие списки для SKU/STORE - это форма добавления новой записи в таблицу.

    SELECT
        SSA.SKU_ID as SS_SKU_ID, P.ARTICLE_NAME as SS_SKU_NAME,
        SSA.STORE_ID as SS_STORE_ID, S.STORE_NAME as SS_STORE_NAME,
        'DEFAULT USER' SS_MANAGER,
        SUBSTRING(CONVERT(VARCHAR, SSA.UPDATED, 120), 1, 16) SS_UPDATED,
        SSA.SS_COEF
    FROM SKU_STORE_SS_COEF AS SSA
    INNER JOIN PRODUCTS as P
    ON P.SKU_ID = SSA.SKU_ID
    INNER JOIN STORES as S
    ON S.STORE_ID = SSA.STORE_ID
    ORDER BY SS_UPDATED DESC;

ss_adjustments_sku_coef_update
Запрос сохранения данных в SS_ADJUSTMENTS. Привязан к /api/ss_adjust/update-sku-coef и /api/ss_adjust/import_skus_to_table и /api/ss_adjust/bulk-update'.
Используется как при редактировании данных из формы, так и при импорте из csv.

    MERGE INTO SS_ADJUSTMENTS dest
    USING (SELECT :sku SKU_ID) src
    ON(dest.SKU_ID = src.SKU_ID)
    WHEN MATCHED THEN UPDATE SET UPDATED = GETDATE(), UPDATED_BY = :user, SS = :ss
    WHEN NOT MATCHED THEN INSERT(SKU_ID, UPDATED_BY, SS, UPDATED) 
              VALUES(src.SKU_ID, :user, :ss, GETDATE());

ss_adjustments_store_coef_update
Запрос сохранения данных в STORE_SS_COEF. Привязан к /api/ss_adjust/update-store-coef и /api/ss_adjust/import_stores_to_table и /api/ss_adjust/bulk-update'.
Используется как при редактировании данных из формы, так и при импорте из csv.

    MERGE INTO STORE_SS_COEF dest
    USING (SELECT :store STORE_ID) src
    ON (dest.STORE_ID = src.STORE_ID)
    WHEN MATCHED THEN UPDATE SET UPDATED = GETDATE(), UPDATED_BY = :user, SS_COEF = :ss
    WHEN NOT MATCHED THEN INSERT(STORE_ID, SS_COEF, UPDATED_BY, UPDATED) 
              VALUES(src.STORE_ID, :ss, :user, GETDATE());

ss_adjustments_skustore_coef_update
Запрос сохранения данных в SKU_STORE_SS_COEF. Привязан к /api/ss_adjust/update-skustore-coef и /api/ss_adjust/import_skustores_to_table и /api/ss_adjust/bulk-update'.
Используется как при редактировании данных из формы, так и при импорте из csv.

    MERGE INTO SKU_STORE_SS_COEF dest
    USING (SELECT :sku SKU_ID, :store STORE_ID) src
    ON (dest.SKU_ID = src.SKU_ID AND dest.STORE_ID = src.STORE_ID)
    WHEN MATCHED THEN UPDATE SET UPDATED = GETDATE(), UPDATED_BY = :user, SS_COEF = :ss
    WHEN NOT MATCHED THEN INSERT(SKU_ID, STORE_ID, SS_COEF, UPDATED_BY, UPDATED) 
              VALUES(src.SKU_ID, src.STORE_ID, :ss, :user, GETDATE());

ss_adjustments_skustore_create
Запрос добавления данных в SKU_STORE_SS_COEF. Привязан к /api/ss_adjust/create-new-skustore.
Используется для добавления новой пары SKU/STORE в таблицу с пустым SS_COEF.

    MERGE INTO SKU_STORE_SS_COEF dest
    USING (SELECT :sku SKU_ID, :store STORE_ID) src
    ON (dest.SKU_ID = src.SKU_ID AND dest.STORE_ID = src.STORE_ID)
    --WHEN MATCHED THEN UPDATE SET UPDATED = GETDATE(), UPDATED_BY = :user
    WHEN NOT MATCHED THEN INSERT(SKU_ID, STORE_ID, UPDATED_BY, UPDATED) 
              VALUES(src.SKU_ID, src.STORE_ID, :user, GETDATE());

Форма Корректировка прогноза

ss_adjustments_table_get_skus

ss_adjustments_table_get_stores

ss_adjustments_table_get_sku-stores

ss_adjustments_sku_coef_update

ss_adjustments_store_coef_update

ss_adjustments_skustore_coef_update

ss_adjustments_skustore_create

manual_forecast_table_data

manual_forecast_create

manual_forecast_delete

manual_forecast_update

manual_forecast_sales_sku_day

manual_forecast_sales_sku_day_group

fcst_adjustments_promo

fcst_adjustments_promo_stores_by_id

fcst_adjustments_promo_skus_by_id

Форма Просмотр прогнозов

fcst_view_sku_by_all_regions

fcst_view_sku_by_region

fcst_view_sku_by_store

fcst_view_group_by_region

fcst_view_group_by_store

fcst_view_sku_by_sum_stores

fcst_view_stock_sku_by_all_regions

fcst_view_stock_sku_by_store

fcst_view_stock_group_by_region

fcst_view_stock_group_by_store

fcst_view_stock_sku_by_region

fcst_view_assort_sku_by_all_regions

fcst_view_assort_sku_by_region

fcst_view_assort_sku_by_store

fcst_view_managers

Запросы Промо

Формы Промо

promo_group_headers

promo_by_sku_store

item_structure

store_structure

promo_update_item_prices

promo_approve

promo_user

promo_headers

promo_headers_calendar

select_promo_id

create_promo

import_internal_promo_header

promo_delete

delete_promo_skus

delete_promo_stores

promo_items

promo_items_detailed

promo_stores

promo_details

promo_update_dates

promo_update_params

promo_unapprove

promo_update_fmt_stores

promo_revisions

promo_add_revision

promo_delete_revision

promo_update_revision

promo_update_revision_sku

promo_update_sku_parameters

promo_update_sku_parameters_with_sales_price

promo_up_revision

promo_up_revision_header

promo_shift_revisions

promo_shift_revisions

promo_update_sku_benefit_with_sales_price

promo_update_sku_benefit_with_communications

promo_update_sku_benefit_with_sales_price_with_communications

promo_get_sku_duplicates

promo_item_names

promo_revision_details

promo_make_copy

promo_get_sku_comparables

promo_get_promo_revision_comparables

promo_get_skus_by_item_code

promo_excel_download

Промо-процессор

promo_update_group_ratio

promo_max_end_week

promo_update_group_ratio

fcst_promo_items

fcst_promo_avg_sales

fcst_promo_avg_sales_group

fcst_promo_stores

promo_delete_sku

promo_delete_sku

fcst_promo_details

fcst_promo_comparable_sku_delete

fcst_promo_items_update

fcst_promo_result_clean

fcst_promo_result_header_update

fcst_update_promo_group_uplift

fcst_promo_result_update

promo_calc_batch_headers

promo_batch_headers

promo_batch_stores

promo_batch_avg_sales_sku

promo_batch_avg_sales_group

promo_batch_merge_sku_sales

update_group_avg_promo_uplift

update_sku_avg_promo_uplift

Запросы, используемые при расчете заказов в модуле Пополнение

rpm_get_all_cross_dock_if_any

Данный запрос используется для того, чтобы определить список кросс-док диаграмм магазинов, которые нужно пересчитывать, если батч запущен по кросс-док диаграммам склада. Это необходимо для того, чтобы пересчитывать заказы магазинов сначала, перед тем, как пересчитывать КД-заказы склад-поставщик

rpm_get_store_picking_diagrams_by_contract_and_whs_id

Данные запрос используется, чтобы выбрать все диаграммы склад-поставщик и поставщик-склад для каждого конкретного склада, в том случае, если в параметрах указана хоть одна диаграмма, относящаяся к этому складу. Это необходимо потому, что заказ поставщик-склад зависит от заказов склад-магазин, а заказы склад-магазин зависят от заказов склад-поставщик (в части корректировки доставки по наличию остатка), а позиции в разных диаграммах/контрактах могут пересекаться. Отследить как именно они пересекаются - трудоемко, поэтому пересчет заказов по складу возможен только общий.

rpm_get_stores_for_orders

Данные запрос выбирает все пары магазин-склад либо, склад-склад, либо склад-поставщик из имеющихся диаграмм, для того чтобы выстроить очередность пересчета магазинов и складов. Очередность магазинов (которые не являются в тоже время и складами), выстраивается просто по возрастанию номеров, так как она не имеет логического значения. Очередность пересчета складов выстраивается по принципу: сначала промежуточные склады, потом склады, которые которые заказывают у поставщиков. Если цепочка промежуточных складов имеет несколько звеньев, то сначала пересчитываются более поздние звеня цепи, потом более ранние. Очередность так выстраивается потому, что заказы более поздних звеньев цепи являются прогнозом отгрузок при расчете заказов более ранних звеньев цепи.

rpm_get_diagrams_by_store

Данные запрос отрабатывает отдельно по каждому магазину или складу, в соответствии с очередностью их расчета. Он вытягивает те номера и параметры диаграмм, которые влияют на расчет заказов, кроме самого графика (вместо него подтягиваются календари запросом rpm_only_calendars_by_store).

rpm_only_calendars_by_store

Данные запрос отрабатывает отдельно по каждому магазину или складу, в соответствии с очередностью их расчета. Он вытягивает все календари, в привязке к диаграммам, а также даты заказа, доставки и следующей доставки, необходимые для расчета заказов.

rpm_get_skus_by_store

Данные запрос вытягивает номера SKU в привязке к событиям календаря, а также значения пользовательских изменений заказа, тип заказа, и пользователя который его изменил, если на момент расчета заказ по этому событию-SKU имеется. Это необходимо, чтобы сохранить пользовательские изменения при пересчете, а также отличить системные изменения заказа от пользовательских. Отрабатывает отдельно по каждому магазину или складу.

rpm_get_forecasts_by_store

Данный запрос выполняется отдельно для каждого магазина или склада и вытягивает прогнозы ( разрезе недель), страховой запас и промо-составляющую в прогнозе по всем пересчитываемым SKU.

rpm_get_master_products_forecasts_by_store

Данный запрос выполняется отдельно для каждого магазина или склада и вытягивает прогнозы (в разрезе недель), страховой запас и промо-составляющую в прогнозе по всем пересчитываемым SKU, которые являются готовым продуктом или полуфабрикатом в одной из рецептур и у них стоит галочка “производство” в параметрах позиций на этом конкретном магазине или складе.

rpm_get_sku_range_for_master_products

Данный запрос выполняется отдельно для каждого магазина или склада, и вытягивает ассортиментные матрицы в привязке к датам для каждого SKU, которое является готовым продуктом или полуфабрикатом в одной из рецептур.

rpm_get_if_bom_by_store

Данный запрос выполняется отдельно для каждого магазина или склада, и вытягивает все рецептуры для всех мастер-продуктов или полуфабрикатов, у которых в параметрах позиций стоит галочка “производство” на этом конкретном магазине или складе.

rpm_get_master_products_stock_presentation

Данный запрос выполняется отдельно для каждого магазина или склада, и вытягивает значения презентационного запаса для мастер-продуктов в рецептурах, у которых стоит галочка “производство”

rpm_get_presentation_stock_by_store

Данный запрос выполняется отдельно для каждого магазина или склада, и вытягивает значения презентации для всех пересчитываемых SKU.

rpm_get_add_presentation_stock_by_store

Данный запрос выполняется отдельно для каждого магазина или склада, и вытягивает значения дополнительной выкладки для всех пересчитываемых SKU.

rpm_get_latest_stock_by_store

Данный запрос вытягивает значения остатка, за минусом кол-ва, зарезервированного для заказов pick-to-zero, для каждого магазина или склада, а также дату этого остатка.

rpm_get_latest_stock_for_whs_stock_estimation

Данный запрос выполняется перед началом расчетов магазинов, и вытягивает остатки складов, которые затем используются для расчета прогнозного остатка склада по датам, чтобы выполнять корректировку доставки заказов магазинов и оценивать прогнозный остаток магазинов по датам, увеличивая будущие заказы магазинов там, где остаток склада будет вымываться.

rpm_get_latest_stock_date

Данный запрос вытягивает самую последнюю дату остатков из таблицы LATEST_STOCK. Заказы считаются на N вперед от этой даты. От этой же даты рассчитываются прогнозные остатки склада. Дата корректируется на +1 день, исходя из предположения, что остатки загружаются на вчера на вечер, а система считает их как сегодня на утро (параметр options.replenishment.adjustStockDate)

rpm_get_tender_items

Запрос вытягивает активные тендерные позиции из таблицы RPM_TENDER_ITEMS. Эти данные используются для того, чтобы проставлять на заказах признак “Тендер”.

rpm_get_sku_range_by_store

Запрос вытягивает активные позиции в ассортиментной матрице в разрезе дат. Выполняется по каждому магазину отдельно. Далее, эти данные используются, чтобы не заказывать позиции, которые не активные в АМ.

rpm_get_master_sku_range_by_store

Запрос вытягивает готовую продукцию, которая активна в ассортиментной матрице в разрезе дат, и производится в этом магазине.. Выполняется по каждому магазину отдельно. Далее, эти данные используются, чтобы не заказывать ингредиенты для готовой продукции, которая не активна в АМ.

rpm_get_sku_parameters

Данный запрос выполняется для каждого магазина отдельно, и вытягивает параметры позиций, по которым рассчитывается заказ: цена закупки, галочка “утро”, признак “pick-to-zero” для склада, с которого заказывается позиция, признак “whs-pick-to-zero” для транзитного склада, для которого рассчитывается заказ, срок годности для расчета прогноза списания (SHELF_DAYS), срок годности, умноженный на коэффициент для обрезания заказов (SHELF_DAYS_FOR_LIMIT), максимальная вместимость, вес, гарантированный заказ, кратность, минимальный заказ, признак “лимит срока годности”, дополнительные циклы заказа, дополнительные дни в прогнозе Д1Д2, фактор округления кратности, лимит списаний.

По умолчанию, для ограничения заказов по сроку годности, используется следующая формула:
round(coalesce(cast(ssc.SHELF_LIFE_PERC as numeric)/100, 0.8)
* (p.SHELF_DAYS - case when p.SHELF_DAYS >= 14 then 2 when p.SHELF_DAYS >= 3 then 1 else 0 end), 1) SHELF_DAYS_FOR_LIMIT

При необходимости ее поменять, необходимо кастомизировать этот запрос для заказчика.

rpm_get_add_load_by_store

Вытягивает даты дополнительной загрузки для SKU по каждому магазину отдельно.

rpm_get_sales_holiday_uplift

Вытягивает повышающие коэффициенты для праздничных дней в разрезе групп, для каждого магазина отдельно.

rpm_get_sales_sku_share

Вытягивает коэффициенты дней недели для каждого SKU. В случае, если для SKU не были посчитаны КДН, они берутся этим запросом с группы. Выполняется по каждому магазину отдельно.

rpm_get_master_products_sales_sku_share

Вытягивает коэффициенты дней недели для каждого мастер-продукта из рецептур (IF_BOM_V). В случае, если для SKU не были посчитаны КДН, они берутся этим запросом с группы. Выполняется по каждому магазину отдельно.

rpm_get_elasticity_formulas

Вытягивает формулы ценовой эластичности, чтобы корректировать прогноз по дням в случае изменения цены в середине недели. Выполняется для каждого магазина отдельно.

rpm_get_elasticity_formulas_for_master_products

Вытягивает формулы ценовой эластичности для мастер-продуктов из рецептур (IF_BOM_V), чтобы корректировать прогноз по дням в случае изменения цены в середине недели. Выполняется для каждого магазина отдельно.

rpm_get_prices_for_store

Вытягивает текущие и будущие цены в разрезе дат для всех SKU, по которым считается заказ. Выполняется для каждого магазина отдельно.

rpm_get_prices_for_store_master_products

Вытягивает текущие и будущие цены в разрезе дат для мастер-продуктов из рецептур (IF_BOM_V). Выполняется для каждого магазина отдельно.

rpm_get_all_promo_and_stores

Вытягивает информацию о заголовках промо: номер промо, дата начала, дата завершения, название промо, % скидки по умолчанию, перечень магазинов в которых проводится промо.

rpm_get_all_promo_skus

Вытягивает информацию об SKU, которые участвуют в промо: номер промо, номер SKU, % скидки, цена продажи без скидки, повышающие коэф-ты промо (с учетом скидки и без).

rpm_get_store_orders_by_delivery_date_period

Вытягивает подтвержденные заказы магазинов, по которым нет прихода (oh.RECEIVED_DATE is null and ol.RECEIVED_QTY is null), а также ручные заказы из таблицы MANUAL_ORDERS. Используется для формирования товаров в пути в заказах. Выполняется по каждому магазину отдельно.

rpm_get_whs_orders_by_delivery_date_period_for_picking

Вытягивает подтвержденные заказы складов, по которым нет прихода (oh.RECEIVED_DATE is null and ol.RECEIVED_QTY is null), а также ручные заказы из таблицы MANUAL_ORDERS. Используется для расчета прогнозного остатка склада по датам.

rpm_delete_orders

Удаляет неподтвержденные заказы по каждому магазину отдельно, для диаграмм, которые участвуют в расчете. Это делается для того, чтобы вместо старых заказов, вставить новые, пересчитанные заказы.

rpm_insert_order_header

Запрос добавляет один новый заказ в таблицу RPM_ORDER_HEADER. Если при вставке пачки заказов через bulk insert возникла ошибка, то используется этот запрос, чтобы вставить в таблицу заказы по одному, для того, чтобы проблема в одном заказе не влияла на другие заказы в пачке.

rpm_insert_order_line

Запрос добавляет одну новую строку заказа в таблицу RPM_ORDER_LINE. Если при вставке пачки заказов через bulk insert возникла ошибка, то используется этот запрос, чтобы вставить в таблицу заказы по одному, для того, чтобы проблема в одном заказе не влияла на другие заказы в пачке.

rpm_get_previous_deliveries_for_writeoffs_calc

Вытягивает предыдущие заказы, по которым были доставки и оприходовано количество больше нуля, для расчета прогноза списаний товара. Выполняется по каждому магазину отдельно.

rpm_confirmed_deliveries_for_write_off_calc

Вытягивает предыдущие заказы, по которым доставка будет сегодня или будущей датой, для расчета прогноза списаний товара. Выполняется по каждому магазину отдельно.

rpm_get_confirmed_pick_zero_deliveries

Вытягивает подтвержденные заказы склад-поставщик pick-to-zero. Эти данные затем используются для того, чтобы выравнивать количество в заказах магазинов с количеством в заказе склада.

rpm_check_whs_working_day

Вытягивает рабочие дни склада на основании активных событий в календарях. Используется для того, чтобы при адаптации графика заказов магазинов по схеме pick-to-zero, заказы не попадали на нерабочие дни.

rpm_get_whs_pick_zero_calendars

rpm_get_whs_pick_zero_stock

rpm_get_store_pick_zero_orders

rpm_create_skus_by_diagrams_table

rpm_delete_skus_by_diagrams_table

rpm_delete_tmp_table_by_store

rpm_truncate_tmp_table_by_store

rpm_fill_tmp_table_with_skus_by_diagram

rpm_select_tmp_table_diagrams

rpm_clear_store_adjusted_delivery_today_order_delivery

rpm_get_existing_cross_dock_orders

rpm_delete_existing_cross_dock_orders

rpm_get_orders_by_stores_for_cross_dock

rpm_update_line_order_volume

rpm_add_whs_order_id_to_header

rpm_get_cross_dock_calendars

rpm_get_forecasts_for_picking

rpm_get_forecasts_for_picking_by_store

rpm_get_master_products_forecasts_picking_by_store

rpm_get_closest_picking_calendars

rpm_get_store_orders_with_insufficient_stock

rpm_get_pick_to_zero_with_insufficient_order

rpm_save_picking_forecast_orders

rpm_delete_assigned_lots

rpm_get_picking_orders_for_lots_assignment

rpm_get_picking_lots_for_assignment

rpm_get_adjusted_picking_orders_to_recalculate

rpm_get_cross_orders_to_adjust_sku_delivery

rpm_clear_adjusted_delivery

rpm_set_adjusted_delivery_by_order_id

rpm_get_todays_whs_deliveries

rpm_confirm_orders_after_orders_batch

rpm_max_calendar_id

rpm_delete_calendars

rpm_delete_unlinked_headers_and_lines

Запросы, используемые при работе с функционалом модуля Пополнение

rpm_check_orders_batch_running

Форма Диаграммы

rpm_diagrams

rpm_suppliers

rpm_warehouses

rpm_contracts_by_supplier

rpm_get_contract_by_diagram

rpm_check_remaining_stores_for_cross_dock

rpm_skus_by_supplier

rpm_get_diagram

rpm_get_groups_for_diagram

rpm_delete_rpm_diagram_groups_by_diagram

rpm_get_diagram_by_id

rpm_get_diagram_mins_for_store

rpm_get_diagram_and_related_crdock

rpm_check_cross_dock_stores_confirmation

rpm_check_cross_dock_whs_confirmation

rpm_max_diagram_id

rpm_update_diagram

rpm_get_all_diagrams

rpm_stores_by_contract

rpm_check_if_diagram_orders_confirmed

rpm_full_delete_diagram_calendars_orders

rpm_full_delete_diagram_calendars_orders_cross_dock_stores

rpm_get_cross_dock_whs_diagram

rpm_delete_rpm_diagram_items_by_diagram

rpm_check_contract_for_supplier

rpm_check_stores_for_contract

rpm_check_skus_for_contract_and_stores

rpm_get_whs_cross_dock_diagram_by_child_id

rpm_current_diagrams_by_contract_and_store

rpm_check_is_future_diagram_exists

rpm_check_if_confirmed_orders_exist

rpm_close_existing_diagrams

rpm_check_if_store_can_be_added_to_cross_dock

rpm_check_if_store_is_attached_to_crdock_pack

rpm_check_if_store_is_attached_to_another_crdock_pack

rpm_get_diagrams_to_copy_params

rpm_get_diagram_items_by_id

rpm_update_diagram_end_date

rpm_delete_calendar_by_diagram_id_and_end_date

rpm_check_if_today_confirmed_order

rpm_update_start_store_crdock_diagrams

rpm_update_interval_store_crdock_diagrams

rpm_get_delivery_days_of_crdock_pack

rpm_update_schedule_store_crdock_diagrams

rpm_delete_skus_store_cr_dock_diagrams

rpm_update_all_skus_store_cross_dock_diagrams

rpm_get_cr_dock_store_diagram_ids

Форма Календари


Место Календарей в системе MySales

Диаграмма описывает общие правила по которым будут создаваться заказы и поставки (приходы) от поставщика на магазины, или от поставщика на склады, и со складов на магазины. В диаграмме указывается диапазон дат когда такие правила будут действовать.
Другими словами диаграма описывает:

  • График заказов (дни или периоды)

  • График поставок (дни или периоды)

  • Время когда Майселс  автоматически подтвердит и сохранит заказ в системе и если указан email, то отправит заказ по електронной почте

  • Привязка вышеуказанеых настроек к контракту поставщику магазину или складу

Подробнее про диаграммы тут.

На основании диаграмм создаются Календари на события.
События бывают двух видов: Заказ и Поставка.

По каким либо причинам поставка может отмениться, и если это известно заранее, ее следует деактивировать в календаре. При пересчете заказов Система учтет что из плана выпала поставка и пересчитает Заказы и Поставки с учетом таких “каникул“ поставщика. Если по какой либо причине не было деактивировано событие в календаре, а поставка не произошла, то это необходимо отобразить в приходах нулевым количеством или если это не будет сделано, то система по остаткам скорректируется и при очередном пересчете скорректирует заказы.

Календари создаются в таких случаях:

  • при сохранении диаграммы календари сразу создаются под эту диаграмму на срок действия диаграммы или на некоторое количество дней вперед (это настройка файла опций - config/options_databasename.json5 replenishment: {calendarDays: 80 // how many days ahead the calendar is calculated} )

  • можно пересчитать (пересоздать) календари, из таблицы с диаграммами на сайте - localhost:3000/diagrams (или со странице с календарями - localhost:3000/calendars, как указано на картинках ниже. Перед пересчетом заказов, пересчитываются календари на основании которых создаются эти заказы. Пересчитываются заказы по выбранной диаграмме, и только те, у которых дата больше текущей. Если нужно пересчитать календари и заказы по одной диаграмме, то это можно сделать из меню строки слева. Если пересчитать несколько диаграмм, то слева в чекбоксах отметить необходимые для пересчета диаграммы, а потом справа в меню выбрать пересчет отмеченых диграмм. При пересчете заказов (календарей) по выбранной диаграмме, так же пересчитываются и календари и заказы по всем связанным диаграммам

  • если ко времени запуска батча есть недосчитанные календари, они досчитываются

  • ручное добавление календаря ( с привязкой к диаграмме и без привязки к диаграмме )

В момент создания диаграммы, автоматически создаются календари. Потом если в диаграмме меняется расписание, буквально сразу, то не подвержденные календари удаляются, и создаются новые.
При сохранении скорректированной диаграммы, по которой уже созданы календари и прошло время (сформировались заказы и были подтверждены), удаляються только те календари которые по дате позже чем календари с подтвержденными заказами, т.е. подтвержденные календари не удаляются, а удаляются те, которые по хронологии идут позже и не имеют подтвержденных заказов.

Календарь можно пересчитать по отдельно взятой диаграмме. Если этого не сделать он будет пересчитан ночью батчем.
Пересчитать календари можно со страницы календарей или со страницы диаграмм.

“Пересчитать календари“ не стоит понимать дословно. Сами по себе календари не пересчитываются они создаются Диаграммой и по сути являются расписанием событий для этой диграммы. События - Заказ или Поставка.
”Пересчитать календари” это значит пересчитать Заказы и Поставки которые будет происходит согласно этим календарям. Система это осуществляет по расписанию, как правило ночью, путем запуска Батча - скрипта, который выполняет расчеты.

Форма Календари
http://localhost:3000/calendar
Основная таблица этой формы RPM_CALENDAR

ID - уникальный идентификатор Календаря, его номер
DIAGRAM_ID - номер Диаграммы, на основании которой был создан Календарь
ORDER_DATE - дата Заказа который создается по этому календарю
DELIVERY_DATE - дата Поставки которая создается по этому календарю
NEXT_DELIVERY_DATE - дата Следующей Поставки которая создается по этому календарю
MORNING - утром или не утром произойдет Поставка запланированная на DELIVERY_DATE
IS_ACTIVE - активен ли данный календарь. Если значение 1, тогда система будет создавать Заказы и Поставки по этому календарю. Если значение 0 - не будет
DELETED_DATE - дата изменения поля IS_ACTIVE
DELETED_BY - кем было изменено поле IS_ACTIVE. Если -1, то изменение внесла либо система, либо разработчик
DELETED_REASON - причина изменения поля IS_ACTIVE
TYPE - тип календаря. d - созданный по диаграмме (автоматически при сохранении или редактировании диаграммы,
с - созданный вручную, custom (дополнительный),
m - созданный вручную, manual (ручной)

Строки из RPM_CALENDAR не удаляются, при “выключении“ Календаря, а IS_ACTIVE становится равным 0
Физическое удаление строк из таблицы RPM_CALENDAR происходит при пересчет расписания или при удаление диаграммы.

По одной диаграмме может быть создано несколько календарей с одной и той же датой, но с разным значением TYPE (В коде JS это обычно calendarTYPE)
Однако на одну дату может быть только один календарь с определенным типом.

Когда в расписании Диаграммы на одной неделе создается более 1 события, учитывается, чтобы дата поставки раннего календаря не была больше или равна дате поставки позднего.
Например: понедельник - 4, вторник - 2


На сайте на странице календарей ( http://localhost:3000/calendar ) можно наблюдать, что одна строка из таблицы RPM_CALENDAR будет отображаться двумя строками Заказ и Поставка

В дальнейшем по календарям формируются Заказы и Поставки.

Запросы FrontEnd

Фронтовой функционал собран в:
public\javascripts\rpm_calendars\main.js
public\javascripts\rpm_calendars\templates.js
public\javascripts\rpm_calendars\calendar_validators.js
public\javascripts\rpm_calendars\addStoreAndDiagramModal.js
public\javascripts\rpm_calendars\createCustomCalendarForm.js
Серверная часть в:
classes\controllers\rpm\calendar.js

rpm_max_order_id
В http запрос не выведен. Предназначен для служебных целей определения следующего ID заказа авто-инкрементом.
Используется в addManualEvent назначенном на /api/rpm/add_manual_event , для создания пользовательского события формирования заказа. Сами записи календарей создает и удаляет система в фоновой обработке (батч). Пользователь может только активировать и деактивировать запись в календаре.

    select max(i.ID) as ID 
    from (
        select max(ID) as ID from RPM_ORDER_HEADER
        union all
        select max(ID) as ID from RPM_ORDER_LINE
        union all
        select max(ID) as ID from RPM_ORDER_HEADER_HIST
        union all
        select max(ID) as ID from RPM_ORDER_LINE_HIST
    ) i

rpm_select_events
Основной запрос страницы calendar. Предназначен для извлечения данных отображаемых таблицей. Назначен на /api/rpm/get_events.

Фильтры:
diagramID - массив ID диаграмм, через запятую,
diagramName - строка для поиска диаграммы по имени,
date - интервал дат разделенный "--", для определения ORDER_DATE или DELIVERY_DATE в зависимости от ключа,
supplier - для определения поставщика по связи с RPM_DIAGRAM.SUPPLIER_ID,
contract - для определения договора, по связи через RPM_DIAGRAM.SPECIFICATION_ID и CONTRACTS.CONTRACT_ID, есть условие как на CONTRACT_ID, так и на CONTRACT_NAME,
store - для определения магазина, по связи через RPM_DIAGRAM.STORE_ID,
eventType - для задания ключа поиска дат ('all','delivery','order'),

calendarType - для определения типа события,

manager - для определения пользователя, последним изменившего запись в RPM_DIAGRAM.

   select c.ID CALENDAR_ID, d.ID DIAGRAM_ID, d.NAME DIAGRAM_NAME, convert(varchar, c.ORDER_DATE, 21) as ORDER_DATE,
        convert(varchar, d.START_DATE, 21) as DIAGRAM_START, convert(varchar, d.END_DATE, 21) as DIAGRAM_END,
        d.UPDATED_BY as MANAGER_ID, mn.NAME as MANAGER_NAME,
        s.SUPPLIER_NAME, c.IS_ACTIVE, c.DELETED_DATE, c.DELETED_BY, c.DELETED_REASON, c.TYPE as CALENDAR_TYPE,
        d.WHS_ID, d.WAREHOUSE_TYPE, st.STORE_NAME as WHS_STORE_NAME, st.STORE_CODE, d.STORE_ID, st1.STORE_NAME,
        d.SUPPLIER_ID, ct.CONTRACT_ID, ct.CONTRACT_NAME,
        convert(varchar, c.DELIVERY_DATE, 21) as DELIVERY_DATE,
        convert(varchar, c.NEXT_DELIVERY_DATE, 21) as NEXT_DELIVERY_DATE,
        case when d.ALL_SKUS = '0' then (select count(*) from RPM_DIAGRAM_ITEMS i where i.DIAGRAM_ID = d.ID)
            else (select count(*) from PRODUCTS p where p.SUPPLIER_ID = d.SUPPLIER_ID) end CNT_SKUS,
        c.EVENT_TYPE TYPE
    from (select *, 'order' EVENT_TYPE from RPM_CALENDAR rc
          where :need_order = 1 and ORDER_DATE BETWEEN ':startDate' AND ':endDate'
            and (':calendar_type' = '0' or rc.TYPE = ':calendar_type')
          union all
          select *, 'delivery' EVENT_TYPE from RPM_CALENDAR rc1
          where :need_delivery = 1 and DELIVERY_DATE BETWEEN ':startDate' AND ':endDate'
            and (':calendar_type' = '0' or rc1.TYPE = ':calendar_type')
         ) c
    inner join RPM_DIAGRAM d on d.ID = c.DIAGRAM_ID
    inner join CONTRACTS ct on ct.CONTRACT_ID = d.SPECIFICATION_ID
        and d.ID [diagram_id]
        and d.NAME like ':diagram_name'
        and d.SUPPLIER_ID [supplier]
        and ( d.UPDATED_BY = :manager_id or :manager_id is null )
        and d.STORE_ID [store]
        and (d.SPECIFICATION_ID like ':contract' or upper(ct.CONTRACT_NAME) like ':contract')
    left join SUPPLIERS s on s.SUPPLIER_ID = d.SUPPLIER_ID
    left join STORES st on st.STORE_ID = d.WHS_ID
    left join STORES st1 on st1.STORE_ID = d.STORE_ID
    left join MANAGER mn on mn.ID = d.UPDATED_BY

get_diagram_managers
Назначен на /api/rpm/get_diagram_managers. Используется для наполнения выпадающего списка выбора менеджеров, для фильтра основной таблицы.

    select m.ID as MANAGER_ID, m.NAME as MANAGER
    from MANAGER m
    where exists (select 1 from RPM_DIAGRAM rd where rd.UPDATED_BY = m.ID)
    order by m.NAME

rpm_get_event_details
Назначен на /api/rpm/get_diagram_managers. Используется для извлечения записи события по calendar_id, для наполнения модального окна редактирования события календаря.

    select oh.STORE_ID, s.STORE_NAME, ol.SKU_ID, p.ARTICLE_NAME as SKU_NAME, 
           ol.RECEIVED_QTY, ol.ADJUSTED_DELIVERY,
           coalesce(ol.CUSTOM_ORDER_VOLUME, ol.ORDER_VOLUME) as VOLUME, p.ITEM_CODE
    from (select * from RPM_CALENDAR where ID = :calendar_id) c
    inner join RPM_ORDER_HEADER oh on oh.CALENDAR_ID = c.ID
    inner join RPM_ORDER_LINE ol on ol.ID = oh.ID
    inner join STORES s on s.STORE_ID = oh.STORE_ID
    inner join PRODUCTS p on p.SKU_ID = ol.SKU_ID

rpm_get_details_for_manual_event
Назначен на /api/rpm/get_skus_for_manual_event. Используется в модальном окне создания пользовательского события формирования заказа.

rpm_get_diagram_schedule
Назначен на /api/rpm/get_diagram_schedule. Используется для извлечения графика по диаграмме, который отображается в модальном окне.

    select ID, convert(varchar, ORDER_DATE, 121) as ORDER_DATE, 
               convert(varchar, DELIVERY_DATE, 121) as DELIVERY_DATE,
            IS_ACTIVE, DELETED_REASON
    from RPM_CALENDAR
    where DIAGRAM_ID = :diagram_id 
        and (ORDER_DATE >= ':start_date' or DELIVERY_DATE >= ':start_date')
    order by ORDER_DATE

rpm_cancel_calendar_event
Назначен на /api/rpm/cancel_event. Используется для отмены события в календаре, при снятии галки "Актив." или массово над отмеченными записями из меню "Отменить события".

rpm_make_calendar_event_active_again
Назначен на /api/rpm/make_event_active_again. Используется для активирования ранее отмененных событий в календаре.

rpm_get_suppliers_from_diagrams
Назначен на /api/rpm/get_custom_params. Вызывается при открытии модального окна добавления события. Извлекает список поставщиков для активных диаграмм. Наполняет выпадающий список поставщиков в модальном окне.

    select distinct s.SUPPLIER_ID ID, s.SUPPLIER_NAME NAME
    from RPM_DIAGRAM d
    inner join SUPPLIERS s on d.SUPPLIER_ID = s.SUPPLIER_ID
    where coalesce(d.WAREHOUSE_TYPE, 'any') <> 'c'
        and d.START_DATE <= cast(getdate() as date)
        and (d.END_DATE >= cast(getdate() as date) or d.END_DATE is null)

rpm_get_diagrams_by_supplier
Назначен на /api/rpm/get_custom_params и /api/rpm/get_custom_params_by_supplier. Второе используется в public\javascripts\rpm_calendars\createCustomCalendarForm.js Извлекает список диаграмм для заданного поставщика.

    select distinct d.ID, d.NAME
    from RPM_DIAGRAM d
    where d.SUPPLIER_ID = :supplier_id 
        and coalesce(d.WAREHOUSE_TYPE, 'any') <> 'c' 
        and d.START_DATE <= cast(getdate() as date)
        and (d.END_DATE >= cast(getdate() as date) or d.END_DATE is null)
    order by d.ID

rpm_get_diagrams_by_contract
Назначен на /api/rpm/get_custom_params_by_contract. Используется в public\javascripts\rpm_calendars\createCustomCalendarForm.js Извлекает список диаграмм для заданного договора.

    select d.ID as DIAGRAM_ID, d.NAME as DIAGRAM_NAME, d.STORE_ID, s.STORE_NAME
    from RPM_DIAGRAM d
    left join STORES s on s.STORE_ID = d.STORE_ID
    where d.SPECIFICATION_ID = :contract_id
        and coalesce(d.WAREHOUSE_TYPE, 'any') <> 'c'
        and d.START_DATE <= ':calendar_date'
        and (d.END_DATE >=  ':calendar_date' or d.END_DATE is null)
    order by d.ID

rpm_check_todays_calendar
Используется в addCustomEvent выведенном в /api/rpm/add_custom_event. Проверяет существование календаря на заданную дату.

    select ID from RPM_CALENDAR 
    where ORDER_DATE = ':order_date' and DIAGRAM_ID = :diagram_id and TYPE != 'm'

rpm_get_max_calendar_dates
Используется в addCustomEvent выведенном в /api/rpm/add_custom_event. Определяет предельные даты заказа и доставки для заданной диаграммы.

    select convert(varchar, max(ORDER_DATE), 121) as MAX_ORDER_DATE, 
           convert(varchar, max(DELIVERY_DATE), 121) as MAX_DELIVERY_DATE 
    from RPM_CALENDAR where DIAGRAM_ID = :diagram_id

rpm_create_custom_event
Используется в addCustomEvent выведенном в /api/rpm/add_custom_event. Добавляет в RPM_CALENDAR запись о новом событии.

    insert into RPM_CALENDAR (ID, DIAGRAM_ID, ORDER_DATE, DELIVERY_DATE, IS_ACTIVE, TYPE, NEXT_DELIVERY_DATE)
    values (:id, :diagram_id, ':order_date', ':delivery_date', ':active', ':type',
        (select min(r.DELIVERY_DATE)
         from (select * from RPM_CALENDAR) r
         where r.DIAGRAM_ID = :diagram_id and r.DELIVERY_DATE > ':delivery_date' and r.IS_ACTIVE = '1' and r.TYPE != 'm')
        );

    update c
    set NEXT_DELIVERY_DATE = (select min(DELIVERY_DATE) from RPM_CALENDAR where DELIVERY_DATE > c.DELIVERY_DATE 
                              and DIAGRAM_ID = c.DIAGRAM_ID and TYPE != 'm' and IS_ACTIVE = '1')
    from RPM_CALENDAR c
    where (ORDER_DATE >= (select max(ORDER_DATE) from RPM_CALENDAR
                          where DIAGRAM_ID = :diagram_id
                          and ORDER_DATE < ':order_date' and ORDER_DATE >= cast(getdate() as date)
                          and TYPE != 'm' and IS_ACTIVE = '1'
                          and not exists(select 1 from RPM_ORDER_HEADER where CALENDAR_ID = c.ID and IS_CONFIRMED = '1'))
           or ORDER_DATE > ':order_date')
        and DELIVERY_DATE != (select max(DELIVERY_DATE) from RPM_CALENDAR where DIAGRAM_ID = :diagram_id and TYPE != 'm')
        and DIAGRAM_ID = :diagram_id
        and TYPE != 'm' 
        and IS_ACTIVE = '1' 
        and not exists(select 1 from RPM_ORDER_HEADER where CALENDAR_ID = c.ID and IS_CONFIRMED = '1');

rpm_calendar_get_additional_data
Используется в assignTotalsToManualOrder и далее в addManualEvent выведенном в /api/rpm/add_manual_event. Извлекает список SKU/цен и объемов для заданных магазина и договора.

    select ssc.SKU_ID, ssc.PURCHASE_PRICE, p.WEIGHT
    from PRODUCTS p
    left join SKU_STORE_CONTRACT_V ssc on ssc.SKU_ID = p.SKU_ID
        and ssc.STORE_ID = :store_id 
        and ssc.CONTRACT_ID = :contract_id
    where p.SKU_ID [sku_id]

rpm_get_calendar_by_id
Используется в addManualEvent выведенном в /api/rpm/add_manual_event. Извлекает дату следующей доставки, договор, поставщика и склад по заданному ID события в календаре.

    select convert(varchar, c.NEXT_DELIVERY_DATE, 21) as NEXT_DELIVERY_DATE, 
        d.SPECIFICATION_ID, d.SUPPLIER_ID, d.WHS_ID
    from RPM_CALENDAR c
    inner join RPM_DIAGRAM d on d.ID = c.DIAGRAM_ID
    where c.ID = :calendar_id

rpm_max_calendar_id
Используется в addCustomEvent выведенном в /api/rpm/add_custom_event. Предназначен для служебных целей определения следующего ID события в календаре авто-инкрементом.

    select max(ID) as ID
    from (
        select max(ID) as ID from RPM_CALENDAR
        union all
        select max(ID) as ID from RPM_CALENDAR_HIST
    ) a

rpm_delete_calendars
Используется в classes\controllers\rpm\dbServices.js в deleteCalendars. Далее в classes\engine\rpm_units.js есть вызов calendarDbService.deleteCalendars в deletePickZeroCalendarsAndOrders, что вызывается в calcStoreOrders из batches\rpm_create_orders.js, т.е. используется только в фоновой обработке.

    delete c
    from RPM_DIAGRAM d
    inner join RPM_CALENDAR c on c.DIAGRAM_ID = d.ID
    where d.ID [diagram_id]
        and d.STORE_ID [store_id]
        and c.ORDER_DATE >= cast(getdate() as date)
        and c.TYPE '[type]'
        and not exists (
            select 1 from RPM_ORDER_HEADER with (nolock)
            where CALENDAR_ID = c.ID and IS_CONFIRMED = '1'
        )

Сейчас (ноябрь 2022) в calendar не используется.
rpm_adjust_delivery_by_sku
Назначен на /api/rpm/adjust_delivery_by_sku. Используется в orders, сейчас в calendar не используется.

rpm_get_cross_dock_store_orders_id
Используется в adjustDeliveryBySku назначенном /api/rpm/adjust_delivery_by_sku из classes\controllers\rpm\orders.js , перед вызовом rpm_adjust_delivery_by_sku.
Используется в orders, сейчас в calendar не используется.

rpm_order_stock_change_reasons
Назначен на /api/rpm/get_order_stock_change_reasons. Используется в public\javascripts\rpm_orders\main.js в calendar не используется.

rpm_change_order_stock
Назначен на /api/rpm/edit_order_stock и /api/rpm/edit_order_stock_and_volume. Используется в public\javascripts\rpm_orders\customStockInput.js и далее в public\javascripts\rpm_orders\main.js в calendar не используется.

rpm_set_cross_dock_optimization_if_any
Используется в classes\controllers\rpm\orders.js в setOrderVolume, что выведено в /api/rpm/edit_order_volume. Используется в public\javascripts\rpm_orders\main.js в calendar не используется.

rpm_change_order_volume
Используется в classes\controllers\rpm\orders.js в setOrderVolume, что выведено в /api/rpm/edit_order_volume. Используется в public\javascripts\rpm_orders\main.js в calendar не используется.

rpm_max_order_id

rpm_select_events

get_diagram_managers

rpm_get_event_details

rpm_adjust_delivery_by_sku

rpm_get_cross_dock_store_orders_id

rpm_get_details_for_manual_event

rpm_get_diagram_schedule

rpm_cancel_calendar_event

rpm_make_calendar_event_active_again

rpm_order_stock_change_reasons

rpm_change_order_stock

rpm_set_cross_dock_optimization_if_any

rpm_change_order_volume

rpm_get_suppliers_from_diagrams

rpm_get_diagrams_by_supplier

rpm_get_diagrams_by_contract

rpm_check_todays_calendar

rpm_get_max_calendar_dates

rpm_create_custom_event

rpm_calendar_get_additional_data

rpm_get_calendar_by_id

rpm_max_calendar_id

rpm_delete_calendars

Форма Новые магазины

rpm_get_new_stores

rpm_check_new_store

rpm_add_new_store

rpm_get_new_store

rpm_edit_new_store

rpm_delete_old_store

rpm_delete_new_store

Форма Спецификации (экспериментальная)

Вместо нее используется просто загружаемая таблица IF_BOM

rpm_get_products

rpm_edit_product_notes

rpm_edit_component_quantity

rpm_get_max_product_id

rpm_get_last_product_version

rpm_add_product

rpm_add_product_version

rpm_add_product_component

rpm_set_main_product

rpm_delete_product

rpm_delete_product_version

Форма Тендерные позиции

rpm_get_sku_tenders

rpm_get_supplier_emails

rpm_get_allowed_contracts

rpm_get_sku_suitable_contracts

rpm_set_order_contract

rpm_erase_sku_tender

rpm_delete_sku_tender

Форма Заказы

rpm_get_managers

rpm_select_orders_to_autoconfirm

rpm_change_order_confirm

rpm_get_order_by_id

rpm_get_cross_dock_orders_by_id

rpm_get_cross_dock_breakdown_by_organization

rpm_set_order_header_email_date

rpm_get_order_headers

rpm_orders

rpm_order_rows_excel_export

rpm_order_headers_excel_export

rpm_get_info_by_order_ids

rpm_get_orders_for_recalculation

rpm_get_full_header

rpm_get_order_tracking

rpm_get_full_order_line

rpm_update_order_line_custom_order

rpm_update_order_line_received

rpm_bulk_update_order_line_received

rpm_update_order_head_received

rpm_update_order_header_opt

rpm_update_order_line

rpm_bulk_update_order_head_received

rpm_cancel_order_line

rpm_update_adjusted_del_date

rpm_check_whs_cross_dock_and_stores_orders_equality

rpm_check_cross_dock_order_equality_by_sku

rpm_confirm_cross_dock_store_orders

rpm_record_email_error

rpm_get_manager_by_id

rpm_cancel_order_confirmation

rpm_check_orders_before_send

rpm_get_sub_product_hierarchy

rpm_get_sub_product_hierarchy_picking

rpm_get_just_diagram_by_id

rpm_bulk_confirm_orders

rpm_get_main_record_diagram_by_id

rpm_get_whs_picking_fcst_details

rpm_reset_order_received_date

rpm_check_if_any_crdock_store_order_confirmed

rpm_bulk_cancel_orders

rpm_reset_order_cancelation

rpm_get_lines_for_adjust_custom_order

rpm_update_single_order_line_by_sku_and_id

rpm_get_main_header_record_by_id

rpm_update_order_totals

rpm_update_order_headers_by_id

Форма Параметры позиций

http://localhost:3000/sku_store_params

Подробнее про функционал “Параметры позиций“ можно узнать тут.
Основная таблица этой формы RPM_SKU_STORE_PARAMS
Таблица заполняется из базы клиента автоматически или через импорт файла csv

IS_CROSS_DOCK, PICK_TO_ZERO, IS_MORNING - эти поля определяют, подтянет ли SKU из контракта диаграмма соответствующего типа.
Сама диаграмма в таблицу RPM_SKU_STORE_PARAMS изменения не вносит.

public\javascripts\rpm_sku_store_params\main.js
Фронтовой функционал собран в:
public\javascripts\rpm_sku_store_params\main.js
public\javascripts\rpm_sku_store_params\templates.js
Серверная часть в:
classes\controllers\rpm\skuStoreParams.js

rpm_get_sku_store_params_rows
Основной запрос страницы sku_store_params. Предназначен для извлечения данных отображаемых таблицей. Назначен на /api/rpm/sku_store_params_get_rows.
Фильтры SKU (сравнивается как с SKU_ID, так и на подстроку в PRODUCTS.ARTICLE_NAME или PRODUCTS.ITEM_CODE), магазин, договор, поставщик, менеджер и признаки sku-range и is-new.

    select top 100000
        ssp.SKU_ID, ssp.STORE_ID, ssp.PARCEL, ssp.CAPACITY, ssp.MIN_ORDER_QTY, 
        ssc.CONTRACT_ID, c.CONTRACT_NAME, sup.SUPPLIER_ID, sup.SUPPLIER_NAME, s.STORE_NAME, 
        p.ARTICLE_NAME, ssm.EXT_MANAGER_ID, convert(varchar, ssp.UPDATED, 121) as UPDATED, 
        ssp.UPDATED_BY, me1.NAME as UPDATED_BY_NAME, me.NAME as MANAGER_NAME, 
        p.ITEM_CODE, ls.QUANTITY as LATEST_STOCK, ib.SUB_SKU_ID, ib1.MASTER_SKU_ID,
        ssp.IS_ORDER, ssp.IS_PRODUCTION, ssp.IS_SHELF_LIMIT, p.SHELF_DAYS,
        (coalesce(pr.PRESENTATION_1, 0) + coalesce(pr.PRESENTATION_2, 0)) as PRESENTATION,
        (select sum(RAPI.QUANTITY)
        from RPM_ADD_PRESENTATION AS AP
        JOIN RPM_ADD_PRESENTATION_ITEMS RAPI ON RAPI.ID=AP.ID
        WHERE AP.IS_ACTIVE=1
        AND RAPI.SKU_ID = ssp.SKU_ID
        AND RAPI.STORE_ID = ssp.STORE_ID
        AND getdate() BETWEEN AP.START_DATE AND AP.END_DATE) as ADD_PRESENTATION_NUM,
        ass.SALES_VOLUME as AVG_SALES, l7ds.SALES_VOLUME LAST_SALES,
        (select max(d.ID) from RPM_DIAGRAM d where d.SPECIFICATION_ID=ssc.CONTRACT_ID 
               and d.STORE_ID=ssp.STORE_ID
               and d.PUSH_ID is null and d.END_DATE is null) DIAGRAM_ID,
        ssp.GUARANTEED_ORDER, ssp.IS_CROSS_DOCK, ssp.PICK_TO_ZERO, ssp.IS_MORNING,
        case when src.SKU_ID is not null then 1 else 0 end as AM, ssp.ADD_CYCLE,
        ssp.PLUS_D1D2FCST, ssp.ROUND_FACTOR, ssp.WRITEOFF_LIMIT,
        ssp.SHELF_LIFE_PERC, ssp.MAX_INCREASE_PERC,
        case when fm.model like '%group_new%' then 1
             when fm.model like '%reg_alloc%' then 2
             else 0 end IS_NEW
    from RPM_SKU_STORE_PARAMS ssp with (nolock)
    inner join PRODUCTS p on ssp.SKU_ID = p.SKU_ID 
          and (upper(p.ARTICLE_NAME) like '%:sku_name%' or upper(p.ITEM_CODE)
             like '%:sku_name%')
    inner join STORES s on s.STORE_ID = ssp.STORE_ID
    left join SKU_STORE_CONTRACT_V ssc on ssc.SKU_ID = ssp.SKU_ID
          and ssc.STORE_ID = ssp.STORE_ID
    left join CONTRACTS c on c.CONTRACT_ID = ssc.CONTRACT_ID
    left join SUPPLIERS sup on sup.SUPPLIER_ID = c.SUPPLIER_ID
    left join SKU_STORE_MANAGER ssm on ssm.SKU_ID = ssp.SKU_ID 
          and ssm.STORE_ID = ssp.STORE_ID
    left join MANAGER_EXT me on me.ID = ssm.EXT_MANAGER_ID
    left join MANAGER_EXT me1 on me1.ID = ssp.UPDATED_BY
    left join LATEST_STOCK ls on ls.SKU_ID = ssp.SKU_ID and ls.STORE_ID = ssp.STORE_ID
    left join FCST_SKU_MEAS fm on ssp.SKU_ID=fm.SKU_ID and ssp.STORE_ID=fm.STORE_ID
               and fm.ID=(select max(id) from fcst where loaded is not null)
    left join RPM_PRESENTATION pr on pr.SKU_ID = ssp.SKU_ID and pr.STORE_ID = ssp.STORE_ID
    left join AVG_SALES_SKU ass on ass.SKU_ID = ssp.SKU_ID and ass.STORE_ID = ssp.STORE_ID
    left join (select distinct SUB_SKU_ID from IF_BOM) ib on ib.SUB_SKU_ID = ssp.SKU_ID
    left join (select distinct MASTER_SKU_ID from IF_BOM) ib1 
          on ib1.MASTER_SKU_ID = ssp.SKU_ID
    left join LAST_DAYS_SALES l7ds on l7ds.SKU_ID = ssp.SKU_ID 
          and l7ds.STORE_ID = ssp.STORE_ID
    left join SKU_RANGE_CURRENT src on src.SKU_ID = ssp.SKU_ID 
          and src.STORE_ID = ssp.STORE_ID
    where ssp.STORE_ID [store]
      and ssp.SKU_ID [skus]
      and (:manager = -999 or ssm.EXT_MANAGER_ID = :manager)
      and (c.SUPPLIER_ID [suppliers] or -10 [suppliers])
      and (c.CONTRACT_ID like ':contract' or upper(c.CONTRACT_NAME) 
          like ':contract' or ':contract' = '%')
      and (:is_in_range in (-999, 0, 2) or src.SKU_ID is not null)
      and (:is_in_range in (-999, 1, 2) or src.SKU_ID is null)
      and (:is_new = -999
           or (:is_new = 0 and fm.model not like '%group_new%' and fm.model 
              not like '%reg_alloc%')
           or (:is_new = 1 and fm.model like '%group_new%')
           or (:is_new = 2 and fm.model like '%reg_alloc%') )
      and (:is_in_range in (-999, 0, 1)
           or (src.SKU_ID is not null
               and not exists (select 1 from rpm_orders_v o
                   where o.order_date >= cast(getdate() as date) 
               and o.sku_id=ssp.SKU_ID)))

rpm_get_sku_store_params_by_key
Предназначен для извлечения из RPM_SKU_STORE_PARAMS признака PICK_TO_ZERO по заданным SKU и магазину.
Используется в classes\controllers\rpm\dbServices.js и далее в getPickingFcstDetails из classes\controllers\rpm\orders.js, что выведено в /api/rpm/get_picking_fcst_details , а сам запрос вызывается из orders.

    select PICK_TO_ZERO
    from RPM_SKU_STORE_PARAMS where sku_id=:sku_id and store_id=:store_id;

rpm_get_sku_store_params_by_pairs
Предназначен для извлечения из RPM_SKU_STORE_PARAMS минимального заказа, кратности и признака sku-range по заданным SKU и магазину.
Используется в checkSkuStoreParamsByPairs из classes\controllers\rpm\push\index.js , что выведено в /api/rpm/push_check_sku_store_params_by_pairs, а сам запрос вызывается из http://localhost:3000/rpm_push

    select SKU_ID, MIN_ORDER_QTY, PARCEL,
        (case
            when exists (select 1 from SKU_RANGE
                where STORE_ID = :store_id and SKU_ID = ssp.SKU_ID
                    and START_DATE <= cast(getdate() as date)
                    and (END_DATE >= cast(getdate() as date) or END_DATE is null))
            then 1 else 0
            end) as IS_IN_RANGE
    from RPM_SKU_STORE_PARAMS ssp where SKU_ID [skus] and STORE_ID=:store_id

rpm_sku_store_params_get_init_data


Предназначен для извлечения списка менеджеров, наполняющего выпадающий список фильтра. Используется в getInitialData из classes\controllers\rpm\skuStoreParams.js и выведен в /api/rpm/sku_params_get_initial_data.

    select ID, NAME from MANAGER_EXT

rpm_sku_store_params_get_contracts
Предназначен для извлечения списка договоров, наполняющего выпадающий список фильтра. Используется в getInitialData из classes\controllers\rpm\skuStoreParams.js и выведен в /api/rpm/sku_params_get_initial_data.

   select CONTRACT_ID ID, CONTRACT_NAME NAME from CONTRACTS;

rpm_get_check_order
По заданному набору SKU и магазинов из вью SKU_STORE_CONTRACT_V извлекает договора, поставщиков и различные признаки для проверки возможности заказа.
Используется в checkPossibilityToOrder из classes\controllers\rpm\skuStoreParams.js и выведен в /api/rpm/sku_store_params/check_order_possibility.
Это ключевой запрос модального окна "Проверка возможности заказа".

    select st.STORE_ID,st.STORE_NAME,
           p.SKU_ID, case when p.ITEM_CODE is null then p.ARTICLE_NAME 
           else concat('(', cast(p.ITEM_CODE as varchar), ') ', p.ARTICLE_NAME) end
           as ARTICLE_NAME,
        (case when
            exists(
                select 1 from SKU_RANGE
                where STORE_ID = st.STORE_ID and SKU_ID = p.SKU_ID
                    and START_DATE <= cast(getdate() as date)
                    and (END_DATE >= cast(getdate() as date) or END_DATE is null)
                )
        then 1 else 0 end) as IS_AM,
        ssc.CONTRACT_ID,
        ssc.PACKAGE_CONTENT,
        ssc.IS_ORDER,
        c.CONTRACT_NAME,
        s.SUPPLIER_ID,
        s.SUPPLIER_NAME
    from STORES st
    join PRODUCTS p on p.SKU_ID [skus]
      or p.ITEM_CODE '[item_codes]'
    left join SKU_STORE_CONTRACT_V ssc on ssc.SKU_ID = p.SKU_ID
        and ssc.STORE_ID = st.STORE_ID
    left join CONTRACTS c on c.CONTRACT_ID = ssc.CONTRACT_ID
    left join SUPPLIERS s on c.SUPPLIER_ID = s.SUPPLIER_ID
    where st.STORE_ID [stores]

rpm_get_diagram_and_cal_by_skus
По заданному набору SKU и магазинов извлекает диаграммы для проверки возможности заказа.
Используется в checkPossibilityToOrder из classes\controllers\rpm\skuStoreParams.js и выведен в /api/rpm/sku_store_params/check_order_possibility.
Это ключевой запрос модального окна "Проверка возможности заказа".

    select d.ID as DIAGRAM_ID, coalesce(di.SKU_ID, 
        ssc.SKU_ID, ssc2.SKU_ID) as SKU_ID, d.STORE_ID,
        (select convert(varchar, min(ORDER_DATE), 121) from RPM_CALENDAR
         where DIAGRAM_ID = d.ID and IS_ACTIVE='1' and ORDER_DATE >= cast(getdate() as date)
        ) as CLOSEST_ORDER
    from RPM_DIAGRAM d
    left join RPM_DIAGRAM_ITEMS di on d.ID = di.DIAGRAM_ID
        and d.ALL_SKUS = '0'
    left join SKU_STORE_CONTRACT_V ssc on d.SPECIFICATION_ID = ssc.CONTRACT_ID
        and d.STORE_ID = ssc.STORE_ID
        and d.ALL_SKUS = '1'
        and coalesce(d.WAREHOUSE_TYPE, '0') != 'c'
    left join SKU_STORE_CONTRACT_V ssc2 on d.SPECIFICATION_ID = ssc2.CONTRACT_ID
        and d.STORE_ID = ssc2.STORE_ID
        and d.ALL_SKUS = '1'
        and d.WAREHOUSE_TYPE = 'c'
        and ssc2.IS_CROSSDOCK = 1
    join products p on coalesce(di.SKU_ID, ssc.SKU_ID, ssc2.SKU_ID) = p.SKU_ID
    where (coalesce(di.SKU_ID, ssc.SKU_ID, ssc2.SKU_ID) [skus]
           or p.ITEM_CODE '[item_codes]')
        and d.STORE_ID [stores]
        and d.START_DATE <= cast(getdate() as date)
        and (d.END_DATE >= cast(getdate() as date) or d.END_DATE is null)

rpm_check_sku_store_pairs_existence
Проверяет существование SKU и магазинов в таблице RPM_SKU_STORE_PARAMS. Используется в filterNonExistentPairs и далее importFromFile из classes\controllers\rpm\skuStoreParams.js
назначенном в /api/rpm/sku_store_params/import_items. Используется при импорте из csv.

    select ssp.SKU_ID, ssp.STORE_ID
    from RPM_SKU_STORE_PARAMS ssp
    where ssp.SKU_ID [skus] and ssp.STORE_ID [stores]

rpm_update_item_params_record
Предназначен для обновления полей таблицы RPM_SKU_STORE_PARAMS для заданных SKU и магазина. Используется в updateParamsBySkuIdStoreId из classes\controllers\rpm\dbServices.js и далее в importFromFile, updateRecordIntoDb и bulkUpdateRecordsIntoDb выведенных соответственно в /api/rpm/sku_store_params/import_items , /api/rpm/sku_store_params/update_record и /api/rpm/sku_store_params/bulk_update_record.

    update ssp
    set PARCEL = :parcel, MIN_ORDER_QTY = :min_order_qty, UPDATED = getdate(),
        UPDATED_BY = :user_id, IS_ORDER = :is_order, IS_PRODUCTION = :is_production,
        IS_SHELF_LIMIT = :is_shelf_limit, GUARANTEED_ORDER = :guar_order,
        IS_CROSS_DOCK = :is_cross_dock, PICK_TO_ZERO = :pick_to_zero,
        IS_MORNING = :is_morning, ADD_CYCLE = :add_cycle, PLUS_D1D2FCST = :plus_d1d2_fcst,
        ROUND_FACTOR = :round_factor, WRITEOFF_LIMIT = :writeoff_limit,
                       SHELF_LIFE_PERC = :shelf_life_perc,
        MAX_INCREASE_PERC = :max_increase_perc, CAPACITY = :capacity
    from RPM_SKU_STORE_PARAMS ssp
    where ssp.SKU_ID = :sku_id and ssp.STORE_ID = :store_id

rpm_sku_store_params_import
Предназначен для вставки записи в таблицу RPM_SKU_STORE_PARAMS. Используется в updateParamsBySkuIdStoreId из classes\controllers\rpm\dbServices.js и далее в importFromFile, updateRecordIntoDb и bulkUpdateRecordsIntoDb выведенных соответственно в /api/rpm/sku_store_params/import_items , /api/rpm/sku_store_params/update_record и /api/rpm/sku_store_params/bulk_update_record.

    merge into RPM_SKU_STORE_PARAMS ssp
    using (select :sku_id SKU_ID, :store_id STORE_ID) src
        on (ssp.SKU_ID = src.SKU_ID and ssp.STORE_ID = src.STORE_ID)
    when matched then
        update set PARCEL = :parcel, MIN_ORDER_QTY = :min_order_qty, UPDATED = getdate(),
        UPDATED_BY = :user_id, IS_ORDER = :is_order, IS_PRODUCTION = :is_production,
        IS_SHELF_LIMIT = :is_shelf_limit, GUARANTEED_ORDER = :guar_order,
        IS_CROSS_DOCK = :is_cross_dock, PICK_TO_ZERO = :pick_to_zero,
        IS_MORNING = :is_morning,
        ADD_CYCLE = :add_cycle, PLUS_D1D2FCST = :plus_d1d2_fcst,
        ROUND_FACTOR = :round_factor,
        WRITEOFF_LIMIT = :writeoff_limit, SHELF_LIFE_PERC = :shelf_life_perc,
        MAX_INCREASE_PERC = :max_increase_perc, CAPACITY = :capacity
    when not matched then
        insert (
            SKU_ID, STORE_ID, PARCEL, MIN_ORDER_QTY, UPDATED, UPDATED_BY,
            IS_ORDER, IS_PRODUCTION, IS_SHELF_LIMIT, GUARANTEED_ORDER, IS_CROSS_DOCK,
            PICK_TO_ZERO, IS_MORNING, ADD_CYCLE, PLUS_D1D2FCST, 
            ROUND_FACTOR, WRITEOFF_LIMIT,
            SHELF_LIFE_PERC, MAX_INCREASE_PERC, CAPACITY
            )
        values (
            :sku_id, :store_id, :parcel, :min_order_qty, getdate(), :user_id,
            :is_order, :is_production, :is_shelf_limit, :guar_order, :is_cross_dock,
            :pick_to_zero, :is_morning, :add_cycle, :plus_d1d2_fcst, :round_factor,
            :writeoff_limit, :shelf_life_perc, :max_increase_perc, :capacity
            );

Сейчас (ноябрь 2022) не используется:

rpm_sku_store_params_update_is_order
Предназначен для обновления поля IS_ORDER таблицы RPM_SKU_STORE_PARAMS для заданных SKU и магазина. Сейчас не используется.

rpm_sku_store_params_update_is_production
Предназначен для обновления поля IS_PRODUCTION таблицы RPM_SKU_STORE_PARAMS для заданных SKU и магазина. Сейчас не используется.

rpm_sku_store_params_update_is_shelf_limit
Предназначен для обновления поля IS_SHELF_LIMIT таблицы RPM_SKU_STORE_PARAMS для заданных SKU и магазина. Сейчас не используется.

Форма Дополнительная загрузка

rpm_get_promo_for_add_load

rpm_get_promo_stores

rpm_get_promo_skus

rpm_create_add_load

rpm_get_max_add_load_id

rpm_add_load_get_rows

rpm_delete_add_load

rpm_get_load_id_details

rpm_check_add_load_intersections

Форму Пуш распределение

rpm_push_get_stores

rpm_push_get_skus

rpm_push_get_sku_by_items

rpm_push_get_sku_by_eans

rpm_push_get_contract_by_stores_skus

rpm_push_get_store_sku_pairs

rpm_push_get_existing_diagrams

rpm_get_suppliers_by_contract

rpm_push_get_existing_diagrams_broad_params

rpm_push_get_forecasts_for_calc_distribution

rpm_push_get_max_push_id

rpm_create_push

rpm_get_closest_next_delivery_days_by_diagrams

rpm_get_managers_by_sku_store

rpm_get_purchase_prices_by_sku_store

rpm_get_all_push

rpm_push_get_whs_cross_dock_params

rpm_push_find_closest_delieveries

Форма Дополнительные места

http://localhost:3000/rpm_add_presentation
Эта функциональность завязана на две таблицы:
RPM_ADD_PRESENTATION - заголовки дополнительных мест
RPM_ADD_PRESENTATION_ITEMS - распределения дополнительных мест

rpm_add_presentation_get_table_rows

Основной запрос страницы rpm_add_presentation. Предназначен для извлечения данных отображаемых таблицей. Назначен на /api/rpm/add_presentation_get_rows.
Фильтры дата, название и SKU (сравнивается как с SKU_ID, так и на подстроку в PRODUCTS.ARTICLE_NAME).

  SELECT
        AP.ID, AP.NAME,
        (select count(*) from RPM_ADD_PRESENTATION_ITEMS where ID = AP.ID) as QTY_RECORDS,
        AP.ALL_STORES,
        convert(varchar, AP.START_DATE, 21) as START_DATE,
        convert(varchar, AP.END_DATE, 21) as END_DATE,
        convert(varchar, AP.UPDATE_DATE, 21) as UPDATE_DATE,
        AP.UPDATED_BY, MANAGER.NAME AS MANAGER,
        AP.PROMO_ID, PH.NAME as PROMO_NAME
    FROM RPM_ADD_PRESENTATION as AP
    LEFT JOIN PROMO_HEADER AS PH on AP.PROMO_ID = PH.ID
    LEFT JOIN MANAGER on MANAGER.ID = AP.UPDATED_BY
    WHERE 
        AP.END_DATE >= ':date'
        AND AP.NAME like ':name'
        AND AP.IS_ACTIVE = 1
        and exists (select ID
            from RPM_ADD_PRESENTATION_ITEMS as API
            left join PRODUCTS on PRODUCTS.SKU_ID = API.SKU_ID
            where AP.ID = API.ID
            and (API.SKU_ID like ':sku' or PRODUCTS.ARTICLE_NAME like ':sku'));

rpm_add_presentation_get_promo

Назначен на /api/rpm/add_presentation_get_promo. Используется для наполнения выпадающего списка выбора "Промо" в модальном окне заведения новых дополнительных мест.
В качестве фильтра текущая дата (выбирается в левом верхнем углу страницы), должна быть меньше либо равна дате завершения "Промо"

    SELECT ID, NAME,
    convert(varchar, PH.START_DATE, 121) as START_DATE,
    convert(varchar, PH.END_DATE, 121) as END_DATE
    FROM PROMO_HEADER PH
    WHERE END_DATE >= ':start_date'

rpm_add_presentation_get_promo_stores
Назначен на /api/rpm/add_presentation_get_promo_stores. Используется для наполнения выпадающего списка выбора магазинов, в модальном окне заведения новых дополнительных мест, с учетом выбранного "Промо". Фильтр, выбранный ID Промо.

    select STORE_ID as ID, (select STORE_NAME from STORES where STORES.STORE_ID = ps.STORE_ID) as NAME
    from PROMO_STORES as ps
    where ID = :promo_id

rpm_add_presentation_get_promo_skus
Назначен на /api/rpm/add_presentation_get_promo_skus. Используется для наполнения выпадающего списка выбора SKU, в модальном окне заведения новых дополнительных мест, с учетом выбранного "Промо". Фильтр, выбранный ID Промо.

    SELECT SKU_ID as ID, 
          (SELECT ARTICLE_NAME FROM PRODUCTS WHERE PRODUCTS.SKU_ID = ps.SKU_ID) as NAME
    from PROMO_SKU as ps
    where ID = :promo_id

rpm_add_presentation_get_sku_store_pairs
Назначен на /api/rpm/add_presentation_get_sku_store_pairs. Предназначен для извлечения объемов дополнительных мест по заданным массивам SKU и магазинов.

    SELECT P.SKU_ID,
    case when P.ITEM_CODE is null 
         then P.ARTICLE_NAME 
         else '(' + cast(P.ITEM_CODE as varchar) + ') ' 
              + P.ARTICLE_NAME end as ARTICLE_NAME,
    S.STORE_ID, S.STORE_NAME,
    (select API.QUANTITY
        from RPM_ADD_PRESENTATION_ITEMS as API
        where P.SKU_ID = API.SKU_ID
        and S.STORE_ID = API.STORE_ID
        and API.ID = ':max_id')
        as QTY
    FROM PRODUCTS as P
    CROSS JOIN STORES as S
    WHERE P.SKU_ID [skus] and S.STORE_ID [stores]

rpm_add_presentation_max_id
В http запрос не выведен. Предназначен для служебных целей определения следующего ID дополнительных мест авто-инкрементом.

SELECT MAX(ID) AS MAXID from RPM_ADD_PRESENTATION

rpm_add_presentation_create

Назначен на /api/rpm/add_presentation_create. Предназначен для сохранения заголовка дополнительных мест.

    DELETE FROM RPM_ADD_PRESENTATION_ITEMS WHERE ID = :max_id;
    
    MERGE INTO RPM_ADD_PRESENTATION dest
    USING (SELECT :max_id as ID) src
    ON (dest.ID = src.ID)
    WHEN MATCHED THEN 
        UPDATE SET NAME = ':name', START_DATE = ':startDate', END_DATE = ':endDate',
        PROMO_ID = :selectedPromo, UPDATE_DATE = getdate(), UPDATED_BY = :user, 
        ALL_STORES = :isAllStores
    WHEN NOT MATCHED THEN 
        INSERT(ID, NAME, START_DATE, END_DATE, PROMO_ID, 
                UPDATE_DATE, UPDATED_BY, ALL_STORES, IS_ACTIVE)
        VALUES(:max_id, ':name', ':startDate', ':endDate', :selectedPromo, 
                getdate(), :user, :isAllStores, 1);

rpm_add_presentation_delete

Назначен на /api/rpm/add_presentation_delete. Предназначен для удаления дополнительных мест, установкой признака IS_ACTIVE в 0.

    UPDATE RPM_ADD_PRESENTATION
    set IS_ACTIVE = 0, UPDATED_BY = :user, UPDATE_DATE = getdate()
    where ID = :id

rpm_add_presentation_get_by_id

Назначен на /api/rpm/add_presentation_load_by_id. Предназначен для извлечения заголовка дополнительных мест и списков ID SKU и магазинов, разделенных запятыми.
Используется в модальном окне редактирования.

  SELECT
        AP.ID, AP.NAME, AP.ALL_STORES,
        convert(varchar, AP.START_DATE, 21) as START_DATE,
        convert(varchar, AP.END_DATE, 21) as END_DATE,
        stuff(
            (select ',' + convert(varchar, SKU_ID)
            from RPM_ADD_PRESENTATION_ITEMS AS API
            where API.ID = :id
            for xml path('')), 1, 1, '') as SKUS,
        stuff(
            (select ',' + convert(varchar, STORE_ID)
            from RPM_ADD_PRESENTATION_ITEMS AS API
            where API.ID = :id
            for xml path('')), 1, 1, '') as STORES,
        AP.UPDATED_BY, AP.PROMO_ID
    FROM RPM_ADD_PRESENTATION as AP
    WHERE AP.IS_ACTIVE = 1 AND AP.ID = :id

add_presentation_check_sku_promo

Назначен на /api/rpm/add_presentation_check_sku_list. Используется для доопределения SKU_ID по заданным EAN или ITEM_CODE при импорте из csv.
Также используется в rpm_push при импорте.

    SELECT
        distinct PS.ID
    FROM PROMO_STORES PS
    JOIN PROMO_SKU_APPROVED PSA ON PSA.ID=PS.ID
    JOIN PROMO_HEADER PH ON PH.ID=PS.ID
    AND (:store_id = -1 OR PS.STORE_ID = :store_id)
    AND (:sku_id = -1 OR PSA.SKU_ID = :sku_id)
    AND (:promo_id = -1 OR PS.ID = :promo_id)
    AND (:promo_id > -1 OR PH.START_DATE BETWEEN ':startDate' AND ':endDate'
        OR PH.END_DATE BETWEEN ':startDate' AND ':endDate'
        OR ':startDate' BETWEEN PH.START_DATE AND PH.END_DATE
        OR ':endDate' BETWEEN PH.START_DATE AND PH.END_DATE)

rpm_add_presentation_check_unique_store_sku_dates

Назначен на /api/rpm/check_unique_store_sku_dates_for_presentation.
Выполняет проверку выбранных списков SKU/магазинов на пересечение с другими дополнительными местами.
Заводить пересекающиеся дополнительные места функционал позволяет, но отмечает предупреждение розовым цветом.

    SELECT AP.NAME,
        RAPI.ID,RAPI.SKU_ID,RAPI.STORE_ID,
        convert(varchar, AP.START_DATE, 21) as START_DATE,
        convert(varchar, AP.END_DATE, 21) as END_DATE
    FROM RPM_ADD_PRESENTATION AS AP
    JOIN RPM_ADD_PRESENTATION_ITEMS RAPI ON RAPI.ID=AP.ID
    WHERE AP.IS_ACTIVE=1
    AND AP.ID <> :id
    AND RAPI.SKU_ID = :sku_id
    AND RAPI.STORE_ID [store_list]
    AND (AP.START_DATE BETWEEN ':startDate' AND ':endDate'
    OR AP.END_DATE BETWEEN ':startDate' AND ':endDate'
    OR ':startDate' BETWEEN AP.START_DATE AND AP.END_DATE
    OR ':endDate' BETWEEN AP.START_DATE AND AP.END_DATE)

Форма Перемещения

get_stores_with_overstock

get_skus_with_overstock_by_store

get_stores_for_sku_transfer

get_store_to_store_skus

get_store_to_supplier_skus

get_store_transfers

get_store_transfer_lines

get_max_store_transfers_id

update_store_transfer_record

update_store_transfer_line

delete_store_transfer_record

delete_store_transfer_line

get_sku_nearest_promo_in_store

Батчи

Батч расчета заказов

Батч расчета заказов - config/[customer]/sql_[customer]_batches.ini
Индивидуален для каждого клиента

Предварительные операции с таблицами перед началом расчета заказов

[rpm_pre_calc_orders_batch]
Выполняет предварительные операции с таблицами перед началом расчета заказов, а именно:

- синхронизирует цены в products.last_purchase_price и sku_store_contract.last_purchase_price,
где last_purchase_price - последняя актуальная цена товарной позиции


- обновляет в RPM_SKU_STORE_PARAMS записи на основе SKU_STORE_CONTRACT
где SKU_STORE_CONTRACT - таблица, которая заполняется клиентом, откуда берутся привязки SKU к актуальным контрактам.
RPM_SKU_STORE_PARAMS - это внутренняя таблица для расчетов автозаказа


- выставляет round_factor = 0,5 для записей, где он не указан явно, в таблице RPM_SKU_STORE_PARAMS


- в таблице RPM_SKU_STORE_PARAMS выставляет поле is_order на основе sku_range_current, rpm_presentation, SKU_WHS_DISABLED_ORDERS и др.
поле is_order определяет можно ли по паре SKU-STORE делать заказ. Значение 1 - можно, 0 - нельзя.


- обновляет manual_orders на основе manual_order_close, manual_order_receivings. manual_orders таблица ручных заказов, которая обновляется на основании закрытых, уже не актуальных ручных заказов manual_order_close и таблицы приходов по ручным заказам manual_order_receivings. Когда по заказу есть приход, заказ становится не актуальным. Так же заказ может становится не актуальным по дате close_date. Поле order_number во всех эти таблицах является связующим полем.


- автоматически закрывает manual_orders, если дата заказа устарела и где релевантно учитывает RPM_TRANSFERS (внутренее перемещение между магазинами). По состоянию на ноябрь 2022 таблица RPM_TRANSFERS практически никем не используется.


- обновляет received_qty в rpm_order_line на основе RPM_RECEIVINGS и где релевантно RPM_TRANSFERS
где rpm_order_line - таблица со строками автозаказов (табличная часть заказа, в вебинтерфейсе “строки“), а RPM_RECEIVINGS таблица приходов которые формируются согласно заказам.


- может автоматически выставлять в 0 received_qty в rpm_order_line для устаревших заказов.

- может автоматически закрывать устаревшие заказы

Т.к. расчет заказов у каждого ретейлера осуществляется по индивидуальному алгоритму, то и выставление 0 в received_qty может происходить при разных условиях. Например одни считают, что если на магазин пришла только часть заказа, то надо закрывать весь заказ, обозначая отсутствующие позиции нулями. А вот другие считают, что заказ может ехать частями, и должен закрываться только когда доедут все позиции или он устареет, не сбрасывая в 0 полученное количество.


- закрывает заказ (поле received_date в rpm_order_header) на основе RPM_RECEIVINGS и rpm_order_close

где RPM_ORDER_ADJUSTMENTS делают ручные корректировки автоматически сгенерированых заказов, а RPM_RECEIVINGS -


- обновляет количество товара в заказе adjusted_delivery на основе RPM_ORDER_ADJUSTMENTS


- обновляет дату поставки adjusted_delivery_date на основе rpm_order_delay

- может иметь специальные условия для заказов на склад

  • No labels