Skip to content

Улучшение механизма поиска и удаления дублей#795

Open
WonderMr wants to merge 3 commits intocpr1c:developfrom
WonderMr:develop
Open

Улучшение механизма поиска и удаления дублей#795
WonderMr wants to merge 3 commits intocpr1c:developfrom
WonderMr:develop

Conversation

@WonderMr
Copy link
Copy Markdown

@WonderMr WonderMr commented Apr 28, 2026

Улучшение поиска и удаления дублей + защита регистров бухгалтерии

Краткое описание

Доработка механизма поиска и удаления дублей в подсистеме «Инструменты разработчика»:
устранены критичные баги (некорректная логика транзакций, потеря субконто в регистрах бухгалтерии, ошибка дублирующихся ключей в регистрах сведений), добавлены пользовательский журнал удаления и отмена длительной операции, реализована автогенерация SQL-скрипта для PostgreSQL/MS SQL, чтобы добить замены, которые нельзя сделать через 1С (регистры бухгалтерии).

Изменения разделены на два коммита: первый - функциональные доработки и UX, второй - защита регистров бухгалтерии и SQL-генератор.


Коммит 1 - 3fcb1273 Улучшение механизма поиска и удаления дублей

Транзакционная логика замены ссылок

  • Убран внутренний Попытка/Исключение в первом проходе записи, который приводил к ошибке «В данной транзакции уже происходили ошибки» и блокировал запись всех объектов батча.
  • Удалён первый «проверочный» проход записи как избыточный - проверка циклических ссылок уже выполняется в ЗаписатьОбъектПриЗаменеСсылок.

Дедупликация ключей регистров сведений

  • Добавлена процедура УдалитьДубликатыКлючейРегистраСведений. После замены ссылок в движениях процедура удаляет записи с дублирующимися ключевыми полями (Период + все Измерения), предотвращая ошибку «Запись с такими ключевыми полями существует».

Журнал удаления дублей на форме

  • Добавлено поле лога на страницу удаления (ЖурналУдаления) - многострочное, на всю ширину, только чтение, с автопрокруткой вниз.
  • Прогресс пишется в Журнал Регистрации (событие «Поиск и удаление ссылок.Прогресс») с режимом Независимая - записи не теряются при откате транзакций.
  • Клиент читает ЖР при каждом опросе прогресса, отображает полный лог с коррекцией на клиентское время (смещение клиент-сервер).
  • По каждому дублю пишется итоговая запись (✓ успех / ✗ ошибка). По каждому месту использования - запись с именем дубля и объекта.
  • Счётчик «обработано X из Y» в заголовке формы считает итоговые записи из ЖР.
  • Лог сохраняется на странице успешного удаления с итогом в конце.
  • Скрыт старый SpreadsheetDocument и отдельная надпись результата.

Отмена фонового задания

  • Кнопка «Прервать» теперь реально отменяет фоновое задание через УИ_ДлительныеОперации.ОтменитьВыполнениеЗадания, а не просто закрывает форму.
  • Идентификатор задания сохраняется в реквизите формы.

Коммит 2 - 438b4aaa Защита регистров бухгалтерии при замене ссылок и доводка SQL-генератора

Этот коммит исправляет критический баг с ОСВ после удаления дублей в Бухгалтерии и доводит SQL-генератор до рабочего состояния для PostgreSQL и MS SQL Server.

Корневая причина бага с ОСВ

  • В пути «Объект» функция ИзмененныеОбъектыПриЗаменеВОбъекте обрабатывала движения регистров бухгалтерии через Выгрузить → модификация → Загрузить → Записать(). Для регистра с составными субконто (3 уровня Дт+Кт) Выгрузить включает виртуальные поля ВидСубконтоДт*/Кт*, а Записать() выполняет DELETE+INSERT. Платформа некорректно восстанавливает виртуальные типы при INSERT, что перераспределяет субконто на другой объект того же типа.
  • Аналогичная защита уже была в пути «КлючЗаписи» (ПроизвестиЗаменуВНаборе, стр. 3855), но отсутствовала в пути «Объект».

Защита регистров бухгалтерии в пути «Объект»

