gifts2017

Получение данных для партионного списания запросом

Опубликовал Павел Чистов (GROOVY) в раздел Программирование - Практика программирования

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

Исходная конфигурация

Конфигурация примитивная. два документа с классическим составом и регистр накопления остатков. Партия в регистре - это ссылка на документ “ПриходнаяНакладная”. Остальное, надеюсь, очевидно.

В тестовой конфигурации были проведены “Приходные”, для формирования остатков по партиям.

Примечание

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

Да - нет контроля остатков.

Да - только метод FIFO. Если есть вопрос как реализовать это методом LIFO - то повторное прочтение статьи Вам вряд ли поможет, как собственно и сама статья - вряд ли будет для Вас полезной.

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

Поехали

Я буду очень подробно показывать получение данных. Прямо по шагам.

Получаем данные документа который проводится

ВЫБРАТЬ
   Товар КАК Товар,
   СУММА(Количество) КАК Количество
ПОМЕСТИТЬ ДокТЧ
ИЗ
   Документ.РасходнаяНакладная.Товары
ГДЕ
   Ссылка = &Ссылка

СГРУППИРОВАТЬ ПО
   Товар
ИНДЕКСИРОВАТЬ ПО
   Товар

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

Получим остатки партий

Далее выберем остатки из регистра с отбором по товарам из таблицы документа.

ВЫБРАТЬ
   Товар,
   Партия,
   Партия.МоментВремени КАК МоментВремени,
   КоличествоОстаток,
   СтоимостьОстаток
ПОМЕСТИТЬ Остатки
ИЗ
   РегистрНакопления.ПартииТоваров.Остатки(
           ,
           Товар В
               (ВЫБРАТЬ
                   ДокТЧ.Товар
               ИЗ
                   ДокТЧ КАК ДокТЧ))

ИНДЕКСИРОВАТЬ ПО
   Товар

Итого получили 2 временные таблицы. Соединяя таблицу “Остатки” саму с собой можем получить накопительный итог по партиям.

Соединяем таблицы

ВЫБРАТЬ
   *
ИЗ
   ДокТЧ КАК ДокТЧ
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т1
       ПО ДокТЧ.Товар = Т1.Товар
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т2
       ПО Т1.Товар = Т2.Товар И Т1.МоментВремени > Т2.МоментВремени

В итоге получаем таблицу вида:

В таблице из ДокТЧ мы узнаем сколько списать товаров надо.

В Т1 количество остатка по конкретной партии.

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

Выберем только нужные поля:

ВЫБРАТЬ
   ДокТЧ.Товар,
   ДокТЧ.Количество КАК КоличествоДокумента,
   Т1.Партия,
   Т1.КоличествоОстаток КАК КоличествоПартии,
   ISNULL(Т2.КоличествоОстаток,0) КАК НакопительныйИтог
ИЗ
   ДокТЧ КАК ДокТЧ
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т1
       ПО ДокТЧ.Товар = Т1.Товар
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т2
       ПО Т1.Товар = Т2.Товар И Т1.МоментВремени > Т2.МоментВремени

При необходимости остаток по стоимости можно получить потом, а можно и в этой же выборке.

Для наглядности поместим все во временную таблицу “Данные” и следующим запросом выберем и сгруппируем данные из нее.

Получаем данные о том, сколько списать нужно с конкретной партии

ВЫБРАТЬ
   Товар,
   Партия,
   МАКСИМУМ(КоличествоДокумента) КАК КоличествоДокумента,
   МАКСИМУМ(КоличествоПартии) КАК КоличествоПартии,
   СУММА(НакопительныйИтог) КАК НакопительныйИтог
ИЗ
   Данные КАК Данные
СГРУППИРОВАТЬ ПО Товар, Партия 

Данные теперь сгруппированы, товары и партии уникальны.

И опять поместим результат во временную таблицу “Данные2” и очередным запросом рассчитаем сколько необходимо списать с конкретной партии:

ВЫБРАТЬ
   *,
   КоличествоДокумента - НакопительныйИтог КАК ОсталосьСписать
ИЗ
   Данные2 КАК Данные

И последняя  итерация: получим в условии сколько нужно списать с конкретной партии (ага, опять с временной таблицей):

ВЫБРАТЬ
   *,
   ВЫБОР КОГДА ОсталосьСписать < КоличествоПартии ТОГДА ОсталосьСписать ИНАЧЕ КоличествоПартии КОНЕЦ КАК Списать
ИЗ
   Данные3 КАК Данные
