При переносе данных или начальной настройке конфигураций на платформе «1С:Предприятие 8.3» (таких как «1С:Управление торговлей 11», «1С:Комплексная автоматизация 2» или «1С:ERP») разработчики часто сталкиваются с неожиданным поведением: документ ВводОстатков создается, в отладчике строки табличной части заполняются, но после выполнения метода Записать() или при открытии формы табличная часть оказывается абсолютно пустой. Рассмотрим подробно, почему так происходит, какие скрытые механизмы конфигурации очищают данные и как правильно написать алгоритм создания документа.
В современных типовых конфигурациях документ ВводОстатков является универсальным инструментом, объединяющим учет по десяткам направлений: собственные товары, взаиморасчеты, основные средства, кассы и другие. Для каждого раздела учета в структуре метаданных документа предусмотрены свои табличные части и реквизиты.
В модуле объекта документа в процедуре-обработчике ПередЗаписью заложен алгоритм контроля целостности данных. Если ключевой реквизит операции не заполнен или заполнен некорректно, система считает строки чужими и принудительно очищает все табличные части, не соответствующие выбранному направлению. В результате в момент вызова Док.Записать() табличная часть Товары попросту стирается типовым кодом конфигурации.
В зависимости от версии конфигурации имя реквизита и состав перечисления могут различаться:
ХозяйственнаяОперация, принимающий значение Перечисления.ХозяйственныеОперации.ВводОстатковСобственныхТоваров.ТипОперации со значением Перечисления.ТипыОперацийВводаОстатков.ОстаткиСобственныхТоваров.РазделУчета со значением Перечисления.РазделыУчетаДляВводаОстатков.СобственныеТовары.Перед заполнением табличной части обязательно проверим состав реквизитов документа в дереве метаданных конфигуратора и укажем требуемый тип операции в шапке документа.
Еще одна распространенная проблема связана с разделением логики на клиентскую и серверную части в управляемом приложении. Нередко разработчик успешно записывает документ на сервере, но при попытке показать его пользователю открывает пустую форму. Выясним, почему это происходит:
ОткрытьФорму() передается структура с произвольным ключом (например, Новый Структура("СобственныеТовары", Ссылка)), платформа не понимает, какой объект требуется открыть. В управляемых формах для передачи ссылки зарезервирован строго определенный параметр Ключ. Если он не задан, форма инициализируется как новый, несохраненный объект.Форма.Объект и копировать данные формы без записи объекта приводят к рассинхронизации данных. Надежнее всего создавать, полностью заполнять и записывать документ на сервере, а на клиент возвращать только готовую ссылку.При использовании процедуры ЗаполнитьЗначенияСвойств() крайне важно, чтобы псевдонимы полей в запросе точно совпадали с именами реквизитов табличной части документа. Например, если в запросе указано КоличествоОстаток КАК Колво, а в табличной части реквизит называется Количество, поле останется пустым.
Кроме того, при получении остатков из регистра ПартииТоваровОрганизаций поле СтоимостьОстаток отражает общую себестоимость партии, а не цену за единицу товара. Если просто присвоить значение стоимости полю Цена, данные по остаткам будут искажены. Также следует учитывать, что измерение АналитикаУчетаНоменклатуры может содержать не только ссылку на номенклатуру, но и характеристики со складами, поэтому при выборке важно производить группировку или использовать специализированный регистр ТоварыНаСкладах.
Разберем готовый шаблон внешней обработки, который корректно формирует документ ввода остатков собственных товаров, заполняет обязательные реквизиты шапки, рассчитывает цену и открывает созданный документ на клиенте.
&НаКлиенте
Процедура СоздатьИОткрытьДокумент(Команда)
// Создаем и записываем документ на сервере
СсылкаНаДокумент = СоздатьВводОстатковНаСервере();
Если ЗначениеЗаполнено(СсылкаНаДокумент) Тогда
// Способ 1: Открытие через стандартный параметр формы "Ключ"
ПараметрыОткрытия = Новый Структура("Ключ", СсылкаНаДокумент);
ОткрытьФорму("Документ.ВводОстатков.Форма.ФормаТовары", ПараметрыОткрытия);
// Способ 2 (альтернативный): Быстрое открытие значения
// ОткрытьЗначение(СсылкаНаДокумент);
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СоздатьВводОстатковНаСервере()
ДокОбъект = Документы.ВводОстатков.СоздатьДокумент();
// 1. Заполняем обязательные реквизиты шапки
ДокОбъект.Дата = ТекущаяДата();
// В зависимости от версии конфигурации активируем нужный вид операции:
ДокОбъект.ХозяйственнаяОперация = Перечисления.ХозяйственныеОперации.ВводОстатковСобственныхТоваров;
// Для более старых релизов:
// ДокОбъект.ТипОперации = Перечисления.ТипыОперацийВводаОстатков.ОстаткиСобственныхТоваров;
// Обязательные аналитики шапки (без них проведение документа будет заблокировано)
// ДокОбъект.Организация = Справочники.Организации.НайтиПоНаименованию("Основная организация");
// ДокОбъект.Склад = Справочники.Склады.НайтиПоНаименованию("Основной склад");
// 2. Формируем запрос к остаткам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Партии.АналитикаУчетаНоменклатуры.Номенклатура КАК Номенклатура,
| СУММА(Партии.КоличествоОстаток) КАК Количество,
| СУММА(Партии.СтоимостьОстаток) КАК Сумма
|ИЗ
| РегистрНакопления.ПартииТоваровОрганизаций.Остатки(
| ,
| Организация = &Организация) КАК Партии
|
|СГРУППИРОВАТЬ ПО
| Партии.АналитикаУчетаНоменклатуры.Номенклатура
|
|ИМЕЮЩИЕ
| СУММА(Партии.КоличествоОстаток) > 0";
Запрос.УстановитьПараметр("Организация", ДокОбъект.Организация);
Выборка = Запрос.Выполнить().Выбрать();
// 3. Заполняем табличную часть документа
Пока Выборка.Следующий() Цикл
НоваяСтрока = ДокОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = Выборка.Номенклатура;
НоваяСтрока.Количество = Выборка.Количество;
НоваяСтрока.Сумма = Выборка.Сумма;
// Корректный расчет цены единицы товара
Если Выборка.Количество <> 0 Тогда
НоваяСтрока.Цена = Окр(Выборка.Сумма / Выборка.Количество, 2);
Иначе
НоваяСтрока.Цена = 0;
КонецЕсли;
КонецЦикла;
// 4. Записываем объект
Попытка
// Использование режима проведения позволяет сразу увидеть ошибки заполнения
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Возврат ДокОбъект.Ссылка;
Исключение
Сообщить("Ошибка при сохранении документа: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Если задача заключается в разовом переносе номенклатуры и остатков из другой базы, писать отдельную обработку не обязательно. Рассмотрим типовые средства платформы, которые решают задачу быстрее и надежнее:
Ввод остатков над табличной частью Товары присутствует штатная кнопка «Загрузить из внешнего файла». Достаточно выгрузить отчет по остаткам из старой базы в Excel или табличный документ, скопировать строки в буфер обмена и сопоставить колонки (номенклатура, количество, цена/сумма).