В процессе работы с конфигурацией 1С:Управление торговлей (ред. 11) программисты часто сталкиваются с необходимостью доработки типовых механизмов, которые работают некорректно или недостаточно быстро. В рамках данной статьи мы разберем несколько практических кейсов: исправление ошибки заполнения серий при вводе Реализации товаров и услуг на основании Возврата товаров от клиента, подходы к созданию многопоточных обработок и нюансы работы с Перечислениями при импорте данных.
Одной из часто встречающихся проблем в типовой УТ 11 является ситуация, когда при создании документа РеализацияТоваровУслуг на основании документа ВозвратТоваровОтКлиента серии товаров не переносятся автоматически, хотя в исходном документе они указаны. Рассмотрим решение, реализованное через механизм расширений с использованием аннотации &Вместо для процедуры ЗаполнитьДокументНаОснованииВозвратаТоваровОтКлиента.
Проанализируем алгоритм исправления. Суть заключается в том, чтобы программно извлечь данные о сериях из документа-основания и корректно распределить их по строкам нового документа. Для этого используется структура запроса к табличным частям Товары и Серии исходного документа ВозвратТоваровОтКлиента.
Разберем по шагам код реализации этого механизма:
&Вместо("ЗаполнитьДокументНаОснованииВозвратаТоваровОтКлиента")
Процедура АР_ЗаполнитьДокументНаОснованииВозвратаТоваровОтКлиента(Знач ДокументОснование)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ДокументОснование", ДокументОснование);
Запрос.Текст =
"ВЫБРАТЬ
| ВозвратТоваровОтКлиента.Ссылка КАК Ссылка,
| ВозвратТоваровОтКлиента.Организация КАК Организация,
| ВозвратТоваровОтКлиента.Партнер КАК Партнер,
| ВозвратТоваровОтКлиента.Склад КАК Склад,
| ВозвратТоваровОтКлиента.Товары.(
| Номенклатура, Характеристика, Упаковка, КоличествоУпаковок, Количество,
| Цена, Сумма, СтавкаНДС, СуммаНДС, Склад, Серия, СтатусУказанияСерий
| ) КАК Товары,
| ВозвратТоваровОтКлиента.Серии.(
| Номенклатура, Характеристика, Серия, Количество
| ) КАК Серии
|ИЗ
| Документ.ВозвратТоваровОтКлиента КАК ВозвратТоваровОтКлиента
|ГДЕ
| ВозвратТоваровОтКлиента.Ссылка = &ДокументОснование";
Выборка = Запрос.Выполнить().Выбрать();
Если Не Выборка.Следующий() Тогда
Возврат;
КонецЕсли;
// Проверка возможности ввода на основании через типовой механизм БСП
ОбщегоНазначенияУТ.ПроверитьВозможностьВводаНаОсновании(Выборка.Ссылка);
// Заполнение реквизитов шапки
ЗаполнитьЗначенияСвойств(ЭтотОбъект, Выборка);
// Работа с табличной частью Товары и Серии
ТоварыОснования = Выборка.Товары.Выгрузить();
СерииОснования = Выборка.Серии.Выгрузить();
ИндексыСтрок = Новый Массив();
Для Каждого СтрокаТовары Из ТоварыОснования Цикл
// СтатусУказанияСерий = 10 означает, что серии указаны в ТЧ Серии
Если СтрокаТовары.СтатусУказанияСерий = 10 Тогда
ИндексыСтрок.Добавить(ТоварыОснования.Индекс(СтрокаТовары));
КонецЕсли;
КонецЦикла;
Если ИндексыСтрок.Количество() > 0 Тогда
КлючСерии = "Номенклатура, Характеристика, Склад";
// Вызов серверного метода для сопоставления серий
ОбеспечениеСервер.ПеренестиСерииИзТаблицыВСтроки(ТоварыОснования, ИндексыСтрок, СерииОснования, КлючСерии);
КонецЕсли;
ЭтотОбъект.Товары.Загрузить(ТоварыОснования);
// Загрузка ТЧ Серии, если она используется в документе
Для Каждого СтрокаСерии Из СерииОснования Цикл
НоваяСтрока = ЭтотОбъект.Серии.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаСерии);
НоваяСтрока.Склад = Выборка.Склад;
КонецЦикла;
КонецПроцедуры
Важно отметить, что в данном примере мы используем метод ОбеспечениеСервер.ПеренестиСерииИзТаблицыВСтроки. Это штатная функция 1С, которая автоматизирует процесс распределения серий из вспомогательной таблицы в основную таблицу товаров. Это позволяет избежать написания сложных циклов перебора и ручного сопоставления остатков по сериям.
Рассмотрим ситуацию, когда необходимо выполнить массовое перепроведение документов или изменение реквизитов в базе объемом несколько сотен гигабайт. Типовые последовательные обработки могут выполняться часами. Выясним, как ускорить этот процесс с помощью многопоточности.
Основные принципы многопоточности в 1С:
UUID.ФоновыеЗадания.Выполнить().Проанализируем пример логики запуска многопоточной обработки:
Процедура ЗапуститьОбработкуВПотоках(МассивДокументов)
МаксимальноеКоличествоПотоков = 8;
ПорцияДанных = Цел(МассивДокументов.Количество() / МаксимальноеКоличествоПотоков);
Для НомерПотока = 1 По МаксимальноеКоличествоПотоков Цикл
НачальныйИндекс = (НомерПотока - 1) * ПорцияДанных;
КонечныйИндекс = ?(НомерПотока = МаксимальноеКоличествоПотоков, МассивДокументов.Количество() - 1, НомерПотока * ПорцияДанных - 1);
ТекущаяПорция = Новый Массив;
Для и = НачальныйИндекс По КонечныйИндекс Цикл
ТекущаяПорция.Добавить(МассивДокументов[и]);
КонецЦикла;
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(ТекущаяПорция);
ФоновыеЗадания.Выполнить("МойОбщийМодуль.ОбработатьПорциюДанных", ПараметрыЗадания);
КонецЦикла;
КонецПроцедуры
Как показывает практика, использование 8–10 потоков на современных серверных мощностях позволяет увеличить скорость обработки данных в 5–8 раз. Однако следует учитывать Блокировки на уровне СУБД, особенно при записи в регистры бухгалтерии или регистры накопления с высокой нагрузкой.
Разберем типичную ошибку начинающих разработчиков при попытке загрузить данные из внешних файлов (Excel, CSV). Часто возникает проблема при заполнении реквизитов типа ПеречислениеСсылка и поиске существующих объектов.
Посмотрим на пример правильной логики сопоставления ставки НДС при создании новой номенклатуры. Вместо прямого присваивания числа или строки, необходимо обращаться к метаданным перечисления:
Если СтрокаДанных.СтавкаНДС = "20%" Тогда
НоваяПозиция.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;
ИначеЕсли СтрокаДанных.СтавкаНДС = "10%" Тогда
НоваяПозиция.СтавкаНДС = Перечисления.СтавкиНДС.НДС10;
Иначе
НоваяПозиция.СтавкаНДС = Перечисления.СтавкиНДС.БезНДС;
КонецЕсли;
При поиске существующих элементов справочника Номенклатура важно использовать метод НайтиПоНаименованию или НайтиПоРеквизиту с осторожностью, учитывая уникальность. Разберем пример безопасного поиска и обновления реквизитов:
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
НайденнаяСсылка = Справочники.Номенклатура.НайтиПоНаименованию(СтрокаДанных.Наименование, Истина);
Если НайденнаяСсылка.Пустая() Тогда
ОбъектНоменклатуры = Справочники.Номенклатура.СоздатьЭлемент();
ОбъектНоменклатуры.Наименование = СтрокаДанных.Наименование;
Иначе
ОбъектНоменклатуры = НайденнаяСсылка.ПолучитьОбъект();
КонецЕсли;
// Корректное заполнение перечисления через условие или соответствие
Если СтрокаДанных.СтавкаНДСЧислом = 20 Тогда
ОбъектНоменклатуры.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;
КонецЕсли;
ОбъектНоменклатуры.Записать();
КонецЦикла;
Полезный совет: Для повышения производительности при массовой загрузке рекомендуется использовать ЗагрузитьВременнуюТаблицу и выполнять поиск соответствий одним запросом ко всей базе, вместо выполнения поиска в цикле. Это существенно сокращает количество обращений к базе данных.
Мы проанализировали ситуацию с программным исправлением типовых механизмов 1С и выяснили, что даже небольшие изменения в процедурах заполнения документов могут значительно упростить работу пользователей. Использование расширений позволяет сохранить конфигурацию на поддержке, а внедрение многопоточности и правильная работа с объектами метаданных (такими как Перечисления) обеспечивают стабильность и высокую производительность системы.