ГДЕ
   НакопительныйИтог < КоличествоДокумента

Дополнительное условие уберет “лишние” партии, списывать которые не нужно.

Осталось убрать столбцы, которые нам не нужны и получим таблицу для партионного списания.

ВЫБРАТЬ
   Товар КАК Товар,
   СУММА(Количество) КАК Количество
ПОМЕСТИТЬ ДокТЧ
ИЗ
   Документ.РасходнаяНакладная.Товары
ГДЕ
   Ссылка = &Ссылка

СГРУППИРОВАТЬ ПО
   Товар
ИНДЕКСИРОВАТЬ ПО
   Товар
;


////////////////////////////////////////////////////////////////////////////////

ВЫБРАТЬ
   Товар КАК Товар,
   Партия,
   Партия.МоментВремени КАК МоментВремени,
   КоличествоОстаток,
   СтоимостьОстаток
ПОМЕСТИТЬ Остатки
ИЗ
   РегистрНакопления.ПартииТоваров.Остатки(
           ,
           Товар В
               (ВЫБРАТЬ
                   ДокТЧ.Товар
               ИЗ
                   ДокТЧ КАК ДокТЧ)) КАК ПартииТоваровОстатки

ИНДЕКСИРОВАТЬ ПО
   Товар
;
ВЫБРАТЬ
   *
ИЗ
   ДокТЧ КАК ДокТЧ
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т1
       ПО ДокТЧ.Товар = Т1.Товар
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т2
       ПО Т1.Товар = Т2.Товар И Т1.МоментВремени > Т2.МоментВремени
;

ВЫБРАТЬ
   ДокТЧ.Товар,
   ДокТЧ.Количество КАК КоличествоДокумента,
   Т1.Партия,
   Т1.КоличествоОстаток КАК КоличествоПартии,
   ISNULL(Т2.КоличествоОстаток,0) КАК НакопительныйИтог
ПОМЕСТИТЬ Данные
ИЗ
   ДокТЧ КАК ДокТЧ
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т1
       ПО ДокТЧ.Товар = Т1.Товар
   ЛЕВОЕ СОЕДИНЕНИЕ
       Остатки КАК Т2
       ПО Т1.Товар = Т2.Товар И Т1.МоментВремени > Т2.МоментВремени
;


ВЫБРАТЬ
   Товар,
   Партия,
   МАКСИМУМ(КоличествоДокумента) КАК КоличествоДокумента,
   МАКСИМУМ(КоличествоПартии) КАК КоличествоПартии,
   СУММА(НакопительныйИтог) КАК НакопительныйИтог
ПОМЕСТИТЬ Данные2
ИЗ
   Данные КАК Данные
СГРУППИРОВАТЬ ПО Товар, Партия
;

ВЫБРАТЬ
   *,
   КоличествоДокумента - НакопительныйИтог КАК ОсталосьСписать
ПОМЕСТИТЬ Данные3
ИЗ
   Данные2 КАК Данные
;

ВЫБРАТЬ
   Товар, Партия,
   ВЫБОР КОГДА ОсталосьСписать < КоличествоПартии ТОГДА ОсталосьСписать ИНАЧЕ КоличествоПартии КОНЕЦ КАК Списать

ИЗ
   Данные3 КАК Данные
ГДЕ
   НакопительныйИтог < КоличествоДокумента

Вот и все.

В приведенном примере, естественно, мы не сможем продать ложки, их мало, нужно 100, и нож не продадим, его вообще в остатках нет. Но это отдельная история…

Оригинал статьи на моем сайте.

С уважением, Павел Чистов.

pbt.jpg

Крупнейшая региональная сеть среди 1С:Франчайзи

// //

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Саня Гончар (Pervuy) 20.03.14 13:43
Хорошая статья!
Хотелось бы конечно увидеть контроль остатков, если делать списание таким методом.
2. Павел Чистов (GROOVY) 20.03.14 13:57
(1) Pervuy, контроль остатков можно сделать соединив первые 2 таблицы и получив итоги без учета партий. Там все элементарно.
Или сгруппировав вот этот результат

Чтойта картинки в комменты не вставляются.
agrustny; Pervuy; +2 Ответить 1
3. Саня Гончар (Pervuy) 20.03.14 14:06
4. Дмитрий Глеков (glek) 01.04.14 11:17
5. Валерий С. (seva1405) 05.07.15 20:52
Павел, спасибо за статью! Скажите не планируется ли у вас урок по партионному учету с характеристиками? Не получается их правильно сгруппировать.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа