При организации обмена данными между информационными базами 1С нередко возникает необходимость проверить корректность переноса проводок. Задача усложняется тем, что документы могут перепроводиться или изменяться в базе-источнике, а итоговые данные бухгалтерского учета должны сходиться «в ноль». При этом требуется выполнить детальную сверку всех реквизитов, ресурсов и аналитики (включая субконто, валютные суммы и количество) и получить быстрый результат — признак соответствия (Истина/Ложь) по каждому документу-регистратору.
Разберем основные технические нюансы таких сверок и рассмотрим наиболее эффективные способы решения задачи.
Прежде чем приступать к программному сравнению наборов записей, проанализируем факторы, которые могут приводить к ложным расхождениям:
Активность = Ложь), например, при ручном отключении проводок или сторнировании. При выборке данных важно явно фильтровать только активные записи.Субконто1, Субконто2, Субконто3. Если в планах счетов двух баз порядок видов субконто на счете не совпадает, одинаковая аналитика попадет в разные колонки.НомерСтроки): проводки могут быть идентичны по дебету, кредиту, суммам и аналитике, но иметь разные номера строк из-за перепроведения. При детальном сравнении поле НомерСтроки обычно исключают из сопоставления.Если требуется получить однозначный результат «Истина/Ложь» по каждому регистратору с минимальной нагрузкой на каналы связи, наиболее быстрым вариантом является расчет контрольной суммы проводок документа. Рассмотрим этот алгоритм.
Для каждого документа в обеих базах формируется каноническая строка из упорядоченных полей проводок, после чего рассчитывается хеш через объект платформы ХешированиеДанных.
Функция ПолучитьХешПроводокДокумента(СсылкаНаДокумент) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Хозрасчетный.СчетДт.Код КАК СчетДт,
| Хозрасчетный.СчетКт.Код КАК СчетКт,
| Хозрасчетный.СубконтоДт1,
| Хозрасчетный.СубконтоДт2,
| Хозрасчетный.СубконтоДт3,
| Хозрасчетный.СубконтоКт1,
| Хозрасчетный.СубконтоКт2,
| Хозрасчетный.СубконтоКт3,
| Хозрасчетный.Сумма КАК Сумма,
| Хозрасчетный.КоличествоДт КАК КоличествоДт,
| Хозрасчетный.КоличествоКт КАК КоличествоКт,
| Хозрасчетный.ВалютнаяСуммаДт КАК ВалютнаяСуммаДт,
| Хозрасчетный.ВалютнаяСуммаКт КАК ВалютнаяСуммаКт
|ИЗ
| РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
|ГДЕ
| Хозрасчетный.Регистратор = &Регистратор
| И Хозрасчетный.Активность = ИСТИНА
|УПОРЯДОЧИТЬ ПО
| СчетДт,
| СчетКт,
| Сумма";
Запрос.УстановитьПараметр("Регистратор", СсылкаНаДокумент);
Выборка = Запрос.Выполнить().Выбрать();
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписьXML.ЗаписатьНачалоЭлемента("Movements");
Пока Выборка.Следующий() Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("Row");
ЗаписьXML.ЗаписатьАтрибут("AccountDr", XMLСтрока(Выборка.СчетДт));
ЗаписьXML.ЗаписатьАтрибут("AccountCr", XMLСтрока(Выборка.СчетКт));
ЗаписьXML.ЗаписатьАтрибут("Amount", XMLСтрока(Выборка.Сумма));
ЗаписьXML.ЗаписатьАтрибут("QtyDr", XMLСтрока(Выборка.КоличествоДт));
ЗаписьXML.ЗаписатьАтрибут("QtyCr", XMLСтрока(Выборка.КоличествоКт));
ЗаписьXML.ЗаписатьАтрибут("CurAmountDr", XMLСтрока(Выборка.ВалютнаяСуммаДт));
ЗаписьXML.ЗаписатьАтрибут("CurAmountCr", XMLСтрока(Выборка.ВалютнаяСуммаКт));
ЗаписьXML.ЗаписатьКонецЭлемента();
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента();
СтрокаXML = ЗаписьXML.Закрыть();
Хеширование = Новый ХешированиеДанных(ХешФункция.MD5);
Хеширование.Добавить(СтрокаXML);
Возврат СтрЗаменить(Строка(Хеширование.ХешСумма), " ", "");
КонецФункции
Сравнивая полученные хеш-строки для одного и того же регистратора из базы-источника и базы-приемника, мы моментально получаем статус идентичности без передачи полных таблиц движений.
Посмотрим на классический аналитический подход, позволяющий не только зафиксировать факт расхождения, но и наглядно увидеть, в каких именно ресурсах и проводках возникла разница.
Разберем логику по шагам:
ТаблицаЗначений. Числовые ресурсы (сумма, количество, валютная сумма) оставляем со знаком «плюс».-1.Свернуть(), указав в качестве группировочных колонок счета и аналитику, а в качестве суммируемых — ресурсы.
// Пример свертки объединенной таблицы движений
КолонкиГруппировки = "СчетДт,СчетКт,СубконтоДт1,СубконтоДт2,СубконтоДт3,СубконтоКт1,СубконтоКт2,СубконтоКт3";
КолонкиСуммирования = "Сумма,КоличествоДт,КоличествоКт,ВалютнаяСуммаДт,ВалютнаяСуммаКт";
ТаблицаСверки.Свернуть(КолонкиГруппировки, КолонкиСуммирования);
// Поиск расхождений
Индекс = ТаблицаСверки.Количество() - 1;
Пока Индекс >= 0 Цикл
СтрокаТЗ = ТаблицаСверки[Индекс];
Если СтрокаТЗ.Сумма = 0
И СтрокаТЗ.КоличествоДт = 0
И СтрокаТЗ.КоличествоКт = 0
И СтрокаТЗ.ВалютнаяСуммаДт = 0
И СтрокаТЗ.ВалютнаяСуммаКт = 0 Тогда
ТаблицаСверки.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
// Если ТаблицаСверки.Количество() = 0 — наборы записей идентичны
Если обе таблицы движений передаются в один контекст выполнения запроса (например, через менеджер временных таблиц), наиболее строгим методом является ПОЛНОЕ СОЕДИНЕНИЕ.
ВЫБРАТЬ
ЕСТЬNULL(Таб1.Регистратор, Таб2.Регистратор) КАК Регистратор,
ЕСТЬNULL(Таб1.Сумма, 0) - ЕСТЬNULL(Таб2.Сумма, 0) КАК РазницаСуммы
ИЗ
вт_ДвиженияБаза1 КАК Таб1
ПОЛНОЕ СОЕДИНЕНИЕ вт_ДвиженияБаза2 КАК Таб2
ПО Таб1.Регистратор = Таб2.Регистратор
И Таб1.СчетДт = Таб2.СчетДт
И Таб1.СчетКт = Таб2.СчетКт
И Таб1.СубконтоДт1 = Таб2.СубконтоДт1
И Таб1.СубконтоКт1 = Таб2.СубконтоКт1
ГДЕ
(Таб1.Регистратор ЕСТЬ NULL
ИЛИ Таб2.Регистратор ЕСТЬ NULL
ИЛИ ЕСТЬNULL(Таб1.Сумма, 0) <> ЕСТЬNULL(Таб2.Сумма, 0))
Выясним преимущества такого подхода: запрос возвращает только строки с несоответствиями, позволяя точно определить, в какой именно базе проводка отсутствует или имеет иную сумму.
Для передачи данных между базами можно использовать следующие механизмы:
COMConnector): подходит для сред под управлением Windows, однако чувствительно к разрядности платформы (32/64 бит) и требует регистрации библиотеки comcntr.dll.Использование функции ЗначениеВСтрокуВнутр для сравнения объектов между разными базами применять не рекомендуется, так как внутреннее представление зависит от релиза платформы и системных идентификаторов метаданных конфигурации.