Исходная конфигурация
Конфигурация примитивная. два документа с классическим составом и регистр накопления остатков. Партия в регистре - это ссылка на документ “ПриходнаяНакладная”. Остальное, надеюсь, очевидно.
В тестовой конфигурации были проведены “Приходные”, для формирования остатков по партиям.
Примечание
Да, статья исключительно академическая, в реальной эксплуатации сомнительно применение подобного подхода.
Да - нет контроля остатков.
Да - только метод 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, и нож не продадим, его вообще в остатках нет. Но это отдельная история…
Оригинал статьи на моем сайте.
С уважением, Павел Чистов.