gifts2017

Корректировка движений регистра (Проведение без Проведения)

Опубликовал Павел (Pavel777777) в раздел Программирование - Практика программирования

Вариант проведения документов по одному выбранному Регистру (для конфигураций 1с 8.1/8.2)

Исходная задача состояла в том, что надо было ввести остатки на начало года по "партиям НДС" в конфигурации "Комплексная автоматизация" и провести все документы по этому регистру. Сложность была в том, что остатки вводились с опозданием и несколько периодов были уже закрыты. Поэтому напрямую перепроводить документы было уже нельзя (из-за возможных изменений сумм себестоимости и т.д.)

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

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

Не претендуя на оригинальность самой идеи отменять транзакцию, тем не менее хочу представить работающий алгоритм (для конфигураций 1С 8.1/8.2). Возможно, кому-то пригодится в работе. Мне он помогал ещё в нескольких случаях.

В примере приводится проведение по регистру накопления "Размещение". Это регистр был добавлен в конфигурацию и не относится к типовым. Алгоритм легко переделать на другой (другие) нужный регистр. Как с любыми операциями с регистрами, и этой операцией тоже следует пользоваться аккуратно )

Текст самих процедур (8.1/8.2)

Процедура ПерепровестиДокументыПоРегистру()

   
//отбираем все проведенные документы, которые могут делать движения по нужному нам
    //регистру (РегистрыНакопления.Размещение)
    //за указанный период с Дата1 по Дата2

   
ИмяРегистра = "Размещение";

   
ТекстЗапроса = "ВЫБРАТЬ Документы.Ссылка ИЗ (";
    Для Каждого
Документ Из Метаданные.Документы Цикл
        Если Не
Документ.Движения.Содержит(Метаданные.РегистрыНакопления[ИмяРегистра]) Тогда
            Продолжить;
        КонецЕсли;
       
ТекстЗапроса = ТекстЗапроса + "ВЫБРАТЬ " + Документ.Имя + ".Ссылка КАК Ссылка, " +
       
Документ.Имя + ".Дата КАК Дата  ИЗ Документ." + Документ.Имя + " КАК " + Документ.Имя +
       
" ГДЕ " + Документ.Имя + ".Дата МЕЖДУ &НачПериода И &КонПериода И "
       
+ Документ.Имя + ".Проведен ОБЪЕДИНИТЬ ВСЕ ";
    КонецЦикла;
   
ТекстЗапроса = ТекстЗапроса + "ВЫБРАТЬ NULL, NULL ) КАК Документы ГДЕ НЕ Документы.Ссылка ЕСТЬ NULL УПОРЯДОЧИТЬ ПО Документы.Дата";
   
Запрос = Новый Запрос(ТекстЗапроса);

   
Запрос.УстановитьПараметр("НачПериода", НачалоДня(Дата1));
   
Запрос.УстановитьПараметр("КонПериода", КонецДня(Дата2));

   
Выборка = Запрос.Выполнить().Выбрать();
   
Сообщить(Выборка.Количество());
    Пока
Выборка.Следующий() Цикл
       
ОбработкаПрерыванияПользователя();
       
ДокСсылка=Выборка.Ссылка;
       
Сообщить(" "+СокрЛП(ДокСсылка));
       
ПровестиПоРегистру(ДокСсылка,ИмяРегистра);
    КонецЦикла;
КонецПроцедуры

Процедура
ПровестиПоРегистру(ДокСсылка, ИмяРегистра)
   
ДокОбъект = ДокСсылка.ПолучитьОбъект();

   
НачатьТранзакцию();

   
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
   
ДокОбъект.Движения[ИмяРегистра].Прочитать();
   
ТаблицаДвиженийРегистра = ДокОбъект.Движения[ИмяРегистра].Выгрузить();

   
//здесь отменяем проведение документа, чтобы ничего не изменилось
    //в прошлых периодах (по другим регистрам)
   
ОтменитьТранзакцию();

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

 

Решение похожей задачи (но другим способом) для платформы 7.7 описано в статье "Технологическое перепроведение документов

 

ps. (03/03/2012)

