При работе с Системой компоновки данных (СКД) в 1С часто возникает необходимость в нумерации строк отчета. Стандартное системное поле НомерПоПорядкуВГруппировке позволяет нумеровать записи в рамках текущей группировки. Однако что делать, если требуется более сложная логика, например, чтобы нумерация детальных записей сбрасывалась и начиналась заново при смене значений верхнего уровня группировки, а не только внутри самой вложенной? Давайте подробно рассмотрим эту задачу и способы ее решения.
Представим ситуацию: у нас есть отчет с двумя уровнями группировки, например, «Производство» и «ОКОФ». Нам необходимо, чтобы детальные записи, относящиеся к определенному «Производству», нумеровались по порядку, но при переходе к следующему «Производству» нумерация начиналась снова с 1.
Стандартное поведение СистемныеПоля.НомерПоПорядкуВГруппировке заключается в нумерации строк внутри той группировки, в которую оно непосредственно добавлено. Если мы добавим его к детальным записям, оно будет нумеровать их сквозным образом, либо внутри самой последней, самой детальной группировки. Это не всегда удовлетворяет нашим требованиям, когда нам нужен контекст нумерации по более высокому уровню иерархии.
Выясним, как мы можем добиться желаемого результата, используя возможности СКД и, при необходимости, программные корректировки.
Уровень() и ВычислитьВыражение() в вычисляемых полях СКДДля создания иерархической нумерации, которая учитывает родительский уровень или сбрасывается на каждом уровне, мы можем эффективно использовать вычисляемые поля в СКД в комбинации с такими функциями, как Уровень() и ВычислитьВыражение().
Рассмотрим, как это работает:
Уровень(): Эта функция возвращает текущий уровень вложенности записи или группировки. Для корневых записей или верхнего уровня группировки она обычно возвращает 0. Для первого вложенного уровня — 1, и так далее. Мы можем использовать ее, чтобы понять, на каком уровне мы находимся.
ВычислитьВыражение(Выражение, КонтекстГруппировки): Эта мощная функция позволяет нам вычислить любое выражение в контексте определенной группировки. Это именно то, что нам нужно для получения номера по порядку для вышележащей группировки.
Выражение) — это строка с выражением, которое нужно вычислить, например, "НомерПоПорядкуВГруппировке()" или "НомерПоПорядку".КонтекстГруппировки) — это имя группировки, в рамках которой должно производиться вычисление.Давайте посмотрим на гипотетический пример выражения для двух уровней группировки ("Производство" и "ОКОФ"):
Допустим, нам нужно, чтобы детальные записи нумеровались в рамках «Производства». Мы можем создать вычисляемое поле, которое будет получать НомерПоПорядку в контексте группировки «Производство».
ВычислитьВыражение("НомерПоПорядку", "Производство")
В этом случае, НомерПоПорядку будет рассчитываться для каждой строки, но счетчик будет сбрасываться каждый раз, когда меняется значение поля, по которому производится группировка «Производство».
Важный момент: Поле НомерПоПорядку является системным полем, которое доступно внутри СКД для вычисления сквозной нумерации или нумерации в рамках группировки, если оно явно не указано в выбранных полях, но используется в выражениях.
Если бы нам понадобилась более сложная иерархическая нумерация, например, "1.1", "1.2", "2.1", "2.2", мы могли бы комбинировать эти функции:
Выбор
Когда Уровень() = 0 Тогда Строка(НомерПоПорядкуВГруппировке())
Когда Уровень() = 1 Тогда
Строка(ВычислитьВыражение("НомерПоПорядкуВГруппировке()", "Производство"))
+ "."
+ Строка(НомерПоПорядкуВГруппировке())
Иначе ""
Конец
Однако в нашем конкретном случае, когда требуется просто сброс нумерации при смене верхнего уровня, достаточно использовать ВычислитьВыражение("НомерПоПорядку", "ИмяВышестоящейГруппировки") для детальных записей.
Наиболее прямолинейный и часто применяемый способ для нашей задачи — это создание вычисляемого поля, которое будет рассчитывать номер по порядку, но при этом явно указывать контекст, в котором этот номер должен быть вычислен.
ВычислитьВыражение("НомерПоПорядку", "Производство")
Где "Производство" — это имя поля, по которому вы осуществляете верхний уровень группировки в настройках СКД.
Как это работает?
Функция ВычислитьВыражение фактически говорит СКД: «Вычисли сквозной номер по порядку ("НомерПоПорядку") для каждой строки, но каждый раз, когда значение поля "Производство" меняется, начни отсчет заново с 1». Таким образом, вы получаете нумерацию детальных записей, которая сбрасывается при смене верхнего уровня группировки «Производство».
Важный аспект: Для корректной работы этого механизма, поле, указанное в качестве контекста (в нашем случае «Производство»), должно присутствовать в настройках группировок СКД, даже если сама эта группировка не выводится визуально в отчете.
Если вы используете пользовательские макеты для оформления отчета, стандартные системные поля типа НомерПоПорядкуВГруппировке могут быть недоступны напрямую или вести себя непредсказуемо. Однако, если вы создали вычисляемое поле в СКД с нужной логикой (как описано в Решении 1 или Решении 2), это пользовательское поле будет доступно для вывода в вашем макете.
Это позволяет сохранить гибкость настройки логики нумерации средствами СКД и одновременно использовать преимущества пользовательских макетов для сложного оформления.
В самых сложных случаях, когда требуется очень специфическая иерархическая нумерация или логика, которую трудно реализовать средствами выражений СКД, можно прибегнуть к программной постобработке отчета. Этот подход требует большего объема кода и понимания структуры объекта «РезультатКомпоновкиДанных».
Используя методы обхода табличного документа, вы можете пройти по строкам отчета, идентифицировать начало новой группировки (например, по изменению значения поля «Производство») и программно заполнить нумерацию, обнуляя счетчик при необходимости.
// Примерный алгоритм
// Получаем табличный документ
ТабличныйДокумент = ЭлементыФормы.РезультатОтчета.Получить();
НомерПП = 0;
ПредыдущееПроизводство = Неопределено;
Для Каждого ОбластьСтроки Из ТабличныйДокумент.Области Цикл
// Определяем, является ли строка детальной записью или строкой группировки
Если ОбластьСтроки.Параметры.Свойство("ТипОбласти") Тогда
Если ОбластьСтроки.Параметры.ТипОбласти = "ДетальныеЗаписи" Тогда
// Получаем значение поля Производство для текущей строки
ТекущееПроизводство = ОбластьСтроки.Параметры.Производство; // Предполагаем, что Производство передается в параметры
Если ТекущееПроизводство <> ПредыдущееПроизводство Тогда
НомерПП = 1; // Сбрасываем счетчик при смене Производства
ПредыдущееПроизводство = ТекущееПроизводство;
Иначе
НомерПП = НомерПП + 1;
КонецЕсли;
// Устанавливаем номер п/п в поле, которое мы создали в макете
ОбластьСтроки.Параметры.Счетчик = НомерПП;
ИначеЕсли ОбластьСтроки.Параметры.ТипОбласти = "ГруппировкаПроизводство" Тогда
// Если это строка группировки, сбрасываем счетчик для следующего блока детальных записей
ПредыдущееПроизводство = ОбластьСтроки.Параметры.Производство;
НомерПП = 0;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ТабличныйДокумент.Показать();
Этот подход дает максимальную гибкость, но требует хорошего знания программной работы с табличными документами и может быть более трудоемким в отладке и поддержке.
Задача нумерации записей в отчете СКД с обнулением при смене верхнего уровня группировки является достаточно распространенной. Мы видим, что стандартное поле НомерПоПорядкуВГруппировке не всегда дает желаемый результат. Наиболее эффективными и гибкими методами являются использование вычисляемых полей в СКД в сочетании с функцией ВычислитьВыражение("НомерПоПорядку", "ИмяВышестоящейГруппировки"). Этот подход позволяет добиться требуемой логики, минимизируя необходимость в программном коде и максимально используя возможности самой СКД. При этом, если используются пользовательские макеты, вычисляемые поля будут легко доступны для вывода. Программная постобработка остается вариантом для очень специфичных и сложных сценариев.