При разработке и сопровождении учетных систем на платформе 1С разработчики нередко сталкиваются с ситуацией, когда в табличной части документа присутствуют две или более строки с одинаковой номенклатурой и одинаковыми характеристиками. Типичный пример: в заказе покупателя одна и та же позиция заведена двумя строками, так как выпуск продукции на производстве запланирован на разные даты. При проведении документа в регистр накопления остатков записываются две отдельные записи. Однако при попытке прочитать данные через виртуальную таблицу Остатки запрос возвращает одну свёрнутую запись с общей суммой и количеством.
Выясним причину такого поведения платформы и подробно рассмотрим варианты решения, позволяющие обойти данное архитектурное ограничение.
Для понимания происходящего проанализируем внутреннее устройство регистров накопления с видом «Остатки» в платформе 1С:Предприятие:
Номенклатура, ХарактеристикаНоменклатуры, ЗаказПокупателя), для платформы это одна и та же итоговая точка остатка.Остатки предназначена для быстрого извлечения мгновенного среза данных именно из таблицы итогов. Поэтому получить из неё остаток с детализацией до исходной строки движения технически невозможно.Параметр Периодичность.Запись или Периодичность.Регистратор доступен только в виртуальной таблице ОстаткиИОбороты. Однако даже обращение к ней с детализацией по документу-регистратору не решит задачу, если обе строки принадлежат одному и тому же документу: они всё равно свернутся в одну запись, так как регистратор и измерения у них полностью совпадают.
Самый простой и типовой путь решения задачи без глобального изменения логики регистров — добавить в движения разделитель, который сделает строки уникальными. В типовых конфигурациях для этого штатно используется измерение СерияНоменклатуры.
Разберем по шагам, как это работает:
СерияНоменклатуры входит в состав измерений регистра остатков, комбинация измерений для двух строк становится различной.Остатки запрос возвращает две независимые строки, каждая со своим количеством и остатком.Если серии использовать нецелесообразно или методология предприятия не предполагает серийного учета, рассмотрим современный платформенный паттерн, применяемый в типовых конфигурациях линейки ERP и УТ 11: внедрение уникального ключа строки.
Для реализации этого подхода выполним следующие действия:
КлючСтроки (тип Число). При заполнении документа ему присваивается уникальный номер (например, номер строки).КлючСтроки с аналогичным типом.В результате комбинация «Номенклатура + Характеристика + Заказ + КлючСтроки» становится уникальной для каждой позиции табличной части, и виртуальная таблица Остатки перестает сворачивать строки:
ВЫБРАТЬ
Остатки.ЗаказПокупателя КАК ЗаказПокупателя,
Остатки.Номенклатура КАК Номенклатура,
Остатки.КлючСтроки КАК КлючСтроки,
Остатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
РегистрНакопления.ЗаказыПокупателей.Остатки(
&Период,
ЗаказПокупателя = &ТекущийЗаказ) КАК Остатки
Если конфигурация находится на поддержке и менять состав измерений регистра нельзя, остаток можно распределить по строкам документа алгоритмически прямо в запросе. Для этого табличная часть соединяется со свернутым остатком регистра, а списание остатка рассчитывается накопительным итогом.
Рассмотрим пример запроса с вычислением накопительного итога:
ВЫБРАТЬ
ТЧ.НомерСтроки КАК НомерСтроки,
ТЧ.Номенклатура КАК Номенклатура,
ТЧ.Количество КАК КоличествоПлан,
СУММА(ТЧ_Предыдущие.Количество) КАК НакопленныйИтогПлан,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК ВсегоОстаток
ПОМЕСТИТЬ ВТ_СтрокиСИтогами
ИЗ
Документ.ЗаказПокупателя.Товары КАК ТЧ
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя.Товары КАК ТЧ_Предыдущие
ПО ТЧ.Ссылка = ТЧ_Предыдущие.Ссылка
И ТЧ.Номенклатура = ТЧ_Предыдущие.Номенклатура
И ТЧ.НомерСтроки >= ТЧ_Предыдущие.НомерСтроки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ЗаказыПокупателей.Остатки(
&Период,
ЗаказПокупателя = &ТекущийЗаказ) КАК Остатки
ПО ТЧ.Ссылка = Остатки.ЗаказПокупателя
И ТЧ.Номенклатура = Остатки.Номенклатура
ГДЕ
ТЧ.Ссылка = &ТекущийЗаказ
СГРУППИРОВАТЬ ПО
ТЧ.НомерСтроки,
ТЧ.Номенклатура,
ТЧ.Количество,
Остатки.КоличествоОстаток
;
ВЫБРАТЬ
ВТ.НомерСтроки КАК НомерСтроки,
ВТ.Номенклатура КАК Номенклатура,
ВТ.КоличествоПлан КАК КоличествоПлан,
ВЫБОР
КОГДА ВТ.ВсегоОстаток >= ВТ.НакопленныйИтогПлан
ТОГДА ВТ.КоличествоПлан
КОГДА ВТ.ВсегоОстаток > ВТ.НакопленныйИтогПлан - ВТ.КоличествоПлан
ТОГДА ВТ.ВсегоОстаток - (ВТ.НакопленныйИтогПлан - ВТ.КоличествоПлан)
ИНАЧЕ 0
КОНЕЦ КАК ОстатокПоСтроке
ИЗ
ВТ_СтрокиСИтогами КАК ВТ
УПОРЯДОЧИТЬ ПО
ВТ.НомерСтроки
Разберем логику вычисления: запрос берет исходные строки документа и рассчитывает, сколько товара уже должно было быть закрыто предыдущими строками. Затем общий свернутый остаток из регистра распределяется по строкам по принципу FIFO, закрывая их последовательно.
В типовых решениях (включая УПП) основным разрезом контроля исполнения заказа покупателя является сам документ заказа. Если две партии одинаковой продукции имеют разные даты готовности и отгрузки, штатным подходом является создание двух отдельных документов «Заказ покупателя» под каждую дату выполнения. Это исключает коллизии в регистрах и снимает необходимость доработки конфигурации.