Забавно - сегодня обнаружил полный аналог этого алгоритма, описанный ранее на "Инфостарт" -  "Перепроведение документов только по выбранным регистрам" .... Похожие идеи витают в воздухе :)

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Андрей Акулов (DrAku1a) 18.12.11 13:45
2. Павел (Pavel777777) 21.12.11 14:32
Спасибо всем за поддержку моей первой статьи на "Инфостарт"
3. Lizi60 (Lizi60) 21.12.11 16:50
Да, идея хорошая. Обязательно пригодится.
4. Vladimir (Boroda) 21.12.11 20:33
Хотя ЗУП в перечне и не указан, но, думаю, принцип можно использовать и при работе в этой конфигурации. Спасибо.
5. Ирина Киселева (irishka77) 22.12.11 10:52
6. Михаил Шайдуров (Mshaydurov) 23.12.11 10:51
Boroda пишет:

Хотя ЗУП в перечне и не указан, но, думаю, принцип можно использовать и при работе в этой конфигурации. Спасибо.


По моему использовать можно абсолютно в любой конфигурации. Даже в нетиповой самописной. Автору респект и уважуха =)
7. Модератор раздела Артур Аюханов (artbear) 23.12.11 16:14
Давно известный баян, конечно :)
8. Модератор раздела Артур Аюханов (artbear) 23.12.11 16:22
(0) 1. Запрос не оптимален :(
Зачем путать оптимизатор запросов вложенностью и ограничением по "ГДЕ НЕ Документы.Ссылка ЕСТЬ NULL"
Проще из текста выпилить последнее "Объединить все"
2.ИМХО Отдельная транзакция на каждый документ в сабжевой задаче не имеет смысла.
Представь, проведение валится на середине, у тебя часть записей по регистру изменилась, а часть нет.
Это неверно.
Проще и правильнее юзать одну общую транзакцию на все документы
или другими способами гарантировать общее изменение или неизменение всех меняемых записей.
9. Модератор раздела Артур Аюханов (artbear) 23.12.11 16:24
(0) 3. Да и сам код как-то совсем не разобран.
Пишешь
ДокСсылка=Выборка.Ссылка;

а далее все-таки юзаешь Выборка.Ссылка вместо ДокСсылка :(
Сообщить(" "+СокрЛП(Выборка.Ссылка));
ПровестиПоРегистру(Выборка.Ссылка,ИмяРегистра);
10. Модератор раздела Артур Аюханов (artbear) 23.12.11 16:29
(0) 4. ИМХО весь твой код по загрузке данных можно слегка поправить
вместо
ДокОбъект.Движения[ИмяРегистра].Прочитать();
    ТаблицаДвиженийРегистра = ДокОбъект.Движения[ИмяРегистра].Выгрузить();

    ОтменитьТранзакцию();

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

Можно написать
    НаборЗаписей = ДокОбъект.Движения[ИмяРегистра];
    НаборЗаписей.Прочитать();
    ТаблицаДвиженийРегистра = НаборЗаписей.Выгрузить();

    ОтменитьТранзакцию(); // как я уже говорил, лучше перенести транзакцию на более верхний уровень

    НаборЗаписей.Загрузить(ТаблицаДвиженийРегистра);
    НаборЗаписей.Записать();
...Показать Скрыть

Правда, не проверял, но зная, как работают объекты 1С, уверен почти на 100% :)
А еще можно попытаться избавиться от выгрузки и загрузки ТаблицаДвиженийРегистра, т.к. данные из набора при отмене транзакции не меняются :) - это же обычный объект/коллекция
11. Ирина Вшивкова (ir_en) 27.12.11 03:02
12. Павел (Pavel777777) 29.01.12 12:18
(8) Спасибо за конструктивную критику )
С п.1 и 3, конечно, согласен ... а вот п.4 (и 2) требуют проверки всё-таки.... особенно п.2, поскольку основная "фишка" алгоритма именно в отмене транзакции каждого проведения и одновременном изменении движений.

