Перепроведение документов 1С — повторное проведение уже проведённых документов: платформа заново формирует их движения в регистрах. Оно нужно, когда документы верные, а движения устарели. Ниже — где найти групповое перепроведение в БП 3.0, УТ 11, КА, ERP и ЗУП, чем оно опасно для закрытых периодов и как написать свою обработку: хронологическая выборка, порции в транзакциях, журнал ошибок, отмена проведения, замер скорости.
Перепроводят, если документ в базе правильный, а его движения — нет:
Риски:
| Конфигурация | Где найти | Что учесть |
|---|---|---|
| БП 3.0 | Операции → Сервис → Групповое перепроведение документов | Отбор по периоду и организации. При нарушенной последовательности помощник «Закрытие месяца» сам предлагает пункт «Перепроведение документов за месяц»; если перепроведение точно не нужно, операцию пропускают. |
| УТ 11, КА 2, ERP 2 | Отдельной обработки нет: Все функции → Стандартные → Проведение документов либо выделить документы в списке и нажать «Провести» | Последовательностей нет: изменения прошлых периодов попадают в «Задания к закрытию месяца», пересчёт делает закрытие месяца, а перепроводят документы, на которые указали его проверки. |
| ЗУП 3, зарплата в КА и ERP | Обработка «Проведение документов по видам учета» | Перепроводит зарплатные документы только по выбранному учёту, например «Учет среднего заработка». |
| Любая конфигурация на 8.3 | Все функции → Стандартные → Проведение документов | Стандартная обработка платформы, работает и в самописных базах. |
Команду «Все функции» включают в параметрах программы: главное меню → «Сервис» → «Параметры» → флажок «Отображать команду "Все функции"».
Своя обработка нужна, когда типовой нет или требуется отбор, которого она не умеет: по складу, автору, списку видов. Создайте внешнюю обработку с управляемой формой — весь код ниже размещается в модуле формы. Сначала выборка документов одного вида:
// Модуль формы внешней обработки «Перепроведение документов».
&НаСервереБезКонтекста
Функция ДокументыОдногоВида(ИмяДокумента, НачалоПериода, КонецПериода, Проведенные)
Если Метаданные.Документы.Найти(ИмяДокумента) = Неопределено Тогда
ВызватьИсключение СтрШаблон("В конфигурации нет документа ""%1""", ИмяДокумента);
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = СтрШаблон(
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.%1 КАК Док
|ГДЕ
| Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Док.Проведен = &Проведен
| И НЕ Док.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Док.МоментВремени", ИмяДокумента);
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Запрос.УстановитьПараметр("Проведен", Проведенные);
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
УПОРЯДОЧИТЬ ПО Док.МоментВремени — хронологический порядок: по дате, внутри одной секунды — по ссылке.Проведен = &Проведен: Истина — перепроведение, Ложь — групповое проведение непроведённых. Помеченные на удаление отсекаются.Метаданные.Документы.Найти: опечатка даст понятную ошибку, а посторонний текст не попадёт в запрос.КонецДня нужен, чтобы попали документы последнего дня со временем позже 00:00:00.Для перепроведения всех видов запрос собирается из метаданных:
&НаСервереБезКонтекста
Функция ДокументыВсехВидов(НачалоПериода, КонецПериода)
Тексты = Новый Массив;
Для Каждого МетаДокумент Из Метаданные.Документы Цикл
Если МетаДокумент.Проведение <> Метаданные.СвойстваОбъектов.Проведение.Разрешить
Или МетаДокумент.Движения.Количество() = 0
Или Не ПравоДоступа("Проведение", МетаДокумент) Тогда
Продолжить;
КонецЕсли;
Тексты.Добавить(СтрШаблон(
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка,
| Док.Дата КАК Дата
|ИЗ
| Документ.%1 КАК Док
|ГДЕ
| Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Док.Проведен", МетаДокумент.Имя));
КонецЦикла;
Если Тексты.Количество() = 0 Тогда
Возврат Новый Массив;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = СтрСоединить(Тексты, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС)
+ Символы.ПС + "УПОРЯДОЧИТЬ ПО Дата, Ссылка";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
Функция записывает один документ и вместо исключения возвращает текст ошибки; режим записи — параметр, так что она же отменяет проведение.
&НаСервереБезКонтекста
Функция ЗаписатьДокумент(Ссылка, РежимЗаписи, ТекстОшибки)
ТекстОшибки = "";
ПолучитьСообщенияПользователю(Истина); // очищаем сообщения прошлого документа
ДокОбъект = Ссылка.ПолучитьОбъект();
Если ДокОбъект = Неопределено Тогда
ТекстОшибки = "Документ не найден, возможно, удален";
Возврат Ложь;
КонецЕсли;
Попытка
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
Если Не ДокОбъект.ПроверитьЗаполнение() Тогда
ТекстОшибки = ТекстСообщений("Не пройдена проверка заполнения");
Возврат Ложь;
КонецЕсли;
ДокОбъект.Записать(РежимЗаписи, РежимПроведенияДокумента.Неоперативный);
Иначе
ДокОбъект.Записать(РежимЗаписи);
КонецЕсли;
Исключение
ТекстОшибки = ТекстСообщений(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
Возврат Истина;
КонецФункции
&НаСервереБезКонтекста
Функция ТекстСообщений(Заголовок)
Строки = Новый Массив;
Строки.Добавить(Заголовок);
Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Истина) Цикл
Строки.Добавить(Сообщение.Текст);
КонецЦикла;
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
ПроверитьЗаполнение(). Программная запись не вызывает ОбработкаПроверкиЗаполнения — проверку запускает форма при проведении или явный вызов. Без этой строки обработка проведёт документ с пустым складом. Так же поступает БСП перед отложенным проведением документов, пришедших из обмена.РежимПроведенияДокумента.Неоперативный. Перепроведение идёт задним числом, а оперативно платформа проводит только документы текущего дня. Режим приходит в ОбработкаПроведения параметром, и от него может зависеть контроль остатков — после перепроведения проверьте отрицательные остатки отчётом.ПолучитьСообщенияПользователю(Истина). При Отказ = Истина причина (нет товара, не заполнен реквизит) приходит сообщением, а не текстом исключения. Первый вызов очищает очередь, чтобы сообщения прошлого документа не приписались следующему.ОбработкаОшибок.КраткоеПредставлениеОшибки — с 8.3.17; на старых релизах — глобальная КраткоеПредставлениеОшибки.Флаг ОбменДанными.Загрузка = Истина при проведении и отмене проведения ставить нельзя, даже ради скорости. Типовые обработчики ПередЗаписью при этом флаге сразу выходят и не готовят данные. Подписка БСП ПроверитьДатуЗапретаИзмененияПередЗаписьюДокумента начинается с Если Источник.ОбменДанными.Загрузка Тогда Возврат, и документ закрытого периода перезапишется без единой ошибки. Даже служебная процедура БСП ОбновлениеИнформационнойБазы.ЗаписатьОбъект сбрасывает этот флаг, если документ проводят или отменяют проведение. Загрузка уместна только при записи без проведения — например, чтобы поправить служебный реквизит в обход бизнес-логики.
Документы проводятся порциями: сначала вся порция одной транзакцией, при ошибке — по одному.
&НаСервереБезКонтекста
Функция ЗаписатьПорцию(Порция, РежимЗаписи, Ошибки)
// Попытка 1: вся порция в одной транзакции.
НачатьТранзакцию();
Попытка
Для Каждого Ссылка Из Порция Цикл
ТекстОшибки = "";
Если Не ЗаписатьДокумент(Ссылка, РежимЗаписи, ТекстОшибки) Тогда
ВызватьИсключение ТекстОшибки;
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Возврат Порция.Количество();
Исключение
ОтменитьТранзакцию();
КонецПопытки;
// Попытка 2: порция откатилась, записываем по одному и ведем журнал ошибок.
Успешно = 0;
Для Каждого Ссылка Из Порция Цикл
ТекстОшибки = "";
Если ЗаписатьДокумент(Ссылка, РежимЗаписи, ТекстОшибки) Тогда
Успешно = Успешно + 1;
Иначе
Ошибки.Добавить(Новый Структура("Документ, ТекстОшибки", Ссылка, ТекстОшибки));
ЗаписьЖурналаРегистрации("Перепроведение документов", УровеньЖурналаРегистрации.Ошибка,
Ссылка.Метаданные(), Ссылка, ТекстОшибки);
КонецЕсли;
КонецЦикла;
Возврат Успешно;
КонецФункции
ВызватьИсключение обрывает порцию, ОтменитьТранзакцию откатывает её целиком, и порция проводится заново по одному документу.&НаСервереБезКонтекста
Функция ЗаписатьДокументы(Ссылки, РежимЗаписи, Знач РазмерПорции, БезИтогов, Ошибки)
РазмерПорции = Макс(РазмерПорции, 1);
Всего = Ссылки.Количество();
Обработано = 0;
Успешно = 0;
Отключенные = Новый Массив;
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
ПоследняяЗапись = 0;
Попытка
Если БезИтогов Тогда
ОтключитьИтоги(Отключенные);
КонецЕсли;
Пока Обработано < Всего Цикл
Порция = Новый Массив;
Пока Обработано + Порция.Количество() < Всего И Порция.Количество() < РазмерПорции Цикл
Порция.Добавить(Ссылки[Обработано + Порция.Количество()]);
КонецЦикла;
Успешно = Успешно + ЗаписатьПорцию(Порция, РежимЗаписи, Ошибки);
Обработано = Обработано + Порция.Количество();
Сейчас = ТекущаяУниверсальнаяДатаВМиллисекундах();
Если Сейчас - ПоследняяЗапись < 30000 И Обработано < Всего Тогда
Продолжить; // пишем в журнал не чаще раза в 30 секунд
КонецЕсли;
ПоследняяЗапись = Сейчас;
Скорость = Обработано / Макс((Сейчас - Начало) / 1000, 1);
ЗаписьЖурналаРегистрации("Перепроведение документов", УровеньЖурналаРегистрации.Информация, , ,
СтрШаблон("Обработано %1 из %2, %3 док/с, осталось примерно %4 мин", Обработано, Всего,
Формат(Скорость, "ЧДЦ=1"), Формат((Всего - Обработано) / Скорость / 60, "ЧДЦ=0; ЧН=0")));
КонецЦикла;
Исключение
ВключитьИтоги(Отключенные);
ВызватьИсключение;
КонецПопытки;
ВключитьИтоги(Отключенные);
Возврат Успешно;
КонецФункции
&НаСервереБезКонтекста
Процедура ОтключитьИтоги(Отключенные)
Менеджеры = Новый Массив;
Для Каждого МетаРегистр Из Метаданные.РегистрыНакопления Цикл
Менеджер = РегистрыНакопления[МетаРегистр.Имя];
Если МетаРегистр.ВидРегистра = Метаданные.СвойстваОбъектов.ВидРегистраНакопления.Обороты
И Менеджер.ПолучитьРежимАгрегатов() Тогда
Продолжить; // в режиме агрегатов вместо итогов агрегаты
КонецЕсли;
Менеджеры.Добавить(Менеджер);
КонецЦикла;
Для Каждого МетаРегистр Из Метаданные.РегистрыБухгалтерии Цикл
Менеджеры.Добавить(РегистрыБухгалтерии[МетаРегистр.Имя]);
КонецЦикла;
Для Каждого Менеджер Из Менеджеры Цикл
Если Менеджер.ПолучитьИспользованиеИтогов() Тогда
Менеджер.УстановитьИспользованиеИтогов(Ложь);
Отключенные.Добавить(Менеджер);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ВключитьИтоги(Отключенные)
Для Каждого Менеджер Из Отключенные Цикл
Менеджер.УстановитьИспользованиеИтогов(Истина); // итоги пересчитаются
КонецЦикла;
КонецПроцедуры
УстановитьИспользованиеИтогов(Ложь) — запись движений перестаёт обновлять итоги, в конце платформа пересчитает их один раз. Это ускоряет документы, которые в основном пишут движения. Если проведение читает остатки (списание себестоимости в БП 3.0, контроль остатков), без итогов они считаются по всем движениям, и выйдет медленнее — решает замер.Попытка с ВызватьИсключение. Нужны права на управление итогами, а отчёты у остальных пользователей на это время замедлятся.Если документов десятки тысяч, перенесите эти функции в общий серверный модуль и запускайте из фонового задания — как, показано в статье про фоновые задания.
// Реквизиты формы: НачалоПериода, КонецПериода (Дата), ИмяДокумента (Строка, пусто — все виды),
// РазмерПорции (Число), БезИтогов (Булево),
// Журнал (ТаблицаЗначений: Документ — ДокументСсылка, ТекстОшибки — Строка).
&НаКлиенте
Процедура Перепровести(Команда)
ВыполнитьНаСервере(Истина, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ПровестиНепроведенные(Команда)
ВыполнитьНаСервере(Ложь, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОтменитьПроведение(Команда)
ВыполнитьНаСервере(Истина, Ложь);
КонецПроцедуры
&НаСервере
Процедура ВыполнитьНаСервере(ОтбиратьПроведенные, Провести)
Если Не ОтбиратьПроведенные И Не ЗначениеЗаполнено(ИмяДокумента) Тогда
ВызватьИсключение "Непроведенные документы проводите по одному виду: среди них бывают черновики";
КонецЕсли;
Если ЗначениеЗаполнено(ИмяДокумента) Тогда
Ссылки = ДокументыОдногоВида(ИмяДокумента, НачалоПериода, КонецПериода, ОтбиратьПроведенные);
Иначе
Ссылки = ДокументыВсехВидов(НачалоПериода, КонецПериода);
КонецЕсли;
РежимЗаписи = ?(Провести, РежимЗаписиДокумента.Проведение, РежимЗаписиДокумента.ОтменаПроведения);
Ошибки = Новый Массив;
Успешно = ЗаписатьДокументы(Ссылки, РежимЗаписи, РазмерПорции, БезИтогов, Ошибки);
Журнал.Очистить();
Для Каждого Ошибка Из Ошибки Цикл
ЗаполнитьЗначенияСвойств(Журнал.Добавить(), Ошибка);
КонецЦикла;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон("Документов: %1, успешно: %2, с ошибками: %3",
Ссылки.Количество(), Успешно, Ошибки.Количество());
Сообщение.Сообщить();
КонецПроцедуры
ОбработкаУдаленияПроведения, а движения удаляет платформа или сам обработчик — это задаёт свойство документа «Удаление движений».Записать и продолжил работать в той же транзакции. Откатывайте транзакцию и повторяйте по одному документу, как в функции ЗаписатьПорцию.Записать передан РежимПроведенияДокумента.Оперативный для документа прошлого дня. Перепроводите неоперативно.ПолучитьСообщенияПользователю.Считают замером: перепроведите 1000–2000 документов и посмотрите в журнале регистрации скорость и прогноз на остаток — их пишет функция ЗаписатьДокументы.
Только если потоки не пишут в одни и те же остатки и порядок между ними не важен — например, разные организации. Партии, FIFO и последовательности перепроводят в один поток.
Документ перезаписывает только те регистры, которые заполняет его обработчик проведения. Если регистр убрали из алгоритма, а свойство «Удаление движений» не равно «Удалять автоматически», старые записи останутся. Очистите их пустым набором с Движения.ИмяРегистра.Записывать = Истина или отмените проведение и проведите документ заново.
Нет, если реквизиты меняли через «Групповое изменение реквизитов» БСП: проведённые документы она записывает в режиме проведения. Исключение — «Режим разработчика»: там запись идёт с ОбменДанными.Загрузка без проведения. Подробнее — в статье о групповой обработке.
Если перепроведение затрагивает закрытые периоды, обмен или доработанные обработчики проведения, обработку с журналом и замером скорости проще поручить исполнителю: разработка отчётов и обработок 1С. Опишите конфигурацию, период и симптомы в форме задания — оценка бесплатная.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.