Почему не заполняются показатели в табличной части при повторном подборе в ЗУП 3.1 и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

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

В этой статье мы подробно разберем природу данной проблемы, проанализируем логическую ошибку в коде, изучим внутреннюю архитектуру хранения показателей в ЗУП 3.1 и рассмотрим современные варианты решения, включая типовые возможности системы.

Анализ логической ошибки: почему ломался первоначальный код?

Для начала выясним причину сбоя в алгоритме заполнения. Проанализируем исходный фрагмент кода, который разработчик использовал для обработки результатов подбора сотрудников:


Для Индекс = 0 По ВыбранноеЗначение.Количество - 1 Цикл
    Для Итератор = 1 По 100 Цикл
        Если Не объект.Начисления.Количество = 0 Тогда
            Если объект.Начисления[Индекс].Свойство("Показатель" + Итератор) Тогда
                Если Строка(объект.Начисления[Индекс]["Показатель" + Итератор]) = "Среднее количество часов в месяце" Тогда
                    объект.Начисления[Индекс]["Значение" + Итератор] = Доработки.ПечатнаяФормаГрафиковРаботы(объект.Начисления[Индекс].ГрафикРаботы, Год(Объект.ДатаНачала));
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

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

Шаг 1: Первичное заполнение документа.
Пользователь открывает пустой документ, нажимает кнопку подбора и выбирает, например, 5 сотрудников. Платформа возвращает коллекцию ВыбранноеЗначение, содержащую 5 элементов. Соответственно, переменная ВыбранноеЗначение.Количество принимает значение 5. В табличную часть Начисления добавляется 5 строк (с индексами от 0 до 4). Запускается внешний цикл: Для Индекс = 0 По ВыбранноеЗначение.Количество - 1, который совершает итерации от 0 до 4. Внутри цикла код успешно обращается к строкам по индексу: объект.Начисления[0], объект.Начисления[1] ... объект.Начисления[4]. Показатели для первых пяти сотрудников рассчитываются и выводятся на форму без замечаний.

Шаг 2: Повторный запуск подбора.
Пользователь решает добавить в этот же документ еще 3 сотрудников. Он снова открывает подбор и выбирает новые элементы. В коллекцию ВыбранноеЗначение теперь попадает только 3 элемента (новые добавленные сотрудники). Соответственно, переменная ВыбранноеЗначение.Количество теперь равна 3. При этом в табличной части Начисления уже содержатся ранее добавленные сотрудники, и теперь общее количество строк равно 8 (5 старых и 3 новых). Новые сотрудники физически записаны в конец таблицы и имеют индексы 5, 6 и 7. Запускается цикл: Для Индекс = 0 По ВыбранноеЗначение.Количество - 1, который в данном случае будет итерироваться от 0 до 2. В результате программа начинает обрабатывать строки объект.Начисления[0], объект.Начисления[1] и объект.Начисления[2]. Это строки **первых трех ранее добавленных сотрудников**! Их показатели рассчитываются заново и перезаписываются. При этом строки с новыми сотрудниками (индексы 5, 6, 7) вообще не обрабатываются кодом, так как переменная Индекс никогда не достигнет этих значений. Именно поэтому значения показателей у новых сотрудников остаются пустыми.

Исправление логической ошибки: правильный обход строк

Чтобы исправить эту проблему раз и навсегда, необходимо отказаться от привязки к индексам коллекции результатов подбора при заполнении строк табличной части. Вместо этого следует использовать универсальный обход коллекции Для Каждого.

Рассмотрим правильный вариант кода:


