Почему не устанавливается цена в табличной части управляемой формы 1С 8.3 и как это исправить?

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

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

Но при запуске кода вы сталкиваетесь с неприятным сюрпризом: документ открывается, номенклатура и количество на месте, а вот поле цены остается пустым или сбрасывается в ноль. Метод Обновить() не помогает, ручной пересчет не запускается. Почему так происходит и как заставить платформу корректно работать с ценами? Давайте подробно разберем эту проблему и изучим правильные архитектурные подходы к её решению.

Выясняем причину: почему очищается цена?

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

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

Прямое заполнение элементов коллекции ДанныеФормыКоллекция (которой и является Форма.Товары) на клиенте до открытия формы — это обход объектной техники 1С, который часто приводит к подобным багам. Давайте рассмотрим три правильных и безопасных способа заполнения данных.

Способ 1. Использование параметров заполнения (ЗначенияЗаполнения)

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

Разберем по шагам, как реализовать этот метод в коде нашей внешней обработки:


&НаКлиенте
Процедура ЗаполнитьИОткрытьДокумент(Команда)

    // Шаг 1. Создаем массив строк табличной части
    МассивСтрок = Новый Массив;
    
    // Шаг 2. Формируем структуру данных для каждой строки
    СтрокаТовара = Новый Структура;
    СтрокаТовара.Вставить("Номенклатура", ПредопределенноеЗначение("Справочник.Номенклатура.ПустаяСсылка")); // Замените на реальную ссылку
    СтрокаТовара.Вставить("Количество", 10);
    СтрокаТовара.Вставить("Цена", 1000);
    СтрокаТовара.Вставить("Сумма", 10000); // Рекомендуется сразу рассчитать сумму самостоятельно
    
    МассивСтрок.Добавить(СтрокаТовара);
    
    // Шаг 3. Упаковываем данные ТЧ в структуру параметров заполнения
    ПараметрыЗаполнения = Новый Структура;
    ПараметрыЗаполнения.Вставить("Товары", МассивСтрок);
    
    // Шаг 4. Передаем параметры в форму через стандартное свойство "ЗначенияЗаполнения"
    ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
    
    // Шаг 5. Открываем форму
    ОткрытьФорму("Документ.ПоступлениеТоваров.Форма.ФормаДокумента", ПараметрыФормы);

КонецПроцедуры

При таком подходе платформа применит параметры к создаваемому объекту на сервере. В модуле объекта документа сработает предопределенный обработчик ОбработкаЗаполнения, который корректно перенесет данные в документ до начала построения интерфейса формы. Это гарантирует, что алгоритмы ценообразования не сбросят ваши данные.

Способ 2. Передача данных через временное хранилище

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

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


&НаКлиенте
Процедура ОткрытьЧерезХранилище(Команда)
    
    // Получаем адрес временного хранилища с заполненной таблицей
    АдресДанных = ПодготовитьДанныеНаСервере();
    
    // Передаем адрес в параметры открываемой формы
    ПараметрыФормы = Новый Структура("АдресДанныхЗаполнения", АдресДанных);
    ОткрытьФорму("Документ.ПоступлениеТоваров.Форма.ФормаДокумента", ПараметрыФормы);
    
КонецПроцедуры

&НаСервере
Функция ПодготовитьДанныеНаСервере()
    
    // Создаем таблицу значений с нужной структурой колонок
    ТаблицаТоваров = Новый ТаблицаЗначений;
    ТаблицаТоваров.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
    ТаблицаТоваров.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
    ТаблицаТоваров.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
    ТаблицаТоваров.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
    
    // Наполняем таблицу данными
    НоваяСтрока = ТаблицаТоваров.Добавить();
    НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("10000001");
    НоваяСтрока.Количество = 10;
    НоваяСтрока.Цена = 1000;
    НоваяСтрока.Сумма = 10000;
    
    // Помещаем таблицу во временное хранилище
    Возврат ПоместитьВоВременноеХранилище(ТаблицаТоваров, УникальныйИдентификатор);
    
КонецФункции

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем, передан ли наш параметр с адресом данных
    Если Параметры.Свойство("АдресДанныхЗаполнения") Тогда
        ТаблицаТоваров = ПолучитьИзВременногоХранилища(Параметры.АдресДанныхЗаполнения);
        // Загружаем данные напрямую в объект формы
        Объект.Товары.Загрузить(ТаблицаТоваров);
    КонецЕсли;
    
КонецПроцедуры

Способ 3. Создание и запись документа на сервере (Самый надежный способ)

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

Посмотрим на пример реализации этого сценария:


&НаКлиенте
Процедура СоздатьИОткрытьЗаписанный(Команда)
    
    // Создаем документ на сервере и получаем его ссылку
    СсылкаНаНовыйДокумент = СоздатьДокументНаСервере();
    
    Если ЗначениеЗаполнено(СсылкаНаНовыйДокумент) Тогда
        // Формируем параметры для открытия существующего документа
        ПараметрыФормы = Новый Структура("Ключ", СсылкаНаНовыйДокумент);
        ОткрытьФорму("Документ.ПоступлениеТоваров.Форма.ФормаДокумента", ПараметрыФормы);
    Иначе
        ВызватьИсключение "Не удалось создать документ на сервере!";
    EndIf;
    
КонецПроцедуры

&НаСервере
Функция СоздатьДокументНаСервере()
    
    // Инициализируем объект документа
    НовыйДокумент = Документы.ПоступлениеТоваров.СоздатьДокумент();
    
    // Заполняем реквизиты шапки (Крайне важно для отработки алгоритмов ценообразования!)
    НовыйДокумент.Дата = ТекущаяДата();
    НовыйДокумент.Организация = Справочники.Организации.НайтиПоРеквизиту(...);
    НовыйДокумент.Контрагент = Справочники.Контрагенты.НайтиПоКоду(...);
    НовыйДокумент.ДоговорКонтрагента = Справочники.ДоговорыКонтрагентов.НайтиПоРеквизиту(...);
    
    // Заполняем табличную часть напрямую в объекте
    НоваяСтрока = НовыйДокумент.Товары.Добавить();
    НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("10000001");
    НоваяСтрока.Количество = 10;
    НоваяСтрока.Цена = 1000;
    НоваяСтрока.Сумма = 10000;
    
    // Для конфигураций Альфа-Авто и ERP-систем рекомендуется вызывать внутреннее API
    // для корректного пересчета налогов (НДС), скидок и итогов:
    // ОбработкаТабличныхЧастей.РассчитатьСуммуТабличнойЧасти(НовыйДокумент, "Товары");
    
    Попытка
        НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
        Возврат НовыйДокумент.Ссылка;
    Исключение
        ЗаписьЖурналаРегистрации("ПрограммноеСозданиеДокумента", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

Преимущества данного метода: документ создается строго в соответствии с метаданными. Отрабатывают все подписки на события, процедуры модуля объекта ПередЗаписью и ПриЗаписи. Когда пользователь увидит форму документа на своем экране, все цены, суммы и ставки налогов гарантированно будут рассчитаны верно и не сбросятся в процессе визуализации формы.

Резюме

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

Используйте Способ 1 (Параметры заполнения) для создания чистых, еще незаписанных документов. Применяйте Способ 2 (Временное хранилище) при сложной структуре передаваемых коллекций. И отдавайте предпочтение Способу 3 (Создание на сервере с записью), если работаете со сложными отраслевыми конфигурациями вроде «Альфа-Авто» или ERP, где ценообразование и расчет налогов сильно завязаны на проведение документа и проверку прав доступа.

← На главную