Файл: УИ_ОбщегоНазначения/Module.bsl, функция ИзмененныеОбъектыПриЗаменеВОбъекте.

  • Сигнатура расширена параметром Результат (для накопления ЗаменыТребующиеSQL).
  • Построение ПарыЗамен перенесено до цикла чтения движений.
  • Для каждого ОписаниеДвижения проверяется тип регистра: если регистр бухгалтерии - помечается флагом ПропуститьИзЗаРБ, накапливаются пары через НакопитьЗаменуДляSQL, пишется информационная запись в Журнал Регистрации. Набор записей не читается и не модифицируется.
  • Во всех трёх последующих циклах по ОписаниеДвижений добавлен skip-фильтр по флагу ПропуститьИзЗаРБ. Замена выполняется SQL-скриптом после операции.

SQL-генератор замены ссылок (СгенерироватьSQLСкриптЗамены)

  • Автоопределение СУБД через парсинг СтрокаСоединенияИнформационнойБазы() по подстроке DBMS=POSTGRESQL / DBMS=MSSQLSERVER. Если определилось - выводится только нужная секция; иначе обе, но MS SQL предваряется префиксом -- - приоритет для PostgreSQL.
  • Корректный порядок байт UUID при формировании decode/0x литералов (СсылкаВHex). 1С хранит ссылки в bytea (PG) / varbinary(16) (MS SQL) с полным реверсом сегментов UUID v1: stored = clock_seq(2) + node(6) + timestamp_hi+ver(2) + timestamp_mid(2) + timestamp_low(4), что в hex даёт перестановку chars[17..32] + chars[13..16] + chars[9..12] + chars[1..8].
  • Пропуск итоговых и служебных таблиц регистров бухгалтерии и накопления (Назначение содержит «ИТОГ» или «НАСТРОЙК»: _AccRgAT*, _AccRgCT*, _AccRgOpt*, _AccumRgT*, _AccumRgOpt*). UPDATE по ним вызывает конфликты UNIQUE constraint (когда у Дубля и Оригинала совпадают остальные ключевые поля) и не имеет смысла - итоги пересчитываются автоматически.
  • Изоляция ошибок: каждый UPDATE обёрнут в DO-блок с EXCEPTION (PG) и BEGIN TRY / BEGIN CATCH (MS SQL). При несовместимости типов (например, _KindDt*/_KindCt* фактически NUMERIC, а не bytea) или конфликте уникальности скрипт логирует пропуск через RAISE NOTICE / PRINT и продолжает выполнение, не откатывая транзакцию.
  • В шапку SQL добавлено напоминание о необходимости запустить Пересчёт итогов в 1С после применения скрипта.

Вывод SQL-скрипта в форму лога

Файл: Forms/ПоискДублей/Module.bsl.

  • ЗаполнитьРезультатыУдаленияДублей: добавлен out-параметр ТекстSQLСкрипта - SQL собирается в параметр и дописывается в ЖурналУдаления вызывающим кодом.
  • Логика ЗавершеноБезОшибок теперь игнорирует ошибки с типом ТребуетсяSQL_Итог и ТребуетсяSQL: операция считается успешной, если других (реальных) ошибок не возникло. До этого фикса форма после защиты РБ всегда уходила на ШагНеудачныеЗамены даже для штатно отработавших замен.
  • Обработчик завершения фонового задания дописывает SQL в конец ЖурналУдаления с разделителями === SQL-СКРИПТ ДЛЯ ДОВЫПОЛНЕНИЯ ЗАМЕН ===.

Поле лога на шаге неудачных замен

Файл: Forms/ПоискДублей/Form.form.

  • На шаг ШагНеудачныеЗамены добавлено поле ЖурналУдаленияНеудача (InputField, multiLine, readOnly), биндится к реквизиту ЖурналУдаления - тому же, что и ЖурналУдаленияУспех на шаге успеха.
  • До этого при реальных ошибках лог и SQL-скрипт были скрыты от пользователя: виден был только список необработанных дублей.

