Форум Кладовочки АЛьФ`а

Общие вопросы => 7.7 => Тема начата: Злоп от 05 сентября 2025, 13:38

Название: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 13:38
Обычная задача ведения лога изменений документа. Если нормально написано - то вкорячиапешь в ПриЗаписи() и норм. Но конфига самопальная, извращенная, запросто в коде формы документа встречается Записать(), ПриЗаписи() не отрабатывает. И прочие заморочки.
.
Поэтому куда можно вклиниться чтобы получить состояние контекста формы документа (изменений, но не записанный), самого документа через ТекущийДокумент() (без изменений еще), при этом чтобы после отработки моего кода пошла запись измененного документа.

И как вообще аннулировать запись в базу об изменениях если по какой-то причине запись измененного документа не прошла?

Мысли есть, но как-то некрасиво, извращенно получается.

Или может какой другой вариант/метод записи изменений документа по всем его реквизитам шапки и тч по типу "было-стало"
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 13:50
Изменения фиксируются в базе документом "Протокол". Где в свободном виде в строку неограниченной длины пишется было-стало
Название: Re: Как перехватить момент перед записью...?
Отправлено: Djelf от 05 сентября 2025, 14:52
ПриОткрытии не сработает при программной записи.
ПриЗаписи не перехватывается, на 1с++ это неоднократно обсуждали.
ПриПроведении работает стабильно, но надо получить данные до  момента измения, а получить ты их не можешь.

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

Но первоначальное состояние точно и надежно никак не получить.

P.S. АльФ! С какой частотой тебя гугл сниферит? Я даже не нажал кнопку отправить, а он уже этот пост засниферил  :o
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 14:54
Или сделать тупо просто
В Приоткрытии() запоминаем содержимое документа, а формексом Послезакрытия() сравниваем с уже текущим состоянием документа.
...
?
Название: Re: Как перехватить момент перед записью...?
Отправлено: Djelf от 05 сентября 2025, 15:02
Цитата: Злоп от 05 сентября 2025, 14:54Или сделать тупо просто
В Приоткрытии() запоминаем содержимое документа, а формексом Послезакрытия() сравниваем с уже текущим состоянием документа.
...
?
Так должно сработать. Попробуй. А ограничения я уже написал выше.
Ну и лучше в json в таблику sqlite писать, или сериализировать туда тз или итз, а вот в длинные строки этот так себе вариант. Плохой вариант...
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 15:08
Цитата: Djelf от 05 сентября 2025, 14:52ПриОткрытии не сработает при программной записи.
ПриЗаписи не перехватывается, на 1с++ это неоднократно обсуждали.
ПриПроведении работает стабильно, но надо получить данные до  момента измения, а получить ты их не можешь.

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

Но первоначальное состояние точно и надежно никак не получить.

P.S. АльФ! С какой частотой тебя гугл сниферит? Я даже не нажал кнопку отправить, а он уже этот пост засниферил  :o

Программную запись извне не рассматриваем.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 15:09
Цитата: Djelf от 05 сентября 2025, 15:02
Цитата: Злоп от 05 сентября 2025, 14:54Или сделать тупо просто
В Приоткрытии() запоминаем содержимое документа, а формексом Послезакрытия() сравниваем с уже текущим состоянием документа.
...
?
Так должно сработать. Попробуй. А ограничения я уже написал выше.
Ну и лучше в json в таблику sqlite писать, или сериализировать туда тз или итз, а вот в длинные строки этот так себе вариант. Плохой вариант...
Знаю что плохой вариант.
Костыли все это.
Можно тупо в файло писать, но как его закрыть что 1с может писать, а интерактивно ось пользователь ручками - не может. Хз.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 15:11
Цитата: Djelf от 05 сентября 2025, 15:02
Цитата: Злоп от 05 сентября 2025, 14:54Или сделать тупо просто
В Приоткрытии() запоминаем содержимое документа, а формексом Послезакрытия() сравниваем с уже текущим состоянием документа.
...
?
Так должно сработать. Попробуй. А ограничения я уже написал выше.
Ну и лучше в json в таблику sqlite писать, или сериализировать туда тз или итз, а вот в длинные строки этот так себе вариант. Плохой вариант...

Но тут засада
Во например ЗБ
Открыл - поправил - провел (тут выполняется запись) - поправил назад - провел (тут запись) - закрыл.

При записи зарегистрируется бы два факта изменения, а при выходе - ищменений нет...
Название: Re: Как перехватить момент перед записью...?
Отправлено: Djelf от 05 сентября 2025, 15:17
Ну и хорошо что при выходе изменений нет, зачем логгировать?
Название: Re: Как перехватить момент перед записью...?
Отправлено: Djelf от 05 сентября 2025, 15:19
Давай каждый клик логгировать, sqlite то справится, но нафейхоа?
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 15:51
Цитата: Djelf от 05 сентября 2025, 15:17Ну и хорошо что при выходе изменений нет, зачем логгировать?
поправили - напечатали - поправили, вышли. Печатное и в базе - разное...
.
Приправильнрй конструкции документов/процессов все это можно обойти, но рефакторить туеву хучу всего не вариант
Название: Re: Как перехватить момент перед записью...?
Отправлено: Djelf от 05 сентября 2025, 16:05
Цитата: Злоп от 05 сентября 2025, 15:51
Цитата: Djelf от 05 сентября 2025, 15:17Ну и хорошо что при выходе изменений нет, зачем логгировать?
поправили - напечатали - поправили, вышли. Печатное и в базе - разное...
.
Приправильнрй конструкции документов/процессов все это можно обойти, но рефакторить туеву хучу всего не вариант

Товарищь Берия с таким бы справился...
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 16:13
Я тоже согласен но персоналом рулю не я
Название: Re: Как перехватить момент перед записью...?
Отправлено: Djelf от 05 сентября 2025, 16:23
А как они смогли напечатать не измененный документ без записи а базу?
Можно тогда еще ПриПечатиТаблицы сниферить...

Но это реально глупость, прощать таки штучки и одновременно их мониторить. 
Название: Re: Как перехватить момент перед записью...?
Отправлено: Ветер в поле от 05 сентября 2025, 18:54
У меня это решено так. ПриОткрытии запоминаем текущее состояние документа. ПриЗакрытии сравниваем и записываем в базу.
С одной стороны тут есть бонус - промежуточные сохранения не забивают базу. С другой - если из документа не вышли, то информация об изменении не отразится в базе. Также в шапке документа есть счетчик перепроведений. В большинстве документов стоит запрет печати незаписанного документа. Точнее при нажатии на кнопку печати, документ записывается и проводится.
Данные изменений хранятся иерархически. Справочник ДокументыИзменения содержит все документы, для которых отслеживается история. Подчиненный ему справочник ИзмененияВДокументе содержит факты изменения, когда, где, кто изменил, тип изменения (провел, пометил на удаление, записал и т.д). Уже этому справочнику подчинен ИзмененияРеквизитовДокумента - тут содержатся измененные реквизиты шапки. Также для каждого документа с табличной частью сделаны справочники типа ИзмененныеСтрокиПоступлениеМатериала, которые содержат изменения в строках.
Такое хранение позволяет очень точно находить всякие специфические ситуации, потому что позволяет запросом поднять нужные данные. С помощью специального класса все манипуляции по поддержанию истории делается просто.
Были идеи по созданию отдельной базы, в которую будут периодически переноситься данные истории, но не понадобилось. Просто создал архивную базу, в которую раз в год переносились все данные за прошедший год. Поэтому есть архив за 14 лет и рабочая база за 1-2 года.

В каждом документе есть примерно такие строки:
Перем ОбъектФормаДокумента;

//*****************************************************************************
Процедура ПриОткрытии() //предопределенная

Если ОбъектФормаДокумента.ПриОткрытии("кнХПредставитель", 1, 1, 1) = 0 Тогда //тут запоминается начальное состояние
Возврат;
КонецЕсли;

Если Форма.ТолькоПросмотр() = 0 Тогда
Если глПолучитьПолномочие("РазрешитьИзменятьДатуДокумента") = 0 Тогда
глДоступностьРеквизитов(Контекст, "ДатаДок", 0);
КонецЕсли;
КонецЕсли;

глАктивизироватьРеквизит(Контекст, "Статус", "ДатаДок", 1);

КонецПроцедуры //ПриОткрытии

//*****************************************************************************
Процедура ПриЗаписи() //предопределенная

Если ОбъектФормаДокумента.ПриЗаписи_ВНачале("") = 0 Тогда //тут стандартные проверки на заполненность реквизитов и возможность записи
Возврат;
КонецЕсли;

Если ОбъектФормаДокумента.ПриЗаписи() = 0 Тогда //тут взводится флаг записи документа
Возврат;
КонецЕсли;

КонецПроцедуры //ПриЗаписи

//*****************************************************************************
Процедура ПриЗакрытии() //предопределенная

Если ОбъектФормаДокумента.ПриЗакрытии() = 0 Тогда //здесь анализируем изменения и записываем в базу
Возврат;
КонецЕсли;

КонецПроцедуры //ПриЗакрытии

////////////////////////////////////////////////////////////////////////////////
// ОПЕРАТОРЫ ОСНОВНОЙ ПРОГРАММЫ

ОбъектФормаДокумента = СоздатьОбъект("Форма.Документ");
ОбъектФормаДокумента.Инит(Контекст, 1);
//ОбъектФормаДокумента.ДобавитьПечФорму("Печатная форма", "Печать");
Название: Re: Как перехватить момент перед записью...?
Отправлено: item от 05 сентября 2025, 20:40
Посмотри вк v7crypt от Щербакова (Вирта).
Там для документов много чего есть.
Практически перехват всех событий Перед/При/После  Записи/Проведения, причем работает для обьектов, а не форм.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 05 сентября 2025, 20:48
Цитата: Djelf от 05 сентября 2025, 16:23А как они смогли напечатать не измененный документ без записи а базу?
Можно тогда еще ПриПечатиТаблицы сниферить...

Но это реально глупость, прощать таки штучки и одновременно их мониторить.
Состояние0
Записали исправленное1 - напечатали - записали исправленное0 - состояние0 - выход.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Харлампий Дымба от 08 сентября 2025, 11:17
Делал такое давным-давно. По памяти:

Завод ЖБИ. Бетономешалка заезжает на территорию, ей выписывают липовую накладную, заливают бетон, после выезда вместо липовой  делают настоящую накладную для следующей машины. Разово 6 кубов бетона - фигня, но аппетиты росли. Выход бетона по сравнению с расходом цемента был подозрительно низок)

Этап 1: Копия накладной остаётся на посту заливки, потом сверка: что в 1С, а что на посту заливки. По итогу - пост заливки берут в долю и липовая накладная исчезает из 1С синхронно с бумажной копией на посту заливки.

Этап 2: Ещё одна копия накладной остаётся на посту охраны (выездные ворота), потом сверка: что в 1С, а что на посту охраны. По итогу - пост охраны берут в долю и липовая накладная исчезает из 1С синхронно с бумажными копииями на посту охраны и на посту заливки.

Этап 3: Сохранение истории изменений накладных в 1С.
Важные моменты:
Всё негласно, чтобы не спугнуть отписчика-вора, ведь подготовить липу в другой базе/программе проще простого - так что о начале охоты знаю только я и главный бухгалтер.
Никакой жёсткости в плане запрета печати непроведенных/несохраненных! - именно для ловли на живца, единственное - запрет редактирования печатной формы.
Должно быть выявление именно подозрительных действий, т.е. распечатали повторно без изменения или распечатали повторно что-то добавив - не подозрительно, а распечатали и сохранили что-то удалив - подозрительно. Потому что просматривать глазами изменения в сотнях накладных в день - не работает.
Распечатали и не сохранили вообще - подозрительно вдвойне, т.е. контроль должен учитывать, что контролируемой накладной в базе 1С может вообще не оказаться.
Не забываем контролировать все возможности: печать из журнала,  печать несохраненного, изменение после печати, возможно даже изменение наименований товаров (если уж заморочиться), отрубаем другие возможности напечатать накладную.
Можно дублировать печать в пдф в папку - для анализа не пригодно, но для последующих разборок может пригодиться.
Технически делал через привязку к накладной mxl-файла куда скидывал действие/время/пользователя и при необходимости состояние документа с подсветкой измененного - так проще для быстрого анализа.
Так как делается под конкретную задачу и для конкретного документа, то всякие программные .Записать() - не проблема, достаточно также делать вызов процедуры фиксации состояния как и в ПриЗаписи().
В УРБД работать не будет.
При выявлении подозрительных действий - желательно сразу сообщение интересанту.
Цель - не спугнув выявить ворующие смены для принятия мер.

Итог 3 этапа: ворующие смены выявлены, я получил в качестве премии 2 месячные зарплаты, никаких административных мер не последовало, а, судя по продолжающим падать мне в список подозрительным накладным, доля начала делиться на большее количество частей.
А потом всего понемногу: чёрненькая из Тату, Великая рецессия, Батурина... в общем всё исчезло.

Если нужно, могу поискать код в закромах, но вряд ли там какие-то прям откровения по сравнению с уже написанным в теме.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Arbuz от 08 сентября 2025, 16:20
Цитата: Djelf от 05 сентября 2025, 14:52ПриЗаписи не перехватывается, на 1с++ это неоднократно обсуждали.
Точности ради: у wirth'а в V7Crypt всё перехватывается, у меня используется
Цитата
И так в чем суть. Помимо стандартных предопределений: «ОбработкаПроведения»
и «ОбработкаУдаленияПроведения», в модуле документа теперь можно определить
дополнительные процедуры для обработки событий:
"ПриЗаписи" или "OnWrite";
"ПередПроведением" или "BeforePosting";
"ПослеПроведения" или "AfterPosting";
"ПередУдалениемПроведения" или "BeforeUnposting";
"ПослеУдаленияПроведения" или "AfterUnposting";
"ПередУдалением" или "BeforeDelete";
"ПослеУдаления" или "AfterDelete";
"ПередОтменойУдаления" или "BeforeUnDelete";
"ПослеОтменыУдаления" или "AfterUnDelete".
Процедуры не имеют входящих аргументов и параметра возврата. В процедурах:
«ПриЗаписи», а также с префиксом «Перед», можно отменить выполняемое действие,
установив статус возврата в ноль, при этом будет брошено стандартное исключение языка
1С. Процедуры, с префиксом «После», действие отменить не могут и вызываются только
как уведомление.
Немаловажный факт, что события с префиксами «Перед» и «После» выполняются
вне рамок транзакции побуждающего действия, т.е. не блокируют базу данных.
События «Перед» и «После» выполняются в рамках одного контекста модуля
документа, т.е. в событии «Перед» можно выбрать данные (например, проводки) и сохранить их в переменной модуля документа, а в событии «После», сравнить эти данные
с результатом после выполнения действия, и произвести необходимые операции.
Это просто сказка (правда лютых фиче-глюков тоже хватает, но я уже их изучил)

Цитата: item от 05 сентября 2025, 20:40Посмотри вк v7crypt от Щербакова (Вирта).
Во-во, я про то. Но я бы не рекомендовал так просто ставить это в прод, там проблем добавится, на самом деле.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 08 сентября 2025, 18:07
И какие фичн-глюки?
Название: Re: Как перехватить момент перед записью...?
Отправлено: alyuev от 09 сентября 2025, 22:50
А для какого релиза 1С эта библиотека v7crypt ? 25й или 27й? И да, интересно было бы знать про реальные проблемы с этой компонентой.
Название: Re: Как перехватить момент перед записью...?
Отправлено: item от 09 сентября 2025, 23:51
Если родной blang.dll а релизах не поменялся, то имхо без разницы.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Arbuz от 11 сентября 2025, 16:40
Эм... Вот с родными событиями, например. Бывает по нескольку раз вызываются, типа ПриЗавершенииРаботы, особенно забавно с параметрами которые, там каша. Там есть ещё возможность добавлять свои глоб.модули и вся событийная логика более-менее предсказуемо работает только при определённой конфигурации. У меня давно это используется, не могу отказаться, везде воркэраунды. Не знаю, может из-за этой компоненты бывает срывает стэк при невыясненных обстоятельствах, но всё время в одних и тех же условиях, слегка меняешь код и нет проблем. Бывает глючит поток исполнения байт-кода, пропускает, останавливается — тоже грешу на эту штуку. Бывают интересные интерференции с трассировкой формекса. Но, повторю, я давно её использую, в том числе, V7CryptLib и уже как крыса в стеклянном лабиринте знаю где повороты на выход, но начертить маршрут не могу ;D. Сейчас у меня очень стабильно работает — ошибки случаются не чаще чем в целом по операционке, т.е. никогда, в пределе.
Я бы вам не советовал её без крайнего любопытства пытаться быстро приспособить себе в прод.
Может ещё что... просто у меня сейчас корона, будь она неладна, ребят — голова не варит совершенно.
Название: Re: Как перехватить момент перед записью...?
Отправлено: item от 11 сентября 2025, 18:03
Пробовал, но отказался.
Добавлю, что помню.
ПриЗавершенииРаботыСистемы вызывается столько раз, сколько обьявишь глобальных модулей,
В каждом глобальном модуле вызывается (должна быть прописана) ОбработкаВнешнегоСобытия.
Функция СоздатьКонтекст работает только для внешних обработок.
Отказался про причине лени разбираться и подстраиваться. У меня ПриЗаписи доков было понатыкано Записать в транзакции, и периодически подвисало крепко на этом моменте. Возможно, если бы вынес логику в ФормаПослеЗаписи, то и работало бы.
А так то да, весчь многообещающая, но сырая.

Пс
Про Гобальные от АЛьФа и ФормуПослеЗаписи на то время не знал.
И да, на загруженныз базах логика ПередПроведением вне транзакции это сила.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 12 сентября 2025, 00:57
ПередПровндением?
Это где такая?
Название: Re: Как перехватить момент перед записью...?
Отправлено: item от 12 сентября 2025, 08:37
Цитата: Злоп от 12 сентября 2025, 00:57ПередПровндением?
Это где такая?
Да все там же, в v7crypt.
ПередПроведением, ПослеПроведения, ПриЗаписи и тд обьявляешь как а модуле документа, так и глобально.
Работают в обьектах
Вот не помню, можно ли обьявить для обьекта экспортный метод, надо глянуть.
Название: Re: Как перехватить момент перед записью...?
Отправлено: trdm от 13 сентября 2025, 10:02
А есть ссылка на компоненту, что-то гугл не гуглит..
Ну или мамыльте..
Название: Re: Как перехватить момент перед записью...?
Отправлено: item от 13 сентября 2025, 10:27
Сетап
V7Crypt_1.0.1.6.exe (https://disk.yandex.by/d/XtX99Q8tU5P8FQ)

Устанавливается в собственную папку.
При патче заменяет родной blang.dll на 1c_blang.dll.
Название: Re: Как перехватить момент перед записью...?
Отправлено: Злоп от 13 сентября 2025, 11:50
Репозиторий по 77 нужен ;-)
У себя на компе файловый архив, по папочкам разложено всякое...
Название: Re: Как перехватить момент перед записью...?
Отправлено: item от 13 сентября 2025, 12:53
Цитата: Злоп от 13 сентября 2025, 11:50Репозиторий по 77 нужен ;-)
...

2 года держу домен  v77.by (http://v77.by) на эти цели, причем написать сервер исключительно на семерке.
Думаю, до 37-го справлюсь ))