Сервис доступа к данным 1С для внешних систем
Жёлтый мост
Код · Программисту 1С

Прогноз перепроведения документов: какие проводки изменятся, до того как перепровести. БП 3.0.194.23 и БП КОРП 3.0.201.16

Функция и обработка для скачивания проводят документы выбранного вида за период внутри транзакции, сравнивают движения и проводки до и после и отменяют транзакцию. В базе ничего не меняется, а на руках список: какие проводки исчезнут и какие появятся.

Бухгалтерия предприятия 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

	// Проводятся документы в порядке времени, как при групповом перепроведении, а в
	// результате они идут по дате и номеру; внутри документа порядок строк сохраняется.
	Различия.Сортировать("Дата, Номер, Порядок");
	Различия.Колонки.Удалить("Номер");
	Различия.Колонки.Удалить("Порядок");

	Возврат Различия;

КонецФункции
Обработка для Бухгалтерия предприятия 3.0.194.23Открыть через "Файл, Открыть", выбрать даты, нажать "Сформировать результат". Ничего не пишет в базу, работает от прав пользователя.
Скачать .epf
Обработка для Бухгалтерия предприятия КОРП 3.0.201.16Открыть через "Файл, Открыть", выбрать даты, нажать "Сформировать результат". Ничего не пишет в базу, работает от прав пользователя.
Скачать .epf

Что учесть

Как воспользоваться

  1. Скачайте обработку под кодом и откройте ее в 1С через "Файл, Открыть". Выберите документ из списка: в нем все документы конфигурации, которые делают движения. Укажите период и сколько документов проверить, нажмите "Сформировать результат". Сначала попробуйте на копии базы.
  2. Результат идет по дате и номеру документа. Разбирайте его парами "было" и "станет" по одному документу и регистру: разница в них и есть то, что изменит перепроведение. Строка "без изменений" значит, что документ проверен и его движения останутся прежними.
  3. Нужно встроить в свою обработку: скопируйте функцию кнопкой над кодом в модуль объекта или общий серверный модуль и вызовите на сервере, например ПрогнозПерепроведения("ПоступлениеНаРасчетныйСчет", НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()), 20).
  4. Через Жёлтый мост то же самое можно попросить у ИИ: "покажи, что изменится в проводках, если перепровести поступления на расчетный счет за март". Мост выполнит код с откатом, в базе ничего не изменится.
Свои задачи таким же способом. Подключение занимает около пятнадцати минут: обработка из кабинета, ключ, готовый текст для ИИ. При регистрации даются три дня работы одной базы, карта не нужна.
Подключить свою базу Другие решения

Комментарии

Нашли ошибку в коде, знаете, как лучше, или запрос повел себя иначе в вашей конфигурации: напишите. Комментарии открываются после проверки, на вопросы отвечаем здесь же. Реклама и ссылки на посторонние сайты не проходят.