Изменённые файлы

  • src/Инструменты/src/CommonModules/УИ_ОбщегоНазначения/Module.bsl - защита РБ в пути «Объект», SQL-генератор, дедупликация ключей РС.
  • src/Инструменты/src/DataProcessors/УИ_ПоискИУдалениеДублей/Forms/ПоискДублей/Module.bsl - журнал удаления, отмена ФЗ, обработка результата с SQL-скриптом.
  • src/Инструменты/src/DataProcessors/УИ_ПоискИУдалениеДублей/Forms/ПоискДублей/Form.form - поля журнала на страницах успеха и неудачи, перенос блока «Все места использования».

Инструкция по применению

  1. «Поиск и удаление дублей» → выбрать пары → «Удалить».
  2. После завершения операции скопировать SQL-скрипт из ЖурналУдаления (PG / MS SQL секция выводится автоматически в зависимости от текущей СУБД).
  3. Выполнить SQL в клиенте СУБД (DataGrip, psql, SSMS).
  4. В 1С запустить Пересчёт итогов (Все функции → Стандартные → Управление итогами или РегистрыБухгалтерии.<Имя>.ПересчитатьИтоги()).
  5. Запустить «Удаление помеченных объектов» для физического удаления дублей.

План тестирования

  • Дубли с движениями по регистрам сведений с потенциально дублирующимися ключевыми полями (Период + Измерения) - проверить, что УдалитьДубликатыКлючейРегистраСведений отрабатывает без ошибки «Запись с такими ключевыми полями существует».
  • Дубли с движениями по регистрам бухгалтерии с составными субконто (≥ 2 уровней Дт/Кт). Сценарий: до удаления - снять ОСВ по контрольному счёту; удалить дубли; применить SQL-скрипт; пересчитать итоги; снять ОСВ повторно - субконто не должны перераспределиться.
  • PostgreSQL: запуск SQL-скрипта целиком в psql / DataGrip. Проверить отсутствие синтаксических ошибок и попадание RAISE NOTICE в лог при несовместимости типов.
  • MS SQL Server: то же самое.
  • Прерывание длительной операции через кнопку «Прервать» - фоновое задание реально останавливается, форма не виснет.
  • Журнал удаления отображает прогресс в реальном времени и сохраняется на финальной странице (как успеха, так и ошибки).

AlZh-Mex and others added 3 commits April 28, 2026 21:31
Исправление транзакционной логики замены ссылок:
- Убран внутренний Попытка/Исключение в первом проходе записи, который
  приводил к ошибке "В данной транзакции уже происходили ошибки" и блокировал
  запись всех объектов батча
- Убран первый проход записи (проверочный блок) как избыточный — проверка
  циклических ссылок уже выполняется в ЗаписатьОбъектПриЗаменеСсылок

Дедупликация ключей регистров сведений:
- Добавлена процедура УдалитьДубликатыКлючейРегистраСведений — после замены
  ссылок в движениях удаляет записи с дублирующимися ключевыми полями
  (Период + все Измерения), предотвращая ошибку "Запись с такими ключевыми
  полями существует"

Журнал удаления дублей на форме:
- Добавлено поле лога на страницу удаления (ЖурналУдаления) — многострочное,
  на всю ширину, только чтение, с автопрокруткой вниз
- Прогресс пишется в Журнал Регистрации (событие "Поиск и удаление ссылок.Прогресс")
  с режимом Независимая — записи не теряются при откате транзакций
- Клиент читает ЖР при каждом опросе прогресса, отображает полный лог
  с коррекцией на клиентское время (смещение клиент-сервер)
- По каждому дублю пишется итоговая запись (✓ успех / ✗ ошибка)
- По каждому месту использования пишется запись с именем дубля и объекта
- Счётчик "обработано X из Y" в заголовке считает итоговые записи из ЖР
- Лог сохраняется на странице успешного удаления с итогом в конце
- Скрыт старый SpreadsheetDocument и отдельная надпись результата

Отмена фонового задания:
- Кнопка "Прервать" теперь реально отменяет фоновое задание через
  УИ_ДлительныеОперации.ОтменитьВыполнениеЗадания, а не просто закрывает форму
