Skip to content

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

Merged
WonderMr merged 2 commits intodevelopfrom
feat/better_remove_dupes
Apr 28, 2026
Merged

Защита регистров бухгалтерии при замене ссылок и доводка SQL-генератора#4
WonderMr merged 2 commits intodevelopfrom
feat/better_remove_dupes

Conversation

@WonderMr
Copy link
Copy Markdown
Owner

@WonderMr WonderMr commented Apr 28, 2026

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

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

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

Защита регистров бухгалтерии в пути "Объект"
(УИ_ОбщегоНазначения/Module.bsl, ИзмененныеОбъектыПриЗаменеВОбъекте):

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

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

  • Автоопределение СУБД через парсинг СтрокаСоединенияИнформационнойБазы() по подстроке DBMS=POSTGRESQL / DBMS=MSSQLSERVER. Если определилось - выводится только нужная секция, иначе обе, но MS SQL предваряется префиксом "-- " (приоритет для PG).
  • Корректный порядок байт 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-скрипт были скрыты от пользователя: виден был только список необработанных дублей

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

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

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com


Note

High Risk
Changes core link-replacement/delete-duplicates flow, including special-casing accounting registers and generating SQL UPDATE scripts, which can directly impact financial register data integrity if incorrect.

Overview
Protects accounting registers during duplicate cleanup by skipping platform-based link replacement for РегистрыБухгалтерии, recording affected pairs into ЗаменыТребующиеSQL, and surfacing a synthesized ТребуетсяSQL_Итог entry with a generated SQL script.

Adds an SQL generator (СгенерироватьSQLСкриптЗамены) that inspects DB storage structure, detects PostgreSQL vs MS SQL, and emits resilient per-field UPDATEs (with TRY/CATCH or EXCEPTION handling) while skipping totals/settings tables; also adds cleanup for post-replacement key collisions in information registers.

Improves UX and operability in the “Поиск и удаление дублей” form: adds “check/uncheck all” commands, streams deletion progress from the registration log into a new ЖурналУдаления field (including SQL script), and allows canceling the running background job from the wizard.

Reviewed by Cursor Bugbot for commit 438b4aa. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI review requested due to automatic review settings April 28, 2026 16:53
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

PR дополняет механизм замены ссылок при удалении дублей: защищает движения регистров бухгалтерии от некорректной перезаписи через Выгрузить()/Загрузить() и добавляет генерацию SQL-скрипта для довыполнения замены в PostgreSQL / MS SQL Server, а также улучшает UX (SQL и лог выводятся в журнал формы, включая шаг “неудачные замены”).

Changes:

  • В пути замены “Объект” добавлен skip для регистров бухгалтерии с накоплением пар замен в ЗаменыТребующиеSQL и последующей генерацией SQL.
  • Доработан СгенерироватьSQLСкриптЗамены: определение DBMS по строке соединения, корректное преобразование ссылок в hex, пропуск итоговых/служебных таблиц, TRY/CATCH (MS SQL) и DO/EXCEPTION (PG).
  • В форме “Поиск и удаление дублей” SQL-скрипт больше не показывается модальным сообщением: он дописывается в конец журнала; на шаге неудачных замен добавлено поле для показа лога.

Reviewed changes

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

File Description
src/Инструменты/src/CommonModules/УИ_ОбщегоНазначения/Module.bsl Защита движений РБ в пути “Объект” + генератор SQL для PG/MS SQL + преобразование ссылок в hex.
src/Инструменты/src/DataProcessors/УИ_ПоискИУдалениеДублей/Forms/ПоискДублей/Module.bsl Сбор SQL-скрипта в текстовый параметр, дописывание в журнал, изменение критерия “успешности” с учётом ТребуетсяSQL*.
src/Инструменты/src/DataProcessors/УИ_ПоискИУдалениеДублей/Forms/ПоискДублей/Form.form Поле журнала на шаге “неудачные замены” для показа лога/SQL пользователю.

Issues found (need fixes):

  • В генераторе PostgreSQL DO-блок закрывается строкой END $$;. Для PL/pgSQL нужен END; (точка с запятой после END) и затем закрытие тела $$;. В текущем виде сгенерированный PG-скрипт будет падать с синтаксической ошибкой на каждом DO $$ ....
  • В ИзмененныеОбъектыПриЗаменеВОбъекте переменная цикла Для Каждого МестоИспользования Из ОбрабатываемыеСтроки переиспользует имя входного параметра МестоИспользования, затирая его значение (в 1С это одна и та же переменная). Это ухудшает читаемость и повышает риск регрессий при будущих правках — лучше переименовать переменную цикла (например, СтрокаИспользования).

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

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c59d68a. Configure here.

Comment thread .github/ISSUE_TEMPLATE/------------------------.md Outdated
AlZh-Mex and others added 2 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>
@WonderMr WonderMr force-pushed the feat/better_remove_dupes branch from 5932976 to 438b4aa Compare April 28, 2026 17:31
@WonderMr WonderMr merged commit 7c62d3a into develop Apr 28, 2026
2 of 5 checks passed
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.

3 participants