Прогноз перепроведения документов: какие проводки изменятся, до того как перепровести. БП 3.0.194.23 и БП КОРП 3.0.201.16
Функция и обработка для скачивания проводят документы выбранного вида за период внутри транзакции, сравнивают движения и проводки до и после и отменяют транзакцию. В базе ничего не меняется, а на руках список: какие проводки исчезнут и какие появятся.
Задача
Бухгалтер собирается перепровести квартал: поменяли учетную политику, исправили документ задним числом, выписку загрузили раньше, чем ввели реализации. Перед этим он хочет знать, что именно поменяется в проводках. Отчетность за период может быть уже сдана, а после перепроведения прежних проводок не вернуть.
Групповое перепроведение меняет все сразу и ничего не показывает. Сравнить до и после можно только на копии базы: выгрузить оборотно-сальдовую ведомость, перепровести, выгрузить снова и сверять вручную. Это долго, и видно только итоговые суммы, а не документы.
Решение
Функция получает имя документа и период. Из метаданных она берет список регистров, по которым этот документ делает движения, и строит один пакет запросов на все эти регистры. Для регистра бухгалтерии берутся движения с субконто, поэтому видны счета и аналитика.
Затем открывается транзакция. Документы периода по очереди, в порядке времени, как при групповом перепроведении, читаются, проводятся заново и читаются снова. Каждый следующий документ видит результат предыдущих, поэтому себестоимость и зачет авансов считаются так же, как при настоящем перепроведении. В конце транзакция отменяется всегда, фиксации в коде нет.
Сравнение сделано без перебора строк. Движения до перепроведения попадают в таблицу со знаком плюс, движения после со знаком минус, и таблица сворачивается по всем колонкам. Совпавшие строки взаимно гасятся, остаются только те, что исчезнут ("было") или появятся ("станет"). Номер строки, регистратор и виды субконто не сравниваются. Документ, у которого ничего не меняется, попадает в результат одной строкой "без изменений", чтобы было видно, что он проверен.
Типичная находка выглядит так. Оплату от покупателя провели раньше, чем ввели реализацию за тот же день, и она ушла авансом на 62.02. При перепроведении оплата зачтется в счет реализации, а у организации на УСН с патентом доход переедет из книги учета доходов и расходов в книгу по патенту.
| Регистр | Изменение | Движение |
|---|---|---|
| Хозрасчетный | было | Дт 51 Кт 62.02, 48 000 |
| Хозрасчетный | станет | Дт 51 Кт 62.01, 48 000 |
| Хозрасчетный | станет | Кт УСН.03, 48 000, деятельность на патенте |
| Книга учета доходов и расходов | было | доход по УСН 48 000 |
| Книга учета доходов и расходов | станет | доход по патенту 48 000 |
| Книга учета доходов по патенту | станет | доход 48 000 |
Функция выполнена в обеих базах на реализациях, поступлениях товаров, поступлениях и списаниях с расчетного счета. Отдельно проверены документ в закрытом периоде, документ без движений и имя документа, которого нет в конфигурации.
// Прогноз перепроведения: документы выбранного вида за период проводятся заново
// внутри транзакции, движения до и после сравниваются, затем транзакция отменяется.
// В базе ничего не меняется. Документы идут в хронологическом порядке, как при
// групповом перепроведении, поэтому каждый следующий видит результат предыдущих.
// Пока транзакция открыта, регистры документов заблокированы: на рабочей базе
// ограничивайте число документов или запускайте в нерабочее время.
//
// Параметры:
// ИмяДокумента - Строка - имя документа в метаданных, например "РеализацияТоваровУслуг".
// НачалоПериода - Дата - начало периода.
// КонецПериода - Дата - конец периода.
// МаксимумДокументов - Число - сколько первых документов периода проверить.
//
// Возвращаемое значение:
// ТаблицаЗначений - Дата, Документ, Регистр, Изменение, Строк, Движение, по дате и
// номеру документа. Изменение: "было" (движение исчезнет), "станет" (появится),
// "без изменений" (документ проверен, движения те же) или "ошибка проведения":
// на таком документе проверка останавливается.
//
Функция ПрогнозПерепроведения(ИмяДокумента, НачалоПериода, КонецПериода, МаксимумДокументов) Экспорт
Различия = Новый ТаблицаЗначений;
Различия.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"), "Дата");
Различия.Колонки.Добавить("Документ", Новый ОписаниеТипов("Строка"), "Документ");
Различия.Колонки.Добавить("Регистр", Новый ОписаниеТипов("Строка"), "Регистр");
Различия.Колонки.Добавить("Изменение", Новый ОписаниеТипов("Строка"), "Изменение");
Различия.Колонки.Добавить("Строк", Новый ОписаниеТипов("Число"), "Строк");
Различия.Колонки.Добавить("Движение", Новый ОписаниеТипов("Строка"), "Движение");
// Служебные колонки для сортировки результата, в конце удаляются.
Различия.Колонки.Добавить("Номер");
Различия.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
МетаДокумента = Метаданные.Документы.Найти(ИмяДокумента);
Если МетаДокумента = Неопределено Тогда
ВызватьИсключение "В конфигурации нет документа " + ИмяДокумента;
КонецЕсли;
// Один пакет запросов читает все регистры, по которым документ делает движения.
// Имена таблиц берутся из метаданных, текст от пользователя в запрос не попадает.
// Для регистра бухгалтерии берется таблица движений с субконто.
ИменаРегистров = Новый Массив;
ТекстыЗапросов = Новый Массив;
Для Каждого МетаРегистра Из МетаДокумента.Движения Цикл
ПолноеИмя = МетаРегистра.ПолноеИмя();
Если Метаданные.РегистрыБухгалтерии.Содержит(МетаРегистра) Тогда
Источник = ПолноеИмя + ".ДвиженияССубконто(, , Регистратор = &Регистратор) КАК Т";
Иначе
Источник = ПолноеИмя + " КАК Т ГДЕ Т.Регистратор = &Регистратор";
КонецЕсли;
ИменаРегистров.Добавить(ПолноеИмя);
ТекстыЗапросов.Добавить("ВЫБРАТЬ * ИЗ " + Источник);
КонецЦикла;
Если ИменаРегистров.Количество() = 0 Тогда
ВызватьИсключение "Документ " + ИмяДокумента + " не делает движений";
КонецЕсли;
ЗапросДвижений = Новый Запрос(СтрСоединить(ТекстыЗапросов, ";" + Символы.ПС));
ЗапросДокументов = Новый Запрос(
"ВЫБРАТЬ ПЕРВЫЕ 1000
| Д.Ссылка КАК Ссылка,
| Д.Дата КАК Дата,
| Д.Номер КАК Номер,
| ПРЕДСТАВЛЕНИЕ(Д.Ссылка) КАК Представление
|ИЗ
| Документ." + МетаДокумента.Имя + " КАК Д
|ГДЕ
| Д.Проведен
| И Д.Дата МЕЖДУ &НачалоПериода И &КонецПериода
|
|УПОРЯДОЧИТЬ ПО
| Д.МоментВремени");
ЗапросДокументов.УстановитьПараметр("НачалоПериода", НачалоПериода);
ЗапросДокументов.УстановитьПараметр("КонецПериода", КонецПериода);
СписокДокументов = ЗапросДокументов.Выполнить().Выгрузить();
Пока СписокДокументов.Количество() > МаксимумДокументов Цикл
СписокДокументов.Удалить(СписокДокументов.Количество() - 1);
КонецЦикла;
// Фиксации нет намеренно: транзакция всегда отменяется.
// BSLLS:PairingBrokenTransaction-off
// BSLLS:WrongUseOfRollbackTransactionMethod-off
НачатьТранзакцию();
Попытка
Для Каждого СтрокаДокумента Из СписокДокументов Цикл
СтрокДоДокумента = Различия.Количество();
ЗапросДвижений.УстановитьПараметр("Регистратор", СтрокаДокумента.Ссылка);
ДоПроведения = ЗапросДвижений.ВыполнитьПакет();
ДокументОбъект = СтрокаДокумента.Ссылка.ПолучитьОбъект();
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
// После ошибки транзакция уже не принимает запросов: фиксируем причину и выходим.
НоваяСтрока = Различия.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДокумента, "Дата, Номер");
НоваяСтрока.Порядок = Различия.Количество();
НоваяСтрока.Документ = СтрокаДокумента.Представление;
НоваяСтрока.Изменение = "ошибка проведения";
НоваяСтрока.Движение = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
Прервать;
КонецПопытки;
ПослеПроведения = ЗапросДвижений.ВыполнитьПакет();
Для Индекс = 0 По ИменаРегистров.Количество() - 1 Цикл
// Строки "до" идут со знаком +1, строки "после" со знаком -1. После свертки
// по всем колонкам ненулевой остаток есть только у строк, которые изменятся.
Сводная = ДоПроведения[Индекс].Выгрузить();
Сводная.Колонки.Добавить("Знак", Новый ОписаниеТипов("Число"));
Сводная.ЗаполнитьЗначения(1, "Знак");
Выборка = ПослеПроведения[Индекс].Выбрать();
Пока Выборка.Следующий() Цикл
ЗаполнитьЗначенияСвойств(Сводная.Добавить(), Выборка);
КонецЦикла;
Для Каждого СтрокаСводной Из Сводная Цикл
Если СтрокаСводной.Знак = 0 Тогда
СтрокаСводной.Знак = -1;
КонецЕсли;
КонецЦикла;
// Служебные колонки не сравниваются: номер строки и регистратор при
// перепроведении не несут смысла, виды субконто видны по самим субконто.
Группировка = Новый Массив;
Для Каждого Колонка Из Сводная.Колонки Цикл
Если Колонка.Имя = "Знак" Или Колонка.Имя = "НомерСтроки" Или Колонка.Имя = "Регистратор"
Или СтрНачинаетсяС(Колонка.Имя, "ВидСубконто")
Или Колонка.ТипЗначения.СодержитТип(Тип("ХранилищеЗначения")) Тогда
Продолжить;
КонецЕсли;
Группировка.Добавить(Колонка.Имя);
КонецЦикла;
Сводная.Свернуть(СтрСоединить(Группировка, ","), "Знак");
Для Каждого СтрокаСводной Из Сводная Цикл
Если СтрокаСводной.Знак = 0 Тогда
Продолжить;
КонецЕсли;
Поля = Новый Массив;
Для Каждого ИмяКолонки Из Группировка Цикл
Значение = СтрокаСводной[ИмяКолонки];
Если ЗначениеЗаполнено(Значение) Тогда
Поля.Добавить(ИмяКолонки + ": " + Значение);
КонецЕсли;
КонецЦикла;
НоваяСтрока = Различия.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДокумента, "Дата, Номер");
НоваяСтрока.Порядок = Различия.Количество();
НоваяСтрока.Документ = СтрокаДокумента.Представление;
НоваяСтрока.Регистр = ИменаРегистров[Индекс];
НоваяСтрока.Изменение = ?(СтрокаСводной.Знак > 0, "было", "станет");
НоваяСтрока.Строк = ?(СтрокаСводной.Знак > 0, СтрокаСводной.Знак, -СтрокаСводной.Знак);
НоваяСтрока.Движение = СтрСоединить(Поля, "; ");
КонецЦикла;
КонецЦикла;
// Документ проверен, а различий нет: так и пишем, чтобы было видно, что проверено.
Если Различия.Количество() = СтрокДоДокумента Тогда
НоваяСтрока = Различия.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДокумента, "Дата, Номер");
НоваяСтрока.Порядок = Различия.Количество();
НоваяСтрока.Документ = СтрокаДокумента.Представление;
НоваяСтрока.Изменение = "без изменений";
КонецЕсли;
КонецЦикла;
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
ОтменитьТранзакцию();
// BSLLS:WrongUseOfRollbackTransactionMethod-on
// BSLLS:PairingBrokenTransaction-on
// Проводятся документы в порядке времени, как при групповом перепроведении, а в
// результате они идут по дате и номеру; внутри документа порядок строк сохраняется.
Различия.Сортировать("Дата, Номер, Порядок");
Различия.Колонки.Удалить("Номер");
Различия.Колонки.Удалить("Порядок");
Возврат Различия;
КонецФункции
// Прогноз перепроведения: документы выбранного вида за период проводятся заново
// внутри транзакции, движения до и после сравниваются, затем транзакция отменяется.
// В базе ничего не меняется. Документы идут в хронологическом порядке, как при
// групповом перепроведении, поэтому каждый следующий видит результат предыдущих.
// Пока транзакция открыта, регистры документов заблокированы: на рабочей базе
// ограничивайте число документов или запускайте в нерабочее время.
//
// Параметры:
// ИмяДокумента - Строка - имя документа в метаданных, например "РеализацияТоваровУслуг".
// НачалоПериода - Дата - начало периода.
// КонецПериода - Дата - конец периода.
// МаксимумДокументов - Число - сколько первых документов периода проверить.
//
// Возвращаемое значение:
// ТаблицаЗначений - Дата, Документ, Регистр, Изменение, Строк, Движение, по дате и
// номеру документа. Изменение: "было" (движение исчезнет), "станет" (появится),
// "без изменений" (документ проверен, движения те же) или "ошибка проведения":
// на таком документе проверка останавливается.
//
Функция ПрогнозПерепроведения(ИмяДокумента, НачалоПериода, КонецПериода, МаксимумДокументов) Экспорт
Различия = Новый ТаблицаЗначений;
Различия.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"), "Дата");
Различия.Колонки.Добавить("Документ", Новый ОписаниеТипов("Строка"), "Документ");
Различия.Колонки.Добавить("Регистр", Новый ОписаниеТипов("Строка"), "Регистр");
Различия.Колонки.Добавить("Изменение", Новый ОписаниеТипов("Строка"), "Изменение");
Различия.Колонки.Добавить("Строк", Новый ОписаниеТипов("Число"), "Строк");
Различия.Колонки.Добавить("Движение", Новый ОписаниеТипов("Строка"), "Движение");
// Служебные колонки для сортировки результата, в конце удаляются.
Различия.Колонки.Добавить("Номер");
Различия.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
МетаДокумента = Метаданные.Документы.Найти(ИмяДокумента);
Если МетаДокумента = Неопределено Тогда
ВызватьИсключение "В конфигурации нет документа " + ИмяДокумента;
КонецЕсли;
// Один пакет запросов читает все регистры, по которым документ делает движения.
// Имена таблиц берутся из метаданных, текст от пользователя в запрос не попадает.
// Для регистра бухгалтерии берется таблица движений с субконто.
ИменаРегистров = Новый Массив;
ТекстыЗапросов = Новый Массив;
Для Каждого МетаРегистра Из МетаДокумента.Движения Цикл
ПолноеИмя = МетаРегистра.ПолноеИмя();
Если Метаданные.РегистрыБухгалтерии.Содержит(МетаРегистра) Тогда
Источник = ПолноеИмя + ".ДвиженияССубконто(, , Регистратор = &Регистратор) КАК Т";
Иначе
Источник = ПолноеИмя + " КАК Т ГДЕ Т.Регистратор = &Регистратор";
КонецЕсли;
ИменаРегистров.Добавить(ПолноеИмя);
ТекстыЗапросов.Добавить("ВЫБРАТЬ * ИЗ " + Источник);
КонецЦикла;
Если ИменаРегистров.Количество() = 0 Тогда
ВызватьИсключение "Документ " + ИмяДокумента + " не делает движений";
КонецЕсли;
ЗапросДвижений = Новый Запрос(СтрСоединить(ТекстыЗапросов, ";" + Символы.ПС));
ЗапросДокументов = Новый Запрос(
"ВЫБРАТЬ ПЕРВЫЕ 1000
| Д.Ссылка КАК Ссылка,
| Д.Дата КАК Дата,
| Д.Номер КАК Номер,
| ПРЕДСТАВЛЕНИЕ(Д.Ссылка) КАК Представление
|ИЗ
| Документ." + МетаДокумента.Имя + " КАК Д
|ГДЕ
| Д.Проведен
| И Д.Дата МЕЖДУ &НачалоПериода И &КонецПериода
|
|УПОРЯДОЧИТЬ ПО
| Д.МоментВремени");
ЗапросДокументов.УстановитьПараметр("НачалоПериода", НачалоПериода);
ЗапросДокументов.УстановитьПараметр("КонецПериода", КонецПериода);
СписокДокументов = ЗапросДокументов.Выполнить().Выгрузить();
Пока СписокДокументов.Количество() > МаксимумДокументов Цикл
СписокДокументов.Удалить(СписокДокументов.Количество() - 1);
КонецЦикла;
// Фиксации нет намеренно: транзакция всегда отменяется.
// BSLLS:PairingBrokenTransaction-off
// BSLLS:WrongUseOfRollbackTransactionMethod-off
НачатьТранзакцию();
Попытка
Для Каждого СтрокаДокумента Из СписокДокументов Цикл
СтрокДоДокумента = Различия.Количество();
ЗапросДвижений.УстановитьПараметр("Регистратор", СтрокаДокумента.Ссылка);
ДоПроведения = ЗапросДвижений.ВыполнитьПакет();
ДокументОбъект = СтрокаДокумента.Ссылка.ПолучитьОбъект();
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
// После ошибки транзакция уже не принимает запросов: фиксируем причину и выходим.
НоваяСтрока = Различия.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДокумента, "Дата, Номер");
НоваяСтрока.Порядок = Различия.Количество();
НоваяСтрока.Документ = СтрокаДокумента.Представление;
НоваяСтрока.Изменение = "ошибка проведения";
НоваяСтрока.Движение = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
Прервать;
КонецПопытки;
ПослеПроведения = ЗапросДвижений.ВыполнитьПакет();
Для Индекс = 0 По ИменаРегистров.Количество() - 1 Цикл
// Строки "до" идут со знаком +1, строки "после" со знаком -1. После свертки
// по всем колонкам ненулевой остаток есть только у строк, которые изменятся.
Сводная = ДоПроведения[Индекс].Выгрузить();
Сводная.Колонки.Добавить("Знак", Новый ОписаниеТипов("Число"));
Сводная.ЗаполнитьЗначения(1, "Знак");
Выборка = ПослеПроведения[Индекс].Выбрать();
Пока Выборка.Следующий() Цикл
ЗаполнитьЗначенияСвойств(Сводная.Добавить(), Выборка);
КонецЦикла;
Для Каждого СтрокаСводной Из Сводная Цикл
Если СтрокаСводной.Знак = 0 Тогда
СтрокаСводной.Знак = -1;
КонецЕсли;
КонецЦикла;
// Служебные колонки не сравниваются: номер строки и регистратор при
// перепроведении не несут смысла, виды субконто видны по самим субконто.
Группировка = Новый Массив;
Для Каждого Колонка Из Сводная.Колонки Цикл
Если Колонка.Имя = "Знак" Или Колонка.Имя = "НомерСтроки" Или Колонка.Имя = "Регистратор"
Или СтрНачинаетсяС(Колонка.Имя, "ВидСубконто")
Или Колонка.ТипЗначения.СодержитТип(Тип("ХранилищеЗначения")) Тогда
Продолжить;
КонецЕсли;
Группировка.Добавить(Колонка.Имя);
КонецЦикла;
Сводная.Свернуть(СтрСоединить(Группировка, ","), "Знак");
Для Каждого СтрокаСводной Из Сводная Цикл
Если СтрокаСводной.Знак = 0 Тогда
Продолжить;
КонецЕсли;
Поля = Новый Массив;
Для Каждого ИмяКолонки Из Группировка Цикл
Значение = СтрокаСводной[ИмяКолонки];
Если ЗначениеЗаполнено(Значение) Тогда
Поля.Добавить(ИмяКолонки + ": " + Значение);
КонецЕсли;
КонецЦикла;
НоваяСтрока = Различия.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДокумента, "Дата, Номер");
НоваяСтрока.Порядок = Различия.Количество();
НоваяСтрока.Документ = СтрокаДокумента.Представление;
НоваяСтрока.Регистр = ИменаРегистров[Индекс];
НоваяСтрока.Изменение = ?(СтрокаСводной.Знак > 0, "было", "станет");
НоваяСтрока.Строк = ?(СтрокаСводной.Знак > 0, СтрокаСводной.Знак, -СтрокаСводной.Знак);
НоваяСтрока.Движение = СтрСоединить(Поля, "; ");
КонецЦикла;
КонецЦикла;
// Документ проверен, а различий нет: так и пишем, чтобы было видно, что проверено.
Если Различия.Количество() = СтрокДоДокумента Тогда
НоваяСтрока = Различия.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДокумента, "Дата, Номер");
НоваяСтрока.Порядок = Различия.Количество();
НоваяСтрока.Документ = СтрокаДокумента.Представление;
НоваяСтрока.Изменение = "без изменений";
КонецЕсли;
КонецЦикла;
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
ОтменитьТранзакцию();
// BSLLS:WrongUseOfRollbackTransactionMethod-on
// BSLLS:PairingBrokenTransaction-on
// Проводятся документы в порядке времени, как при групповом перепроведении, а в
// результате они идут по дате и номеру; внутри документа порядок строк сохраняется.
Различия.Сортировать("Дата, Номер, Порядок");
Различия.Колонки.Удалить("Номер");
Различия.Колонки.Удалить("Порядок");
Возврат Различия;
КонецФункцииЧто учесть
- Пока транзакция открыта, регистры документов заблокированы. На копии базы проверка документа заняла от долей секунды до нескольких секунд, на нагруженной рабочей базе доходило до минуты, и все это время пользователи ждут. Проверяйте на копии или в нерабочее время и начинайте с 5-20 документов.
- Документ в периоде, закрытом датой запрета изменения, не проводится: функция покажет причину и остановится. Чтобы проверить закрытый период, используйте копию базы, где дата запрета снята.
- После ошибки проведения 1С больше не выполняет запросов в этой транзакции, поэтому проверка останавливается на первом документе с ошибкой. Исправьте его или начните период после него.
- Проверка накопительная: изменения каждого документа учитывают перепроведение предыдущих. Чтобы увидеть один документ сам по себе, задайте период ровно на него.
- Сравниваются регистры из состава движений документа. Что проведение меняет в других объектах, например границы последовательностей, в таблицу не попадает, но тоже откатывается.
- Отменяется все, что записано в базу. Если доработанная обработка проведения отправляет письма, пишет файлы или вызывает внешние сервисы, это откатить нельзя. Типовая Бухгалтерия при проведении так не делает.
- Пользователь, от которого выполняется функция, должен иметь право проводить эти документы.
- В Управлении торговлей 11 и Комплексной автоматизации 2 проводки формируются не при проведении, а при отражении документов в регламентированном учете. Там функция покажет изменения оперативных регистров, а проводок не покажет.
- За один вызов проверяется не больше 1000 документов: столько отбирает запрос, дальше ограничивает параметр МаксимумДокументов.
Как воспользоваться
- Скачайте обработку под кодом и откройте ее в 1С через "Файл, Открыть". Выберите документ из списка: в нем все документы конфигурации, которые делают движения. Укажите период и сколько документов проверить, нажмите "Сформировать результат". Сначала попробуйте на копии базы.
- Результат идет по дате и номеру документа. Разбирайте его парами "было" и "станет" по одному документу и регистру: разница в них и есть то, что изменит перепроведение. Строка "без изменений" значит, что документ проверен и его движения останутся прежними.
- Нужно встроить в свою обработку: скопируйте функцию кнопкой над кодом в модуль объекта или общий серверный модуль и вызовите на сервере, например ПрогнозПерепроведения("ПоступлениеНаРасчетныйСчет", НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()), 20).
- Через Жёлтый мост то же самое можно попросить у ИИ: "покажи, что изменится в проводках, если перепровести поступления на расчетный счет за март". Мост выполнит код с откатом, в базе ничего не изменится.
Комментарии
Нашли ошибку в коде, знаете, как лучше, или запрос повел себя иначе в вашей конфигурации: напишите. Комментарии открываются после проверки, на вопросы отвечаем здесь же. Реклама и ссылки на посторонние сайты не проходят.