Работа с периодическими реквизитами в 1С:Предприятие 7.7 имеет свои специфические особенности, которые часто вызывают вопросы даже у опытных разработчиков. Основная сложность заключается в том, что периодический реквизит — это не просто поле в таблице справочника, а целая история значений, хранящаяся в отдельной системной таблице (1SCONST). Рассмотрим подробно, как правильно изменять такие данные программно, проанализируем типичные ошибки и разберем наиболее эффективные способы решения задачи на примере массового изменения ставки НДС.
Этот способ является наиболее распространенным. Его суть заключается в том, что мы «настраиваем» объект справочника на работу с конкретной датой, после чего присваиваем значение реквизиту как обычному атрибуту и фиксируем изменения методом Записать(). Проанализируем пример кода, который часто используют для таких задач:
ИзменямСправочник = СоздатьОбъект("Справочник.Номенклатура");
// Устанавливаем дату, на которую будет записано новое значение
ИзменямСправочник.ИспользоватьДату(ТекущаяДата(), 1);
ИзменямСправочник.ВыбратьЭлементы();
Пока ИзменямСправочник.ПолучитьЭлемент() = 1 Цикл
// Проверяем, не является ли элемент группой (папкой)
Если ИзменямСправочник.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
// Присваиваем новое значение реквизиту
ИзменямСправочник.СтавкаНДС = Перечисление.СтавкиНДС.СтавкаНДС20;
// Обязательно вызываем метод Записать()
ИзменямСправочник.Записать();
Сообщить("Обновлен элемент: " + ИзменямСправочник.Наименование);
КонецЦикла;
Разберем важный нюанс, который часто упускают. Метод ИспользоватьДату(Дата, УстСразу) имеет второй необязательный параметр. Посмотрим на его значение:
Если вы уже получили элемент через ПолучитьЭлемент() и только потом решили вызвать ИспользоватьДату, без передачи единицы во втором параметре изменения могут не примениться к текущему объекту в памяти. Поэтому рекомендуем всегда указывать 1, чтобы гарантировать корректную установку даты записи.
Если нам не нужно менять весь объект справочника, а требуется только записать значение конкретного периодического реквизита на определенную дату, можно воспользоваться методом Установить(). Это более лаконичный способ, который работает напрямую с реквизитом.
Синтаксис метода выглядит следующим образом: Справочник.Реквизит.Установить(Дата, Значение). Обратите внимание на порядок параметров, он отличается от некоторых других функций 1С. Выясним, как применить это на практике:
Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 0 Тогда
// Устанавливаем ставку НДС на начало 2019 года
Спр.СтавкаНДС.Установить('01.01.2019', Перечисление.СтавкиНДС.СтавкаНДС20);
// В этом случае метод Записать() для справочника вызывать НЕ НУЖНО
КонецЕсли;
КонецЦикла;
Этот метод удобен тем, что он автоматически создает запись в истории значений на указанную дату. Если запись на эту дату уже существовала, она будет перезаписана новым значением.
Для массовых операций и сложной работы с историей (например, когда нужно не только записать, но и прочитать предыдущие значения или удалить историю за период) лучше всего использовать объект Периодический. Это самый «чистый» и производительный метод с точки зрения архитектуры 1С 7.7.
Проанализируем алгоритм работы с этим объектом:
Периодический.ИспользоватьОбъект.Записать() самого объекта Периодический.Посмотрим на пример кода:
Спр = СоздатьОбъект("Справочник.Номенклатура");
ОбъектПериод = СоздатьОбъект("Периодический");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
// Связываем объект с реквизитом "СтавкаНДС" текущего товара
ОбъектПериод.ИспользоватьОбъект("СтавкаНДС", Спр.ТекущийЭлемент());
// Задаем параметры новой записи истории
ОбъектПериод.ДатаЗнач = '01.01.2019';
ОбъектПериод.Значение = Перечисление.СтавкиНДС.СтавкаНДС20;
// Записываем только значение реквизита, не трогая карточку товара
ОбъектПериод.Записать();
КонецЦикла;
Преимущества данного метода: работа происходит быстрее, так как не перезаписывается вся запись в таблице справочника (не меняется время последнего редактирования элемента, не блокируется вся строка справочника). Это критически важно, если в вашей базе данных сотни тысяч наименований номенклатуры.
Разберем несколько практических советов, которые помогут избежать ошибок и потери данных при выполнении подобных обработок:
НачатьТранзакцию();
// Ваш цикл изменения справочника
ЗафиксироватьТранзакцию();
ЭтоГруппа(). Попытка записать значение в периодический реквизит группы справочника может привести к ошибке исполнения, если для групп этот реквизит не предусмотрен метаданными.ТекущаяДата(). Если вы запускаете обработку по переходу на новую ставку НДС заранее (например, 25 декабря), а ставка должна начать действовать с 1 января, обязательно указывайте жесткую дату '01.01.2019', иначе история заполнится некорректно.Таким образом, мы рассмотрели три способа управления историей значений. Для простых разовых правок подойдет метод Установить, а для серьезных автоматизаций и массовых обновлений рекомендуем использовать объект Периодический в связке с транзакциями.