Как изменить расчет ресурса СтоимостьРегл в регистре СебестоимостьТоваров в 1С?

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

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

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

Анализ ошибки: почему не подходит событие ПриЗаписи

Распространенная ошибка начинающих разработчиков — попытка модифицировать движения в обработчике ПриЗаписи модуля набора записей регистра. Посмотрим на типичный ошибочный код:


Процедура ПриЗаписи(Отказ, Замещение)
    Для Каждого Движение Из ЭтотОбъект Цикл 
        Движение.СтоимостьРегл = Движение.СтоимостьБезНДС * ПолучитьКурс(); 
    КонецЦикла;        
КонецПроцедуры

Выясним причину, почему такой код не работает. Обработчик ПриЗаписи вызывается платформой в тот момент, когда данные набора уже физически записаны в таблицы СУБД в рамках открытой транзакции. Изменение значений в коллекции ЭтотОбъект на данном этапе меняет лишь состояние набора в оперативной памяти сервера, но в базу данных эти изменения уже не попадают.

Если же разработчик пытается принудительно зафиксировать изменения и вызывает команду ЭтотОбъект.Записать() внутри процедуры ПриЗаписи, платформа повторно инициирует цепочку событий записи. Это приводит к бесконечной рекурсии (зацикливанию) и аварийному завершению транзакции по переполнению стека вызовов.

Правильное решение: использование события ПередЗаписью

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

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


Процедура ПередЗаписью(Отказ, Замещение)
    
    // Если набор записывается пустым (например, при отмене проведения), расчет не требуется
    Если ЭтотОбъект.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

    // Определяем курс валюты заранее до входа в цикл для экономии ресурсов
    КурсВалюты = ПолучитьКурсРеглУчета(ЭтотОбъект.Отбор.Регистратор.Значение);
    
    Если КурсВалюты = 0 Тогда
        Возврат;
    КонецЕсли;

    Для Каждого Движение Из ЭтотОбъект Цикл 
        Движение.СтоимостьРегл = Окр(Движение.СтоимостьБезНДС * КурсВалюты, 2); 
    КонецЦикла;
    
КонецПроцедуры

Обратите внимание: обращение к набору записей внутри его модуля выполняется через контекст ЭтотОбъект. Нет необходимости заново инициализировать объект через СоздатьНаборЗаписей(), устанавливать отборы и вызывать метод Прочитать() — коллекция строк движений уже доступна для обхода.

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

Важнейший нюанс при модификации регистров себестоимости — нагрузка на производительность. Документы перемещения, сборки или реализации могут содержать тысячи строк. Если внутри цикла по строкам набора записей вызывать функции, обращающиеся к регистрам сведений за курсами валют, проведение документов замедлится в десятки раз.

Разберем правила оптимизации при реализации такой логики:

  1. Получение параметров за пределами цикла. Дата проведения документа и курс регламентированного учета должны вычисляться ровно один раз для всего набора записей.
  2. Минимизация блокировок СУБД. Любые длительные вычисления в ПередЗаписью удерживают транзакционную блокировку таблицы регистра, повышая риск взаимных блокировок (deadlocks) в многопользовательской среде.
  3. Округление копеек. Суммовые ресурсы в регламентированном учете должны округляться до копеек функцией Окр(), иначе накопление погрешностей чисел с плавающей точкой нарушит баланс и сходимость отчетов.

Архитектурные риски и последствия прямого вмешательства

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

  1. Рассинхронизация связанных регистров. Данные о себестоимости дублируются и перекрестно сопоставляются с регистрами ВыручкаИСебестоимостьПродаж, ПартииТоваровОрганизаций и ДетализацияСебестоимостиТоваров. Если изменить СтоимостьРегл исключительно в одном регистре, стандартные отчеты «Валовая прибыль предприятия» и «Себестоимость товаров организаций» начнут показывать принципиально разные цифры по одним и тем же операциям.
  2. Конфликт с закрытием месяца. В программе реализован двухэтапный расчет себестоимости: оперативные движения документов и расчетные движения, которые формирует регламентный документ Расчет себестоимости товаров. Если перезаписывать ресурс без фильтрации расчетных движений, алгоритмы закрытия месяца (распределение допрасходов, расчет партий по ФИФО и средней) будут выдавать неустранимые ошибки сходимости и «зависание» остатков сумм без количества. В наборе записей движения закрытия месяца обычно идентифицируются реквизитом РасчетСебестоимости.
  3. Ограничения платформы версий 8.3.8. В платформе 8.3.8 механизм расширений конфигурации еще не позволял перехватывать события модулей наборов записей регистров с помощью аннотаций &Перед, &Вместо или &После. Соответственно, такая доработка требует обязательного снятия регистра с полной поддержки в основной конфигурации.

Альтернативные варианты решения

Проанализируем более надежные способы реализации задачи без риска повреждения структуры учета:

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