В любом случае - представленный код проверен на реальных данных, а оптимизировать всегда есть куда
13. Сергей (lsp71) 10.02.12 12:37
14. Vladimir (Boroda) 04.03.12 23:15
Интересно, чем редакция [03.03.2012 11:13] отличается от предыдущей? Что-нибудь добавлено, кроме p/s? Или новая дата появилась только для поднятия публикации?
15. Павел (Pavel777777) 05.03.12 08:18
(14) Новая дата появилась автоматически после того, как я добавил ps. А дополнение это я считаю важным, поэтому его и добавил.... Поскольку перед размещением статьи я ничего похожего на сайте Инфостарт не нашёл .... Так что это скорее поднятие публикации-ссылки из примечания.
16. Алекс Ю (AlexO) 27.08.12 10:33
Pavel777777,
Забавно - сегодня обнаружил полный аналог этого алгоритма, описанный ранее на "Инфостарт"

аналог кода или аналог последовательности действий?
17. Алекс Ю (AlexO) 27.08.12 10:38
(0) Pavel777777,
вот из-за этого
Если Не Документ.Движения.Содержит(Метаданные.РегистрыНакопления[ИмяРегистра])

нужно курочить Движения в свойствах всех документов, учавствующих в доп-проведении - а это изменение конфы существенное.
И тут - очередная "удивительная" недоработка регистров РН у 1С: ну вот зачем писать новый регистр в Движения всех отобранных видов документов, если все равно - доп-проведение через наборЗаписей напрямую, без задействования объекта "Движения":
 НаборЗаписей = РегистрыНакопления[ИмяРегистра].СоздатьНаборЗаписей();

А без прописки в Движения отбор в набор записей по регистратору не сработает...
18. Павел (Pavel777777) 10.09.12 10:46
(16) Аналог последовательности действий) .. в написании кода то по-любому будут отличия

(17) Вообще предполагалось, что перепроводиться будут ТОЛЬКО документы, которые уже делают движения по выбранному регистру. Поскольку используется алгоритм проведения документа, уже предусмотренный конфигурацией.
А поэтому - дополнительно в конфигурации только для этого перепроведения ничего менять не надо.
19. Сергей (lsp71) 04.04.13 13:43
Использовал изложенную идею для создания движений по новому (нестандартному) РН. Надо было перепровести документы, начиная с 2007 года. Выяснилось:
1. Конфа с тех времен существенно изменилась и проведение некоторых документов по всем РН невозможно из-за изменения реквизитов этих документов и процедур проведения по РН (проще говоря, текущая обработка проведения не соответствует старым данным).
2. Проведение (а реально это перепроведение, т.е. проведение с предварительным удалением движений по РН) а потом отмена транзакции происходит очень медленно. А еще заодно запускаются процедуры модуля объекта ПередЗаписью и ПриЗаписи. Документов много, месяц деятельности "переваривался" таким алгоритмом около суток.
Мое решение (дополняющее идею статьи): некоторые типы документов обрабатывать не описанным в статье алгоритмом, а своим, который будет:
1. учитывать изменения конфы (т.е. очень старые и более свежие документы можно обрабатывать вообще разными алгоритмами)
2. не будет проводить документ по всем РН, а только по одному, мне интересному
3. не будут работать процедуры ПередЗаписью и ПриЗаписи
В принципе, нам ведь все равно каким образом получена ТаблицаДвиженийРегистра, если она содержит правильные данные. Я написал "свои" обработки, формирующие ТаблицаДвиженийРегистра, для 3-х из 16 документов-регистраторов. Свои в кавычках из-за того, что их основой все равно были алгоритмы проведения из конфы, я лишь убрал ненужные проверки и сделал чтобы это работало не из модуля объекта, а из внешней процедуры.
Скорость работы выросла в десятки раз (примерно в 22 раза) и ушли ошибки проведения.
20. Npoen Dzogchen (Dansur) 11.04.16 23:28
21. Алексей Ахмадеев (Alexey_A) 30.10.16 22:59
Спасибо! гениальная и в то же время простая идея! я уж расстроился, думал писать целый обработчик по выправлению регистра и вспомнил, что уже когда-то пользовался этой статьей и нашел ее. огроменное человеческое спасибище!