Как загрузить данные в подчиненный регистр сведений из Excel в 1С

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

Разберем частую задачу, с которой сталкиваются разработчики и администраторы 1С: как правильно загрузить данные из файла Excel в регистр сведений (например, СостоянияОСОрганизаций). Зачастую при попытке использовать стандартные обработки пользователи сталкиваются с тем, что программа просто не видит нужный регистр. А при попытке написать свой код — данные записываются с ошибками, затирая уже существующие строки.

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

Почему регистр не виден для стандартных загрузчиков?

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

  1. Независимые регистры — записи в них существуют сами по себе, их можно добавлять, изменять и удалять напрямую.
  2. Подчиненные регистратору — записи в таких регистрах (движения) жестко привязаны к документу, который их создал. Без документа-регистратора запись существовать не может.

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

Типовой метод загрузки (без написания кода)

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

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

  1. Если вы работаете в конфигурациях 1С:ERP, Управление торговлей (УТ) или Комплексная автоматизация (КА), создайте новый документ КорректировкаЗаписейРегистров.
  2. Если ваша база — 1С:Бухгалтерия предприятия, создайте документ ОперацияБух (в интерфейсе он называется «Операции, введенные вручную»).
  3. В настройках созданного документа (кнопка «Выбор регистров») отметьте галочкой нужный регистр сведений — «Состояния ОС организации».
  4. После подтверждения в форме документа появится новая вкладка с табличной частью выбранного регистра.
  5. Теперь вы можете использовать любую стандартную обработку (например, «Загрузка данных из табличного документа») для заполнения этой конкретной табличной части из вашего файла Excel.

Этот метод абсолютно безопасен, оставляет прозрачный след в системе (всегда видно, каким документом внесены изменения) и не требует вмешательства программиста.

Программное добавление записей: исправляем частую ошибку

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

Часто начинающие программисты пишут алгоритм, устанавливают отбор по регистратору, добавляют строку и вызывают метод Записать(). Но при тестировании обнаруживается критическая проблема: обработка добавляет одну новую запись, но при этом безвозвратно удаляет все остальные движения этого документа в регистре.

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

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


&НаСервере
Процедура ЗагрузитьДанныеВРегистрСервер(ВыборкаИзExcel, СсылкаНаДокумент, ОсновноеСредство, ДатаСостояния)
    
    // Создаем объект набора записей нужного регистра
    НаборЗаписей = РегистрыСведений.СостоянияОСОрганизаций.СоздатьНаборЗаписей();
    
    // Устанавливаем отбор по документу-регистратору
    НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
    
    // КРИТИЧЕСКИ ВАЖНЫЙ ШАГ: Читаем уже имеющиеся движения из базы данных!
    НаборЗаписей.Прочитать(); 
    
    // Теперь добавляем новую запись к уже существующим в коллекции
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.Период = ВыборкаИзExcel.Период;
    НоваяЗапись.Организация = ВыборкаИзExcel.Организация;
    НоваяЗапись.ОсновноеСредство = ОсновноеСредство;
    НоваяЗапись.ДатаСостояния = ДатаСостояния;
    НоваяЗапись.Состояние = ВыборкаИзExcel.Состояние;
    НоваяЗапись.Регистратор = СсылкаНаДокумент;
    
    // Записываем обновленный набор, заменяя старый (но со всеми сохраненными строками)
    НаборЗаписей.Записать(Истина);
    
КонецПроцедуры

Альтернативный вариант: передать в метод записи параметр Ложь — НаборЗаписей.Записать(Ложь). В этом случае чтение можно пропустить, платформа просто допишет данные к существующим. Однако использование метода Прочитать() является более гибким и надежным подходом, так как позволяет вам проверить имеющиеся строки на дубликаты перед добавлением новых элементов.

Восстановление записей в закрытом периоде

Разберем еще одну проблему. Что делать, если из-за ошибки в коде движения документа были удалены, а сам документ находится в прошлом году? Бухгалтерский период давно закрыт, установлена дата запрета редактирования данных, и перепровести документ обычным способом 1С не позволит.

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

Для этого в 1С существует специальное свойство ОбменДанными.Загрузка. Если установить его в значение Истина, платформа отключает большинство проверок, включая контроль даты запрета изменения и вызов платформных обработчиков бизнес-логики.

Посмотрим, как это выглядит в коде:


НаборЗаписей = РегистрыСведений.СостоянияОСОрганизаций.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокументЗакрытогоПериода);

// Формируем нужные записи для восстановления
Запись = НаборЗаписей.Добавить();
Запись.Регистратор = СсылкаНаДокументЗакрытогоПериода;
// ... заполняем остальные измерения и ресурсы (Организация, ОсновноеСредство и т.д.) ...

// Включаем режим загрузки для обхода проверок закрытого периода
НаборЗаписей.ОбменДанными.Загрузка = Истина;

// Выполняем запись движений без перепроведения самого документа
НаборЗаписей.Записать();

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

Оптимизация массовой загрузки данных из Excel

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

Проанализируем производительность. Если в файле окажется десять строк для одного и того же документа-регистратора, построчная обработка заставит базу данных десять раз прочитать набор и десять раз перезаписать его. Это приведет к огромным затратам серверного времени и сильным "тормозам" при загрузке.

Разберем по шагам правильный алгоритм массовой загрузки:

  1. Прочитайте все данные из файла Excel и поместите их во внутренний объект ТаблицаЗначений.
  2. Сгруппируйте данные в таблице. Создайте копию таблицы и вызовите метод Свернуть("Регистратор"), чтобы получить уникальный список документов, для которых нужно создать движения.
  3. Запустите главный цикл перебора по этой свернутой таблице уникальных регистраторов.
  4. Внутри цикла создайте набор записей и установите отбор по текущему регистратору. Обязательно вызовите метод Прочитать().
  5. Затем с помощью метода НайтиСтроки() отберите из исходной большой таблицы значений все строки, относящиеся только к этому регистратору.
  6. Во внутреннем цикле переберите эти найденные строки и добавьте их в прочитанный набор записей с помощью НаборЗаписей.Добавить().
  7. После завершения внутреннего цикла вызовите НаборЗаписей.Записать(Истина).

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

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

← На главную