- Идентификатор задания сохраняется в реквизите формы

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Дополнение к c40603f — устранение критического бага с ОСВ после удаления
дублей в Бухгалтерии Казахстана и доведение SQL-генератора до рабочего
состояния для PostgreSQL и MS SQL Server.

Корневая причина бага с ОСВ:
- В пути "Объект" функция ИзмененныеОбъектыПриЗаменеВОбъекте обрабатывала
  движения регистров бухгалтерии через Выгрузить → модификация → Загрузить →
  Записать(). Для регистра с составными субконто (3 уровня Дт+Кт) Выгрузить
  включает виртуальные поля ВидСубконтоДт*/Кт*, а Записать() выполняет
  DELETE+INSERT. Платформа некорректно восстанавливает виртуальные типы при
  INSERT, что перераспределяет субконто на другой объект того же типа
- Аналогичная защита УЖЕ БЫЛА в пути "КлючЗаписи" (ПроизвестиЗаменуВНаборе,
  стр. 3855), но отсутствовала в пути "Объект"
- Симптом: по счёту 1310 одна номенклатура показывала Дт=359380 Кт=566742
  сальдо=-207362, общий итог при этом сходился — записи остались, но
  Субконто Дт1 перераспределилось

Защита регистров бухгалтерии в пути "Объект"
(УИ_ОбщегоНазначения/Module.bsl, ИзмененныеОбъектыПриЗаменеВОбъекте):
- Сигнатура расширена параметром Результат (для накопления ЗаменыТребующиеSQL)
- Построение ПарыЗамен перенесено до цикла чтения движений
- Для каждого ОписаниеДвижения проверяется тип регистра: если регистр
  бухгалтерии — помечаем флагом ПропуститьИзЗаРБ, накапливаем пары через
  НакопитьЗаменуДляSQL, пишем информационную запись в Журнал Регистрации.
  Набор записей не читается и не модифицируется
- Во всех трёх последующих циклах по ОписаниеДвижений добавлен skip-фильтр
  по флагу ПропуститьИзЗаРБ. Замена выполняется SQL-скриптом после операции

SQL-генератор замены ссылок (СгенерироватьSQLСкриптЗамены):
- Автоопределение СУБД через парсинг СтрокаСоединенияИнформационнойБазы()
  по подстроке DBMS=POSTGRESQL / DBMS=MSSQLSERVER. Если определилось —
  выводится только нужная секция, иначе обе, но MS SQL предваряется
  префиксом "-- ", чтобы запуск всего файла в PG-клиенте не падал на
  синтаксисе BEGIN TRY
- Корректный порядок байт UUID при формировании decode/0x литералов
  (СсылкаВHex). 1С хранит ссылки в bytea PG / varbinary(16) MS SQL с
  полным реверсом сегментов UUID v1: stored = clock_seq(2) + node(6) +
  timestamp_hi+ver(2) + timestamp_mid(2) + timestamp_low(4), что в hex
  даёт перестановку chars[17..32] + chars[13..16] + chars[9..12] +
  chars[1..8]. Подтверждено сравнением реального содержимого _RecorderRRef
  в БД с XMLString ссылки документа. Без свопа UPDATE даёт 0 affected rows
- Пропуск итоговых и служебных таблиц регистров бухгалтерии и накопления
  (Назначение содержит "ИТОГ" или "НАСТРОЙК": _AccRgAT*, _AccRgCT*,
  _AccRgOpt*, _AccumRgT*, _AccumRgOpt*). UPDATE по ним вызывает конфликты
  UNIQUE constraint (когда у Дубля и Оригинала совпадают остальные ключевые
  поля) и не имеет смысла — итоги пересчитываются автоматически
- Каждый UPDATE обёрнут в DO-блок с EXCEPTION (PG) и BEGIN TRY / BEGIN CATCH
  (MS SQL). При несовместимости типов (например _KindDt*/_KindCt* фактически
  NUMERIC, а не bytea) или конфликте уникальности скрипт логирует пропуск
  через RAISE NOTICE / PRINT и продолжает выполнение, не откатывая транзакцию