Для Каждого Стр Из Объект.Начисления Цикл
    Для Итератор = 1 По ЭтаФорма.Показатели.Количество Цикл
        Если Стр.Свойство("Показатель" + Итератор) Тогда
            Если Строка(Стр["Показатель" + Итератор]) = "Среднее количество часов в месяце" Тогда
                Стр["Значение" + Итератор] = Доработки.ПечатнаяФормаГрафиковРаботы(Стр.ГрафикРаботы, Год(Объект.ДатаНачала));
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Проанализируем преимущества данного подхода:

  1. Полный охват данных: Конструкция Для Каждого Стр Из Объект.Начисления гарантирует, что программа обойдет абсолютно все строки, присутствующие в документе на момент выполнения кода, независимо от того, когда и каким образом они были туда добавлены.
  2. Независимость от порядка и времени добавления: Нам больше не нужно пытаться сопоставить входящий массив выбора с индексами строк таблицы. Мы просто последовательно заполняем показатели для всех сотрудников в табличной части.
  3. Повышение производительности и стабильности: Мы заменили жестко прописанный лимит итераций в 100 циклов на динамическое количество показателей формы: ЭтаФорма.Показатели.Количество. Это избавляет систему от выполнения сотен лишних 'холостых' циклов и предотвращает возможные ошибки выхода за границы диапазона.

Архитектурные особенности: как показатели устроены «под капотом» ЗУП 3.1

Для того чтобы писать надежный код, способный пережить будущие обновления конфигурации, важно понимать, как устроена архитектура хранения показателей в ЗУП 3.1.

Многие начинающие разработчики совершают методологическую ошибку, пытаясь напрямую работать с динамическими колонками формы вида Значение1, Значение2 и т. д. Давайте разберем, почему это тупиковый путь при разработке сложных алгоритмов:

Рассмотрим пример правильного программного заполнения показателей на уровне объекта данных. Этот код будет стабильно работать как на форме, так и в серверных фоновых заданиях или при программном создании документов из внешних источников:


// Пример правильного программного заполнения показателей на уровне объекта метаданных
Для Каждого СтрокаНачисления Из Объект.Начисления Цикл
    
    // Получаем уникальный идентификатор строки для установки связи
    ИдентификаторСвязи = СтрокаНачисления.ИдентификаторСтроки;
    
    // Определяем нужный нам показатель расчета зарплаты
    СсылкаНаПоказатель = Справочники.ПоказателиРасчетаЗарплаты.НайтиПоНаименованию("Среднее количество часов в месяце");
    
    Если ЗначениеЗаполнено(СсылкаНаПоказатель) Тогда
        
        // Пытаемся найти уже существующую строку показателя для данного начисления
        ПараметрыПоиска = Новый Структура;
        ПараметрыПоиска.Вставить("ИдентификаторСтроки", ИдентификаторСвязи);
        ПараметрыПоиска.Вставить("Показатель", СсылкаНаПоказатель);
        
        НайденныеСтроки = Объект.Показатели.НайтиСтроки(ПараметрыПоиска);
        
        Если НайденныеСтроки.Количество() > 0 Тогда
            СтрокаПоказателя = НайденныеСтроки[0];
        Иначе
            // Если строка не найдена, создаем новую и связываем ее
            СтрокаПоказателя = Объект.Показатели.Добавить();
            СтрокаПоказателя.ИдентификаторСтроки = ИдентификаторСвязи;
            СтрокаПоказателя.Показатель = СсылкаНаПоказатель;
        КонецЕсли;
        
        // Производим расчет значения и его запись в ТЧ "Показатели"
        СтрокаПоказателя.Значение = Доработки.ПечатнаяФормаГрафиковРаботы(СтрокаНачисления.ГрафикРаботы, Год(Объект.ДатаНачала));
        
    КонецЕсли;
    
КонецЦикла;

Этот подход является архитектурно верным для ЗУП 3.1. Он не зависит от контекста формы, выполняется на сервере и гарантирует полную сохранность связей между начислениями сотрудников и их показателями.

Современное типовое решение в ЗУП 3.1 (версии 3.1.27+)

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

Начиная с релизов 3.1.27.111 и 3.1.28.11, фирма «1С» добавила в документы «Премия» и «Разовое начисление» мощный стандартный инструмент — кнопку «Заполнить показатели». Во многих случаях этот функционал полностью исключает необходимость ручных программных доработок.

Возможности типового механизма:

Использование этого механизма снижает совокупную стоимость владения системой, так как типовая конфигурация остается на стандартной поддержке без необходимости постоянного обновления кастомного кода при выходе новых релизов от фирмы «1С».

← На главную