В практике разработчика 1С часто возникает задача массового обновления данных в существующих документах. Типичный сценарий: менеджер предоставляет файл Excel со списком номеров накладных или заказов, в которых необходимо изменить определенный реквизит, например, торгового представителя или склад. В этой статье мы подробно разберем, как реализовать такую обработку для обычных форм, проанализируем типичные ошибки начинающих программистов и изучим лучшие практики работы с объектами базы данных.
Первым делом нам необходимо сопоставить данные из файла Excel с объектами в базе данных 1С. Основным идентификатором в таких случаях выступает номер документа. Разберем ситуацию: мы загрузили данные из Excel в таблицу значений ТабличноеПоле. Теперь нам нужно обойти эту таблицу и найти ссылки на соответствующие документы.
Для поиска мы будем использовать метод НайтиПоНомеру(). Рассмотрим пример кода, который часто используется в подобных обработках:
Для Каждого СтрокаТЗ Из ТабличноеПоле Цикл
// Номер из Excel может содержать лишние пробелы, поэтому используем СокрЛП
НомерДокумента = СокрЛП(СтрокаТЗ.Номер);
// Поиск документа ЗаказПокупателя
// Если нумерация периодическая (например, в пределах года), важно указать дату
ДокументСсылка = Документы.ЗаказПокупателя.НайтиПоНомеру(НомерДокумента, Дата('20190101'));
Если Не ДокументСсылка.Пустая() Тогда
Сообщить("Документ найден: " + ДокументСсылка);
Иначе
Сообщить("Документ с номером " + НомерДокумента + " не найден!");
КонецЕсли;
КонецЦикла;
Проанализируем метод НайтиПоНомеру(Номер, Дата). Если в конфигурации для данного типа документа установлено свойство Периодичность (например, "Год"), то поиск без указания второго параметра может вернуть пустую ссылку, даже если документ с таким номером существует. Параметр Дата указывает системе, в каком интервале времени (периоде уникальности номеров) искать документ. Если номера уникальны в пределах года, достаточно передать любую дату из нужного года.
Важный момент: часто номера в Excel не содержат лидирующих нулей или префиксов, которые есть в 1С (например, в файле "22172", а в базе "А0000022172"). В таких случаях поиск НайтиПоНомеру не сработает напрямую. Нам придется либо программно дополнять номер нулями, либо использовать запрос для поиска по правой части номера.
Найденная переменная ДокументСсылка является ссылкой. Ссылки в 1С предназначены только для чтения данных. Чтобы изменить значение реквизита, нам необходимо получить объект документа. Рассмотрим, как правильно это сделать и изменить торгового представителя:
Если Не ДокументСсылка.Пустая() Тогда
// Получаем объект для редактирования
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
// Предположим, новый торговый представитель указан в Excel строкой (ФИО)
// Нам нужно найти ссылку на него в справочнике
ТТ_Ссылка = Справочники.ФизическиеЛица.НайтиПоНаименованию(СокрЛП(СтрокаТЗ.Агент));
Если Не ТТ_Ссылка.Пустая() Тогда
ДокументОбъект.ТорговыйПредставитель = ТТ_Ссылка;
// Переходим к записи и проведению
Попытка
// Сначала просто записываем изменения
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
// Пытаемся провести документ, если он был проведен ранее
Если ДокументОбъект.Проведен Тогда
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЕсли;
Исключение
Сообщить("Ошибка при записи документа " + НомерДокумента + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
Выясним причину использования блока Попытка...Исключение. Проведение документа — это сложная операция, которая может сорваться из-за отсутствия остатков на складе, превышения лимита задолженности или блокировок со стороны других пользователей. Использование "попытки" гарантирует, что ваша обработка не остановится на середине списка из-за одной ошибки, а продолжит работу с остальными документами.
Выполнение поиска НайтиПоНомеру внутри цикла по тысячам строк может существенно замедлить работу системы, так как на каждой итерации происходит отдельный запрос к базе данных. Проанализируем более профессиональный подход — использование временных таблиц.
Такой подход позволяет найти все необходимые документы за одно обращение к серверу БД, что в десятки раз быстрее циклического поиска.
При массовом изменении документов стоит придерживаться нескольких правил, которые помогут избежать порчи данных:
1. Использование режима загрузки данных. Если вам нужно просто сменить реквизит, не вызывая при этом тяжелые механизмы проверки бизнес-логики (подписки на события, проверки остатков), используйте свойство ОбменДанными.Загрузка.
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.ОбменДанными.Загрузка = Истина;
ДокументОбъект.ТорговыйПредставитель = НовыйАгент;
ДокументОбъект.Записать();
Это позволит изменить реквизит даже в тех документах, которые "не хотят" проводиться в текущем периоде из-за изменившихся настроек учета.
2. Проверка на идентичность. Перед записью всегда проверяйте, действительно ли новое значение отличается от старого. Нет смысла записывать и перепроводить документ, если в нем уже указан правильный торговый представитель. Это сэкономит время и уменьшит размер логов транзакций.
Если ДокументОбъект.ТорговыйПредставитель <> ТТ_Ссылка Тогда
ДокументОбъект.ТорговыйПредставитель = ТТ_Ссылка;
ДокументОбъект.Записать();
КонецЕсли;
3. Типизация данных. Помните, что реквизиты в 1С имеют строгую типизацию. Если реквизит ТорговыйПредставитель имеет тип СправочникСсылка.ФизическиеЛица, вы не можете присвоить ему просто строку из Excel. Обязательно выполните поиск ссылки в справочнике, прежде чем присваивать значение объекту документа.
Подведем итог: программное изменение реквизитов требует внимательного отношения к типам данных, периодам нумерации и обработке исключительных ситуаций. Рассмотренные нами методы позволяют создать надежный инструмент для автоматизации рутинных операций в учетных системах на базе 1С.