Как реализовать массовое закрытие заказов поставщикам в 1С:ERP программно

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

При работе в 1С:ERP Управление предприятием часто возникает ситуация, когда в системе накапливается огромное количество старых документов Заказ поставщику (например, за прошлые периоды 2018–2019 годов), которые по разным причинам не были закрыты вручную. Оставлять их в статусе «К поступлению» или «В работе» нельзя, так как они искажают отчетность, влияют на доступные остатки и создают «шум» в регистрах накопления. В этой статье мы подробно разберем, как автоматизировать процесс закрытия таких заказов с помощью внешней обработки, используя возможности типового механизма конфигурации.

Анализ проблемы: почему нельзя просто изменить статус?

Проанализируем ситуацию: простое программное изменение реквизита Статус в значение Закрыт недостаточно. Документ Заказ поставщику в ERP делает движения по множеству регистров (например, Заказы поставщикам, Расчеты с поставщиками, Движения Номенклатура — Документы заказа). Если заказ выполнен не полностью, ручная смена статуса без корректировки остатков по регистрам приведет к тому, что невыполненные строки «зависнут» в системе как ожидаемые поставки.

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

Шаг 1. Получение списка заказов на сервере

Рассмотрим процедуру получения ссылок на документы, которые подлежат закрытию. Типичная ошибка начинающих разработчиков — попытка передать ДокументОбъект с сервера на клиент. Напомним, что объекты (типа ДокументОбъект.ЗаказПоставщику) существуют только в памяти сервера. На клиент мы должны возвращать только ссылки или массивы ссылок.

Создадим функцию, которая отберет заказы по конкретному менеджеру за определенный период:


&НаСервере
Функция ПолучитьСписокЗаказовДляЗакрытия()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЗаказПоставщику.Ссылка КАК Ссылка
        |ИЗ
        |	Документ.ЗаказПоставщику КАК ЗаказПоставщику
        |ГДЕ
        |	ЗаказПоставщику.Проведен = ИСТИНА
        |	И ЗаказПоставщику.ПометкаУдаления = ЛОЖЬ
        |	И ЗаказПоставщику.Менеджер = &Менеджер
        |	И ЗаказПоставщику.Дата МЕЖДУ &НачалоПериода И &КонецПериода
        |	И ЗаказПоставщику.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказовПоставщикам.Закрыт)";
    
    Запрос.УстановитьПараметр("Менеджер", Справочники.Пользователи.НайтиПоНаименованию("Якушевич Михаил Михайлович"));
    Запрос.УстановитьПараметр("НачалоПериода", НачалоДня('20180101'));
    Запрос.УстановитьПараметр("КонецПериода", КонецДня('20191231'));
    
    РезультатЗапроса = Запрос.Выполнить();
    // Возвращаем массив ссылок, который легко передается на клиент
    Возврат РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции

Шаг 2. Подготовка структуры параметров для помощника закрытия

Выясним, какие параметры ожидает форма Обработка.ПомощникЗакрытияЗаказов.Форма.ФормаЗакрытия. Это ключевой момент, так как от этих флагов зависит логика обработки строк. Разберем основные ключи структуры:

  1. Заказы — СписокЗначений, содержащий ссылки на закрываемые документы.
  2. ОтменитьНеотработанныеСтроки — если Истина, система установит признак отмены для всех строк, по которым не было фактического поступления.
  3. СкорректироватьЦены — полезно, если цена в заказе отличается от цены в фактическом поступлении.
  4. ЗакрыватьЗаказы — финальный флаг, который переведет документ в статус Закрыт.

Посмотрим на реализацию основной клиентской процедуры:


&НаКлиенте
Процедура ЗапуститьМассовоеЗакрытие(Команда)
    
    МассивСсылок = ПолучитьСписокЗаказовДляЗакрытия();
    
    Если МассивСсылок.Количество() = 0 Тогда
        ПоказатьПредупреждение(, "Заказы для закрытия не найдены.");
        Возврат;
    КонецЕсли;
    
    СписокЗаказовКЗакрытию = Новый СписокЗначений;
    СписокЗаказовКЗакрытию.ЗагрузитьЗначения(МассивСсылок);
    
    СтруктураЗакрытия = Новый Структура;
    СтруктураЗакрытия.Вставить("Заказы", СписокЗаказовКЗакрытию);
    // В качестве инициатора можно указать первый заказ из списка или саму обработку
    СтруктураЗакрытия.Вставить("ДокументИнициатор", МассивСсылок[0]); 
    СтруктураЗакрытия.Вставить("ОтменитьНеотработанныеСтроки", Истина);
    СтруктураЗакрытия.Вставить("СкорректироватьЦены", Истина);
    СтруктураЗакрытия.Вставить("ЗакрыватьЗаказы", Истина);
    
    // Открываем типовую форму помощника ERP
    ОткрытьФорму("Обработка.ПомощникЗакрытияЗаказов.Форма.ФормаЗакрытия", 
        СтруктураЗакрытия, 
        ЭтаФорма, 
        Истина, 
        , 
        , 
        Неопределено, 
        РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
        
КонецПроцедуры

Шаг 3. Важные нюансы и решение проблем с записью

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

Проанализируем ситуацию с ошибкой XDTO или ошибкой передачи объекта. Как мы выяснили ранее, никогда не пытайтесь вернуть Выборка.Ссылка.ПолучитьОбъект() из серверной функции на клиент. Если вам нужно провести документ перед закрытием, делайте это строго на сервере в отдельном цикле:


&НаСервере
Процедура ПровестиЗаказыПередЗакрытием(МассивСсылок)
    Для Каждого Ссылка Из МассивСсылок Цикл
        ОбъектДок = Ссылка.ПолучитьОбъект();
        Если Не ОбъектДок.Проведен Тогда
            Попытка
                ОбъектДок.Записать(РежимЗаписиДокумента.Проведение);
            Исключение
                ЗаписьЖурналаРегистрации("МассовоеЗакрытие", УровеньЖурналаРегистрации.Ошибка, , , 
                    "Не удалось провести заказ: " + Ссылка + " Ошибка: " + ОписаниеОшибки());
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Обратите внимание: если вы закрываете документы за 2018–2019 годы, скорее всего, период редактирования закрыт. В этом случае обычная запись не сработает. Вам потребуется либо временно открыть период (что не всегда возможно в рабочей базе), либо использовать специализированные методы обхода проверок, однако использование типового Помощника закрытия все равно инициирует стандартные механизмы проведения, поэтому контроль дат запрета остается обязательным условием.

Дополнительные параметры помощника

Рассмотрим более детально, что еще можно передать в структуру закрытия для более тонкой настройки процесса в 1С:ERP:

Рекомендации по оптимизации

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

  1. Разбивать массив ссылок на порции (пакеты) по 50–100 документов.
  2. Использовать фоновые задания для обработки, чтобы пользователь не ждал завершения процесса.
  3. Вместо открытия формы использовать программный вызов серверного метода закрытия, если архитектура конфигурации это позволяет (например, метод ЗакрытиеЗаказовСервер.ЗакрытьЗаказы() в последних версиях ERP).

Подводя итог, можно сказать, что использование типового помощника закрытия через ОткрытьФорму с подготовленной структурой параметров — это самый безопасный способ массового приведения базы 1С:ERP в порядок, так как он гарантирует соблюдение всей бизнес-логики, заложенной вендором.

← На главную