Изменение времени документов, перенос документов в начало дня. 1С 7.7
1C-admin
08.10.2019
Данная обработка 1С 7.7 помогает, когда кто-то установил точку актуальности на конец текущего дня (провел документ концом дня) и документы перестали проводиться. Теперь, чтобы нормализовать ситуацию, время документов нужно изменить и документы перепровести, затем перенести точку актуальности на последний проведенный документ.
Запускать обработку надо монопольно. При нажатии "Сформировать" все документы будут перенесены на начало дня (начиная с указанной в модуле даты с сохранением последовательности и интервалом 1 секунда).
Техническая реализация переноса времени на начало дня
//*******************************************
Процедура УстановитьВремяДокументаЧислом(Док, Сек)
Перем Ч,М,С;
Ч=Цел(Сек/3600);
Сек=Сек-Ч*3600;
М=Цел(Сек/60);
С=Сек-М*60;
Док.УстановитьВремя(Ч,М,С);
КонецПроцедуры // УстановитьВремяДокументаЧислом()
//*******************************************
Процедура Сформировать()
Перем ЧЧ,ММ,СС;
// СЮДА ВНОСИТЬ ВРЕМЯ+
ПоследнийПравильныйЧас = 15;
ПоследняяПравильнаяМинута = 30;
ПоследняяПравильнаяСекунда = 00;
Если МонопольныйРежим() = 0 Тогда
Предупреждение("Запускать в монопольном режиме!");
Возврат;
КонецЕсли;
СП = СоздатьОбъект("СписокЗначений");
Док = СоздатьОбъект("Документ");
Ном= 0;
Док.ВыбратьДокументы(РабочаяДата(),РабочаяДата());
Время = (ПоследнийПравильныйЧас * 60 * 60) + (ПоследняяПравильнаяМинута * 60) + ПоследняяПравильнаяСекунда;
Пока Док.ПолучитьДокумент()=1 Цикл
Док.ПолучитьВремя(ЧЧ,ММ,СС);
Если (ЧЧ*60*60+ММ*60+СС)>Время Тогда
Сп.ДобавитьЗначение(Док.ТекущийДокумент(), ?(Док.Проведен() = 1, "Проведен", "Не проведен"));
КонецЕсли;
КонецЦикла;
Сообщить(Сп.РазмерСписка());
СчЦикла = 0;
Для СчЦикла = 1 По Сп.РазмерСписка() Цикл
Время = Время+1;
СтатусДокумента = "";
Док.НайтиДокумент(Сп.ПолучитьЗначение(СчЦикла, СтатусДокумента));
НачатьТранзакцию();
Попытка
Провед = Док.Проведен();
Если Провед=1 Тогда
Док.СделатьНеПроведенным();
КонецЕсли;
ТВремя= Время;
УстановитьВремяДокументаЧислом(Док,ТВремя);
Если Провед=1 Тогда
Док.Провести();
Иначе
Док.Записать();
КонецЕсли;
Исключение
Сообщить(Док.ТекущийДокумент());
ОтменитьТранзакцию();
Прервать;
КонецПопытки;
ЗафиксироватьТранзакцию();
Сообщить(Строка(СчЦикла) + " / " + Сп.РазмерСписка());
КонецЦикла;
КонецПроцедуры
Обработка написана в комплексной конфигурации 4.2 (7.70.424). Версия платформы 7.70.027.
наращивание времени как сделано? что суммируется? как сделан переход на минутах и часах?
примечание боковое: по 10 секунд в общем случае — «плохо».
надо смотреть в каком времени первый непереносимый документ и впихивать переносимые ДО этого документа. соответсвенно надо посчитать дельту наращивани времени.
(1) я открыл код, пересчет прямой: время=ЧЧ*60*60+ММ*60+СС и обратный к нему.
это зачем? оно же изменит последовательность проведения документов?
Если база SQL, то я бы посоветовал использовать 1C++ и писать напрямую в необходимые таблицы. На практике это экономит достаточно много времени. В условиях когда работа предприятия встала, время работы — очень важный параметр. Изначально делали примерно так же как в этой обработке, только выбирали последний правильный документ (с верным временем) и перепроведение делали с интервалом в 1 секунду. После того как переписали на SQL длительность обработки с 15-20 минут уменьшилось до 5-10. Причем львиную долю. времени занимает установка ТА.
(3) вариант с 1C++ менее универсален так как для его реализации не достаточно функционала 1С. А код обработки можете написать сюда?
(2) для переноса документов «в начало дня» — все переносимые «в начало дня» документы в общем случае должны быть ДО первого неперносимого документа.
.
По наращиванию времени — я так и знал!!!
(смотри у меня публикацию пр финт ушами с временем документа).
Для переноса достаточно оперировать только СС, если секунды задашь больше 60 — платформа это правильно проглотит сама. это работает в пределах дня, дальше 23.59-59 или 00-00-00 не уйдет документ сколько бы большое значение СС ни было. Пользуйся!
Если через 1С++ чистить нудевые записи в итогах таблицы то перенос ТА идет быстро на границе месяцев.
(5) багофичи это зло ибо делает код черезжопным, в моей программе ошибок нет.
Я указал на то что перенос документа через документ ломает логику взаиморасчетов.
(7) багофичи — на вкус и цвет, согласен.
(7)
уу, название ппубликации вводит в заблуждение. поправить бы хорошо.
потому что перенос документов в начало дня — это перенос в начало дня.
здесь по факту перенос ВСЕХ (это ключевой момент) документов, лежащих после времени «Ч» до конца дня — в «правильную» последовательность документов ПОСЛЕ «Ч». Конечно, а таком контексте выполнения задачи, мое замечание неверно.
Однако, тут все равно вылезет ошибка другого рода (но похожая, так как связана с нарушением очередности документов), в общем случае:
Последнее правильное время=14 сек (Док0). Считаем что все проведение было сделано правильно, ГП не нарушена.
Исходная цепочка:
Док1, 15 сек
Док2, 15 сек
Док3, 16 сек
Док4, 16 сек
По идее, после обработки (сдвиг по 1 сек на документ) получится так:
Док1, 15 сек (14+1), ОК
Док2, 16 сек (14+2) — конфликт с Док3, Док2 ляжет и проведется ПОСЛЕ ЕЩЕ НЕ ОБРАБОТАННОГО Док3 (другой результат проведения получится чем до переноса) и не факт что Док2 проведется вообще
Док3, 17 сек (14+3) — конфликт с Док4, Док3 ляжет и проведется ПОСЛЕ ЕЩЕ НЕ ОБРАБОТАННОГО Док4 (другой результат проведения получится чем до переноса) и вдобавок проведение док3 будет опираться на неверные результаты проведения Док2 и не факт что Док3 проведется вообще
Док4, 18 сек (14+4) — проведение док4 будет опираться на неверные результаты проведения Док2 и Док3 и не факт что Док4 проведется вообще.
В случае, если все доки перенеслись и провелись повторно «без проблем» — это не гарантирует получение тех же результатов проведения что в исходной цепочке, т.к. нарушена не просто ГП (изменение задним числом), но и исходный порядок проведения документов.
Для получения гарантированного правильного результата следует ОБЯЗАТЕЛЬНО восстановить ГП последовательность документов от Док0 до последнего перенесенного документа. Или переписать алгоритм переноса.
(7) Имхо
В данном коде обертывать обработку единственного документа В МОНОПОЛЬНОМ Режиме — совершенно излишне. В приведенном коде при любой ошибке — выполнение стопорится (логику по крайне мере такую я наблюдаю).
(попутно, информационно: кстати, вместе с с предыдущим замечанием, это может в итоге привести к потере правильной последовательности документов проведения вообще, сильно не думал, надо продумать что будет при исправлении допустим ошибки непроведения и повторном запуске обработки).
Итого: транзакции если убрать и оставить только попытку — ничего в логике не поменяется.
?
(7) Не уверен, точно не помню, но что-то так:
Выполнение Док.Провести() вообще сомнительно в таком применении.
возможно проведение сломается с синтаксической ошибкой и вывалится в Исключение.
А вот если проведение просто НЕ ПРОВЕДЕТСЯ о вернет результат проведения — 0 (штатно как обычно установкой статусвозврата(0) — никакое исключение не произойдет. Поэтому надо типа внутри попытки
Результат = Док.Провести();
Если Результат =0 Тогда
//искуственно вызвать исключение или прерваться явно
(9) Сергей, спасибо за подробное объяснение принципа действия алгоритма. На самом деле алгоритм рабочий, переписывать его не надо. Но Ваша постановка задачи к которой Вы применили алгоритм не имеет смысла. Никто не переносит документы на секунду назад, 100 % случаев возникает необходимость перенести на несколько часов, поэтому описанная Вами ситуация практически не возможна.
На самом деле практические задачи для решения которых мной предназначен алгоритм в публикации такие:
1) алгоритм поможет изменить время документов на заранее выбранное, каждый следующий документ на следующую секунду, но не с 15й секунды на 14ю, ибо это не имеет смысла.
2) алгоритм поможет если надо перенести документы на начало дня, хоть на 00 часов — не ломая последовательности.
3) алгоритм поможет, когда кто-то установил точку актуальности на конец текущего дня (провел документ концом дня) и документы перестали проводиться. Теперь, чтобы нормализовать ситуацию, время документов нужно изменить и документы перепровести, затем перенести точку актуальности на последний проведенный документ. Решать эту задачу в разделенном режиме смысла нет, так как в разделенном режиме пользователи напрасно будут мучать базу — все равно документы не проводятся, да и точку актуальности на последний документ можно установить только в монопольном режиме.
(12) все пункты работают только если верить что » 100 % случаев возникает необходимость перенести на несколько часов, поэтому описанная Вами ситуация практически не возможна.»
— практически не очень вероятно, да. но вполне может случится казус.
ибо в приведенном примере — алгоритм породит некорректные данные.
а сработает ли такой пример в реальности — зависит исключительно от количества доков которые надо перенести, периода времени на котором эти доки находятся и зависимостей документов (и результатов их проведения) друг от друга.
в общем случае — алгоритм нерабочий. да, я тоже оцениваю вероятность трабла как маленькую.
Но я бы посоветовал, во избежание либо в конце кода перепровести все перенесенынные документы в хорологической последовательности или сначала все документы перенести в виде непроведенных, а потом перепровести. и это ВСЕ обернуть в транзакцию.
.
транзакция в коде — как у вас — излишняя.
И что главное — Док.Провести() — в случае непроведения НЕ ВЫЗОВЕТ ИСКЛЮЧЕНИЯ. что может в такой (или разновидностях такой логики обработки чуть более сложной) привести к ЯВНОЙ ОШИБКЕ в итогах переноса.
.
та позже, в вашем коде, в случае если Док.Провести() не проведется — скорее всего упадет на ЗафиксироватьТранзакцию(), ибо транзакция уже отатана назад неявно.
(13) Спасибо за подробное замечание!!
Согласен что Док.Провести() в данном контексте выглядит сомнительно и вызывает вопрос, ну ни разу не бывало проблем. Согласен красивее выглядит
но практически это пока не испробовано. Ну ни разу у меня не было проблем с этим, возможно причина в СтатусВозврата(0)+транзакции, надо провести тест…
(13) в общем Вы не правы, все у меня отлично работает, тест пройден успешно. Оно несколько лет используется. Не могло оно глючить.
1)В тестовой базе берем любой документ, в начале обработки проведения пишем:
Я для примера в документ Аккредитив добавил, установил признак проводить в оперативном учете. Реструктуризация прошла…
2)создаем и проводим с нулевой суммой
3)редактируем реквизит сумма = 1р
4) запускаем мою обработку
Смотрим результат, попробуйте повторить сами:
(15) все правильно, я об этом и сказал выше, что сломается на ЗафиксироватьТранзакцию.
неудачное проведение как таковое не вызывает исключения. поэтому ошибка проведеняи документа — не отлавливается. и то что это неудачное проведение стопорит систему — просто удачное стечение обстоятельств что напарывается на ЗафиксироватьТранзакцию в лишней обертке транзакции (я думаю что вы рассчитывали что неудачное првоедение вывалится в исключение),
это я к тому, что надо помнить что неудачное проведение не вызывает исключения.
и при пакетной обработке при использовании попытки для отлавливания проблем — запросто можно пройти «мимо» (особенно если обработка множества объектов не обернута в транзакцию, даже когда обернута в транзакцию то тоже можно пропустить или потребуются детальный просмотр лога чтобы понять почему в 500 обработанных объектах внезапно транзакция не зафиксировалась.).
В приведенном коде по-правильному д.б. типа
Если Док.Провести()=0 Тогда Прервать; КонецЕсли;
.
По большому счету — эти мои замечания про Провести() — относятся больше к общему подходу к программированию в части правильности написания кода.
В вашем коде за счет избыточности — в результате отлавливается, ну и ок.
Пусть код так и будет.
(16) У меня есть практический совет о «прервать» применительно к обработкам документов. Если требуется однозначно прекратить выполнение кода (вот как например требуется в данном случае) я всегда вместо «Прервать» пишу «ф = 1/0;», это красивее выглядит. Ато дальше после «Прервать» может что-нибудь нехорошее произойти.
п.с. У меня ведь тоже багофича получиласть, поэтому код статьи и обработку поправлю после удачного применения нового алгоритма на практике.
(13)
Транзакция у меня в коде нужна для того, чтобы в случае выявленной ошибки распроведение не произошло и документ, который не удалось перенести, остался нетронутым (проведенным).
(18) дело в том, что если документ был проведен но теперь не может быть перепроведен может возникнуть необходимость разобраться почему он не проводится и выполнить эти условия, чтобы не поломать учет. И тогда при повторном запуске обработка переноса документов продолжит свою работу в штатном режиме.
(10)
Итого: транзакции если убрать и оставить только попытку — ничего в логике не поменяется.
В случае возникновения ошибки на одной из итераций цикла, последний удачно проведенный документ останется на новом времени (часть документов уже перепроведена). Проблемный документ останется на старом неправильном времени неповрежденным, как будто мы не пытались его распровести — для этого транзакция написана в коде обработки. Последовательность документов остается правильной как и была, потому что документ основания не может быть позже по цепочки структуры подчиненности, чем переносимый документ. В противном случае если какими-то ухищрениями достигнута ситуация что документ не может быть перепроведем, мы опять же с помощью транзакции получаем целостный неповрежденный проблемный документ.
Если транзакцию убрать, произойдут необратимые изменения, которые потом надо будет исправлять, тратить на это время.