- В шапку SQL добавлено напоминание о необходимости запустить Пересчёт
  итогов в 1С после применения скрипта

Вывод SQL-скрипта в форму лога вместо модального попапа
(Forms/ПоискДублей/Module.bsl):
- ЗаполнитьРезультатыУдаленияДублей: добавлен out-параметр ТекстSQLСкрипта,
  удалён вызов Сообщить() — SQL собирается в параметр и дописывается в
  ЖурналУдаления вызывающим кодом, не показывается всплывающим окном
- Логика ЗавершеноБезОшибок теперь игнорирует ошибки с типом
  ТребуетсяSQL_Итог и ТребуетсяSQL: операция считается успешной, если
  других (реальных) ошибок не возникло. До этого фикса форма после защиты
  РБ всегда уходила на ШагНеудачныеЗамены даже для штатно отработавших замен
- Обработчик завершения фонового задания дописывает SQL в конец
  ЖурналУдаления с разделителями "=== SQL-СКРИПТ ДЛЯ ДОВЫПОЛНЕНИЯ ЗАМЕН ==="

Поле лога на шаге неудачных замен (Forms/ПоискДублей/Form.form):
- На шаг ШагНеудачныеЗамены добавлено поле ЖурналУдаленияНеудача
  (InputField, multiLine, readOnly), биндится к реквизиту ЖурналУдаления —
  тому же что и ЖурналУдаленияУспех на шаге успеха
- До этого при реальных ошибках лог и SQL-скрипт были скрыты от пользователя:
  виден был только список необработанных дублей

Инструкция по применению:
1. "Поиск и удаление дублей" → выбрать пары → "Удалить"
2. Скопировать SQL-скрипт из ЖурналУдаления (PG/MS SQL секция выводится
   автоматически в зависимости от текущей СУБД)
3. Выполнить SQL в клиенте СУБД (DataGrip, psql, SSMS)
4. В 1С запустить Пересчёт итогов (Все функции → Стандартные → Управление
   итогами или РегистрыБухгалтерии.<Имя>.ПересчитатьИтоги() в коде)
5. Запустить "Удаление помеченных объектов" для физического удаления дублей

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Защита регистров бухгалтерии при замене ссылок и доводка SQL-генератора
Copilot AI review requested due to automatic review settings April 28, 2026 17:45
@sonar-openbsl-ru-qa-bot
Copy link
Copy Markdown

Failed Quality Gate failed

  • 74 New Issues (is greater than 0)

Project ID: tools_ui_1c

View in SonarQube

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Pull request дорабатывает обработку «Поиск и удаление дублей» в подсистеме «Инструменты разработчика»: исправляет проблемные места при замене ссылок (в т.ч. регистры бухгалтерии), добавляет подробный пользовательский лог и поддержку отмены, а также формирует SQL-скрипт для «довыполнения» замен на уровне СУБД.

Changes:

  • Добавлен пользовательский журнал удаления на форме (чтение прогресса из Журнала регистрации), автопрокрутка и вывод SQL-скрипта в лог.
  • Реализована защита регистров бухгалтерии при замене ссылок в пути «Объект» через пропуск движений и накопление замен для последующего SQL.
  • Добавлены: генератор SQL для PostgreSQL/MS SQL и удаление дублей ключей регистров сведений после замены.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/Инструменты/src/CommonModules/УИ_ОбщегоНазначения/Module.bsl Защита регистров бухгалтерии в обработке движений, накопление замен “требуется SQL”, генерация SQL-скрипта, дедупликация ключей РС.
src/Инструменты/src/DataProcessors/УИ_ПоискИУдалениеДублей/Forms/ПоискДублей/Module.bsl Отмена фонового задания, чтение/отображение лога из ЖР, финализация результата удаления и дописывание SQL в лог.
src/Инструменты/src/DataProcessors/УИ_ПоискИУдалениеДублей/Forms/ПоискДублей/Form.form Поля многострочного read-only лога на шагах удаления/успеха/неудачи, привязка к реквизиту формы.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@LevkinSergey
Copy link
Copy Markdown
Member

@WonderMr сможешь поправить замечания сонара?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants