Как реализовать автоматический пересчет цен при изменении даты документа в 1С 8.3 (Занятие 9 Радченко)

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

При изучении основ разработки в системе 1С по методике М.Г. Радченко многие начинающие разработчики сталкиваются с ситуацией, когда механизмы, описанные в учебнике, работают корректно только при создании нового документа. Типичный пример — занятие №9, где настраивается автоматическое получение цены из регистра сведений при выборе номенклатуры. Однако часто возникает вопрос: почему, если мы меняем дату уже созданного документа, цены в табличной части не обновляются автоматически, хотя в регистре на новую дату могут быть установлены совсем другие значения?

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

Анализ механизма: почему цена не меняется автоматически?

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

Когда же мы меняем реквизит Дата в шапке документа, срабатывает событие самого поля даты. Платформа 1С не знает о том, что данные в табличной части (цены, суммы) зависят от этой даты, пока разработчик явно не укажет это в коде. В системе 1С нет встроенного интеллекта, который бы автоматически пересчитывал все связанные данные при изменении даты, так как в реальных бизнес-задачах это может привести к нежелательному изменению финансовых показателей прошлых периодов без ведома пользователя.

Разбираем код из занятия №9

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


// Обработчик изменения номенклатуры в строке табличной части
&НаКлиенте
Процедура ПереченьНоменклатурыНоменклатураПриИзменении(Элемент)
    // Получить текущую строку табличной части.
    СтрокаТабличнойЧасти = Элементы.ПереченьНоменклатуры.ТекущиеДанные;
    
    // Установить цену, используя функцию из общего модуля.
    // Передаем дату документа и выбранную номенклатуру.
    СтрокаТабличнойЧасти.Цена = РаботаСоСправочниками.РозничнаяЦена(Объект.Дата, СтрокаТабличнойЧасти.Номенклатура);
    
    // Пересчитать сумму строки
    РаботаСДокументами.РассчитатьСумму(СтрокаТабличнойЧасти);
КонецПроцедуры

В данном коде ключевым моментом является использование метода Объект.Дата. Именно этот параметр определяет, на какой «срез времени» функция РозничнаяЦена будет искать данные в регистре сведений. Если мы изменим дату в шапке, значение Объект.Дата поменяется, но обработчик ПриИзменении для номенклатуры не запустится, поэтому старая цена останется в строке.

Пошаговое решение: пересчет при изменении даты

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

  1. Создать обработчик события для даты: В конфигураторе откроем форму документа ОказаниеУслуги. Найдем в реквизитах объекта поле Дата, перейдем в его свойства и создадим обработчик события ПриИзменении на клиенте.
  2. Организовать цикл по строкам: В отличие от выбора номенклатуры, где мы работаем с ТекущиеДанные (одной строкой), при изменении даты нам нужно обновить все строки табличной части.
  3. Вызвать функции пересчета: Для каждой строки нужно заново обратиться к серверной функции получения цены и пересчитать сумму.

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


&НаКлиенте
Процедура ДатаПриИзменении(Элемент)
    
    // Выясним причину: нам нужно пройти по всей коллекции строк табличной части
    Для Каждого СтрокаТЧ Из Объект.ПереченьНоменклатуры Цикл
        
        // Для каждой строки получаем актуальную цену на новую дату документа
        // Используем ту же экспортную функцию из общего модуля
        НоваяЦена = РаботаСоСправочниками.РозничнаяЦена(Объект.Дата, СтрокаТЧ.Номенклатура);
        
        // Проверяем, изменилась ли цена, чтобы не перезаписывать данные лишний раз
        Если СтрокаТЧ.Цена <> НоваяЦена Тогда
            СтрокаТЧ.Цена = НоваяЦена;
            
            // После изменения цены обязательно вызываем пересчет суммы
            РаботаСДокументами.РассчитатьСумму(СтрокаТЧ);
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Нюансы работы с периодическими регистрами

Проанализируем работу функции РозничнаяЦена. Внутри она выполняет запрос к виртуальной таблице СрезПоследних регистра сведений. Параметр «Период» в этом запросе критически важен. Если бы в коде вместо Объект.Дата передавалась пустая дата или ТекущаяДата(), то система всегда возвращала бы самую последнюю цену, игнорируя дату документа. В учебнике Радченко грамотно используется передача даты именно из реквизита документа, что позволяет соблюдать историческую точность учета.

Оптимизация и промышленный подход

В реальных типовых конфигурациях (например, в 1С:Управлении торговлей или ERP) автоматический пересчет цен при случайном изменении даты может быть опасен. Представьте, что бухгалтер случайно изменил дату в документе годовой давности, и все цены «поехали». Поэтому профессиональные разработчики часто добавляют вопрос пользователю: «Дата документа изменилась. Желаете ли вы пересчитать цены в соответствии с новой датой?».

Также стоит учитывать производительность. Если в табличной части сотни строк, вызов функции РозничнаяЦена в цикле (который внутри делает запрос к БД) может замедлить работу формы. В таких случаях программисты пишут один запрос, который получает цены сразу для всего списка номенклатуры из документа на определенную дату. Однако для учебных целей и небольших документов подход с циклом, предложенный выше, является абсолютно корректным и наглядным.

Заключение

Мы выяснили, что для решения проблемы «застывших» цен необходимо связать событие изменения даты с логикой обновления табличной части. Помните, что в 1С 8.3 управляемые формы работают по принципу «событие — реакция». Если вы хотите, чтобы изменение одного реквизита влияло на другие, вы всегда должны прописывать эту связь программно в соответствующем обработчике события.

← На главную