Почему не совпадают номера строк в документе и регистре накопления 1С и как правильно связать материалы с продукцией?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке отчетов или доработке механизмов проведения производственных документов (например, Отчета производства за смену) разработчики часто сталкиваются с ситуацией: при попытке сопоставить строки табличной части документа с записями регистра накопления через стандартное поле НомерСтроки данные расходятся или перемешиваются. Разберем детально, почему возникает такое поведение платформы «1С:Предприятие», в чем заключается назначение поля НомерСтроки в регистрах и какими типовыми механизмами следует пользоваться для получения связи «материал — выпущенная продукция».

Выясним природу поля НомерСтроки в регистрах накопления

Распространенное заблуждение заключается в предположении, что колонка НомерСтроки в таблице движений регистра автоматически дублирует индекс строки табличной части документа. На практике это не так. Проанализируем, как устроен этот механизм на уровне платформы:

  1. Физический индекс записи набора. Поле НомерСтроки в регистре — это порядковый номер записи внутри конкретного набора записей регистратора. Оно формируется платформой заново при записи набора или при вызове метода набора записей Загрузить() от 1 до N.
  2. Составной первичный ключ. В платформе 1С идентификация отдельной записи регистра накопления обеспечивается объектом РегистрНакопленияКлючЗаписи, который состоит из комбинации двух полей: Регистратор + НомерСтроки. Системное поле НомерСтроки служит исключительно для обеспечения уникальности физических записей внутри одного документа в базе данных.
  3. Предупреждение платформы. Как указано в синтакс-помощнике платформы 1С, объект РегистрНакопленияКлючЗаписи нельзя использовать как устойчивый идентификатор записи (например, в качестве ссылки или внешнего ключа). Это значение актуально только до тех пор, пока набор записей существует в неизменном виде и не был перезаписан.

Почему порядок строк в движениях документа меняется?

Рассмотрим причины, по которым порядок записей в регистре отличается от порядка строк в табличной части документа:

  1. Группировка в запросах проведения. В типовых алгоритмах проведения движения формируются не построчным обходом табличной части, а пакетными запросами к базе данных. При этом практически всегда применяется конструкция СГРУППИРОВАТЬ ПО по измерениям регистра (номенклатура, склад, характеристика, серия). Если одна и та же позиция указана в таблице документа несколько раз, в регистре строки схлопываются, и однозначное соответствие номеров строк теряется.
  2. Недетерминированная сортировка СУБД. Если в тексте запроса формирования движений отсутствует явное указание УПОРЯДОЧИТЬ ПО НомерСтроки, результирующий порядок строк определяется оптимизатором СУБД. В результате записи могут следовать в произвольном порядке, отличном от визуального порядка в форме документа.
  3. Партионный учет и списание со складов. При проведении документа алгоритм может разбивать одну исходную строку документа на несколько движений (например, при списании материалов по методу FIFO или с разных мест хранения).
  4. Динамичность номеров в табличной части документа. Реквизит НомерСтроки в табличных частях самого документа пересчитывается при интерактивном удалении строк, перетаскивании или сортировке колонок пользователем, что делает его непригодным для надежной программной связи.

Где на самом деле искать связь списанного материала и продукции?

Проанализируем назначение регистров в производственном контуре типовых решений (таких как УПП, Комплексная автоматизация или ERP):

  1. Регистр «Материалы в производстве». Этот регистр является остаточным. Он предназначен для оперативного контроля наличия материалов в незавершенном производстве (цеховых кладовых) и контроля остатков у мастеров смен. Он не содержит аналитики выпуска и не предназначен для калькуляции себестоимости или привязки затрат к продукции.
  2. Регистры затрат на выпуск. Полная аналитическая привязка сырья к конкретному изделию фиксируется в оборотных регистрах учета затрат, таких как Затраты на выпуск продукции (управленческий учет) или Затраты на выпуск продукции (бухгалтерский учет). В этих регистрах присутствуют как измерения готовой продукции (номенклатура выпуска, характеристика, серия, спецификация), так и аналитика списанных материальных затрат.
  3. Табличная часть «Распределение материалов». В самом документе «Отчет производства за смену» привязка выполняется на закладке распределения, где в каждой строке явно указаны реквизиты выпущенной продукции и списанного на нее материала.

Как правильно организовать связь между строками в коде 1С?

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

Способ 1. Использование механизма «КлючСвязи» / «КлючСтроки»

В типовых конфигурациях для соединения строк разных табличных частей (например, «Продукция» и «Материалы») используется специальный реквизит табличной части с типом Число — КлючСвязи (или КлючСтроки). Он генерируется при заполнении таблицы и не меняется при интерактивных перемещениях строк.

Посмотрим на пример запроса, соединяющего продукцию и распределенные материалы по ключу связи:


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

Способ 2. Добавление явного реквизита в регистр накопления

Если для аналитических отчетов вам действительно требуется знать исходную строку документа в движениях регистра, никогда не полагайтесь на системное поле НомерСтроки. Добавьте в регистр собственный реквизит (например, НомерСтрокиДокумента или ИдентификаторСтроки с типом Число) и заполняйте его явно в процедуре ОбработкаПроведения модуля документа:


Для Каждого СтрМатериалы Из ТаблицаМатериалов Цикл
    Движение = Движения.МатериалыВПроизводстве.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = Дата;
    Движение.Номенклатура = СтрМатериалы.Номенклатура;
    Движение.Количество = СтрМатериалы.Количество;
    
    // Явно сохраняем номер строки табличной части в наш собственный реквизит:
    Движение.НомерСтрокиДокумента = СтрМатериалы.НомерСтроки;
КонецЦикла;

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

← На главную