Сверка закрывающих документов между УТ 11 и БП 3.0
В работе часто возникает необходимость сверить закрывающую первичку торговли и бухгалтерии за период: реализации, поступления, счета-фактуры, корректировки. Типовой обмен УТ↔БП объекты переносит, а отчёт «что не сошлось по сумме, НДС и строкам» не строит. Предлагаю два расширения с одним и тем же рабочим местом: запуск из УТ или из БП даёт один результат.
К публикации прилагаются два файла .cfe. Имя в конфигураторе на обеих сторонах — СверкаПервичныхДокументов. Префиксы разные: УТ — СпдУт_, БП — СпдБп_.
В расширениях нет заимствованных типовых документов и нет объектов, которые потребуют реструктуризации типовой конфигурации. Свои — обработка, HTTP-сервис, регистр адреса публикации, общие модули. Своей роли нет: права на обработку, регистр и HTTP-сервис выдаём штатно.
Для обмена будем использовать HTTP-сервис с RootURL = spd и фиксированным JSON. Так как контракт одинаковый, сторона запуска не меняет ключи и допуски: локальная выборка плюс POST /documents второй базы, затем сравнение канона. Произвольный текст запроса 1С из тела не выполняется.
Общая настройка
- Загрузить расширение в УТ и в БП.
- Опубликовать HTTP-сервис
spdна каждой стороне. - Пользователю публикации дать право читать закрывающие документы. Пользователю рабочего места — открыть обработку «Настройки сверки», регистр подключения и сервис.
- В форме указать адрес второй базы до
/hs/spdвключительно, пользователя и пароль.
УТ: e1cib/app/Обработка.СпдУт_РабочееМестоСверки
БП: e1cib/app/Обработка.СпдБп_РабочееМестоСверки

В форме не пишут /ping и /documents. Клиент сам делает POST …/ping, затем POST …/documents.
| Поле | Значение |
|---|---|
| Адрес публикации | http://<сервер>:<порт>/<имя_публикации>/hs/spd |
| Пользователь | пользователь инфобазы второй стороны |
| Пароль | его пароль (в регистр не пишется) |
Примеры: в УТ — http://bp-server:8080/buh/hs/spd, в БП — http://ut-server:8080/ut/hs/spd.
Советую указывать путь до /hs/spd явно.
Пароль кладём в безопасное хранилище БСП, в регистре остаются только адрес и имя пользователя.
ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(
СпдУт_СверкаКлиентСервер.ВладелецПароляПодключения(),
Пароль);
Проверка связи вручную: POST {адрес}/ping → {"ok": true, "storona": "UT"|"BP", "versiya": "1.0"}.
Пример для запуска сверки
Нам нужно за период и организацию увидеть расхождения,. Без организации запуск не идёт. Если вторая база не отвечает — ошибка связи, таблицы «расхождений нет» нет. Если обе выборки пустые — «данных нет», это не успех.
Сначала пинг, потом локальные документы и выборка второй стороны. Документы не пишем.
Функция ВыполнитьСверку(ПараметрыСверки) Экспорт
Результат = Новый Структура;
Результат.Вставить("Состояние", СпдУт_СверкаКлиентСервер.СостояниеНеЗапускалась());
Результат.Вставить("Сообщение", "");
Результат.Вставить("ТабличныйДокумент", Новый ТабличныйДокумент);
Настройки = ПрочитатьНастройкиПодключения();
ОтветПинг = СпдУт_Транспорт.ВыполнитьПинг(Настройки);
Если Не ОтветПинг.Успех Тогда
Результат.Состояние = СпдУт_СверкаКлиентСервер.СостояниеОшибкаСвязи();
Результат.Сообщение = ОтветПинг.Сообщение;
Возврат Результат;
КонецЕсли;
Локальные = ВыбратьДокументы(ПараметрыСверки);
ОтветДокументы = СпдУт_Транспорт.ПолучитьДокументы(Настройки, ТелоЗапросаДокументов(ПараметрыСверки));
Если Не ОтветДокументы.Успех Тогда
Результат.Состояние = СпдУт_СверкаКлиентСервер.СостояниеОшибкаСвязи();
Результат.Сообщение = ОтветДокументы.Сообщение;
Возврат Результат;
КонецЕсли;
Удаленные = СпдУт_СверкаКлиентСервер.СвойствоСтруктуры(ОтветДокументы.Данные, "dokumenty");
Если Локальные.Количество() = 0 И Удаленные.Количество() = 0 Тогда
Результат.Состояние = СпдУт_СверкаКлиентСервер.СостояниеНетДанных();
Результат.Сообщение = "По выбранным фильтрам данных нет";
Возврат Результат;
КонецЕсли;
Расхождения = СопоставитьИСверить(Локальные, Удаленные, ПараметрыСверки.СверятьКорректировки);
Результат.ТабличныйДокумент = ПостроитьТабличныйДокумент(Расхождения, ПараметрыСверки.СверятьКорректировки);
Результат.Состояние = СпдУт_СверкаКлиентСервер.СостояниеЕстьРезультат();
Возврат Результат;
КонецФункции
В сверку входят только проведённые, не помеченные на удаление. Флаг «только проведённые» на форме включён и недоступен.
Типы на форме:
- УПД (статус 1 и 2) — реализации/поступления (акт, накладная, УПД) и возвраты того же направления;
- счёт-фактура — выданные и полученные, без авансов;
- УПД корректировка — только согласование стоимости, не исправление ошибок.
Как посмотреть: выбрать организацию, текущий месяц, все флажки, «Выполнить сверку». Успешные пары в таблицу не попадают.

Четыре блока всегда на месте, даже пустые:
- Реализации (и возврат от клиента).
- Поступления (и возврат поставщику).
- Позиционные расхождения строк.
- Корректировки (суммы увеличения/уменьшения и основание).
Экспорт — ТипФайлаТабличногоДокумента.XLSX текущего табличного документа. Пока сверка не дала состояние «есть результат», файл не создаём: ни после ошибки связи, ни после «данных нет».
Пример для ключа сопоставления
Нам нужно склеить ТД0000123 в УТ и 0000123 в БП как одну пару и не склеить филиалы с разным КПП.
Исходящие (реализация, СФ выданный, корректировка реализации, возврат от клиента): номер без префикса + календарный день + ИНН контрагента.
Входящие (поступление, СФ полученный, корректировка поступления, возврат поставщику): входящий номер + день + ИНН поставщика. Внутренний номер базы во входящий ключ не входит.
Функция НомерБезПрефикса(Знач НомерДокумента) Экспорт
Результат = СокрЛП(Строка(НомерДокумента));
Пока СтрДлина(Результат) > 0 Цикл
Первый = Лев(Результат, 1);
Если СтрНайти("0123456789", Первый) = 0 Тогда
Результат = Сред(Результат, 2);
Иначе
Прервать;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Функция КлючДокументаБезОрганизации(Документ) Экспорт
НомерДляКлюча = СокрЛП(Строка(СвойствоСтруктуры(Документ, "nomerDlyaKlyucha")));
ДатаКлюч = КлючДаты(СвойствоСтруктуры(Документ, "data")); // yyyyMMdd
Контрагент = СвойствоСтруктуры(Документ, "kontragent");
ИНН = "";
Если Контрагент <> Неопределено Тогда
ИНН = СокрЛП(Строка(СвойствоСтруктуры(Контрагент, "inn")));
КонецЕсли;
Возврат НомерДляКлюча + "|" + ДатаКлюч + "|" + ИНН;
КонецФункции
Организация в отборе — отдельно. Тождество УТ↔БП: GUID ссылки (и СоответствияОбъектовИнформационныхБаз, если есть), иначе ИНН, при заполненном КПП — ИНН+КПП. GUID главнее расхождения ИНН.
Пустой входящий номер — расхождение «неполный ключ», не успешная пара. Несколько документов с одним ключом в одной базе — «неоднозначный ключ», первый попавшийся молча не берём.
Допуски: сумма и НДС — расхождение, если |Δ| строго больше 0,01; количество и цена — строго больше 0,001. Ставка шапки и строки — строго по канону 22 / 10 / 0 / БезНДС (плюс факт 20/18/5/7). Расчётные вроде НДС22_122 сводим к базовой.
Строки одной номенклатуры не суммируем. Склейка жадная: внутри позиции берём пару с минимальной |Δцена| + |Δколичество|, лишняя строка — «нет парной строки».
Функция СопоставитьСтрокиЖадно(СтрокиУТ, СтрокиБП)
Пары = Новый Массив;
ИспользованныеБП = Новый Соответствие;
Для Каждого СтрокаУТ Из СтрокиУТ Цикл
ЛучшийИндекс = Неопределено;
ЛучшаяРазница = Неопределено;
Для ИндексБП = 0 По СтрокиБП.ВГраница() Цикл
Если ИспользованныеБП.Получить(ИндексБП) = Истина Тогда
Продолжить;
КонецЕсли;
СтрокаБП = СтрокиБП[ИндексБП];
Если Не СпдУт_СверкаКлиентСервер.НоменклатурыТождественны(
СтрокаУТ.nomenklatura, СтрокаБП.nomenklatura) Тогда
Продолжить;
КонецЕсли;
ДельтаЦены = СтрокаУТ.cena - СтрокаБП.cena;
Если ДельтаЦены < 0 Тогда
ДельтаЦены = -ДельтаЦены;
КонецЕсли;
ДельтаКол = СтрокаУТ.kolichestvo - СтрокаБП.kolichestvo;
Если ДельтаКол < 0 Тогда
ДельтаКол = -ДельтаКол;
КонецЕсли;
Разница = ДельтаЦены + ДельтаКол;
Если ЛучшаяРазница = Неопределено Или Разница < ЛучшаяРазница Тогда
ЛучшаяРазница = Разница;
ЛучшийИндекс = ИндексБП;
КонецЕсли;
КонецЦикла;
ПараСтрок = Новый Структура("СтрокаУТ, СтрокаБП", СтрокаУТ, Неопределено);
Если ЛучшийИндекс <> Неопределено Тогда
ПараСтрок.СтрокаБП = СтрокиБП[ЛучшийИндекс];
ИспользованныеБП.Вставить(ЛучшийИндекс, Истина);
КонецЕсли;
Пары.Добавить(ПараСтрок);
КонецЦикла;
Для ИндексБП = 0 По СтрокиБП.ВГраница() Цикл
Если ИспользованныеБП.Получить(ИндексБП) = Истина Тогда
Продолжить;
КонецЕсли;
Пары.Добавить(Новый Структура("СтрокаУТ, СтрокаБП", Неопределено, СтрокиБП[ИндексБП]));
КонецЦикла;
Возврат Пары;
КонецФункции
Номенклатура: GUID, иначе артикул, иначе наименование. Если артикул заполнен хотя бы с одной стороны и не совпал — до наименования не опускаемся.
Как проверить: две реализации с одним номером без префикса и ИНН, сумма отличается на 0,02 — блок 1, комментарий «Сумма». Реализация только в УТ — «Нет пары». Авансовый СФ в периоде не показывается.
Пример для HTTP-выборки
Нам нужна выборка второй базы без COM и без текста запроса в теле. Имя процедуры модуля должно совпасть с Handler в XML: Пинг и Документы. Ответ — ЗаписатьJSON, не ЗначениеВСтрокуВнутр.
Функция Пинг(Запрос)
Данные = Новый Структура;
Данные.Вставить("ok", Истина);
Данные.Вставить("storona", "UT"); // в БП — "BP"
Данные.Вставить("versiya", "1.0");
Возврат ОтветJSON(200, Данные);
КонецФункции
Функция Документы(Запрос)
Тело = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Тело);
ДанныеЗапроса = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
РезультатПроверки = СпдУт_СверкаСервер.ПроверитьФильтрыHTTP(ДанныеЗапроса);
Если Не РезультатПроверки.Успех Тогда
Возврат ОтветОшибки400(РезультатПроверки.Сообщение);
КонецЕсли;
Данные = Новый Структура;
Данные.Вставить("ok", Истина);
Данные.Вставить("dokumenty", СпдУт_СверкаСервер.ВыбратьДокументыПоФильтрамHTTP(РезультатПроверки.Фильтры));
Возврат ОтветJSON(200, Данные);
КонецФункции
Фильтры жёсткие: есть организации, есть типы из {upd, invoice, updCorrection}, даты не перепутаны. Нет поля текста запроса. Любой не-200, таймаут или тело без ok: true на стороне запуска — ошибка связи.
Тело /documents (схема):
{
"dataNachala": "2026-01-01",
"dataOkonchaniya": "2026-01-31",
"organizacii": [{ "identifikator": "…", "inn": "7701234567", "kpp": "770101001" }],
"kontragenty": [],
"tipy": ["upd", "invoice", "updCorrection"]
}
POST /documents без организаций — 400, таблица сверки не строится.
Важные дополнения
- Своей роли в расширении нет. Бухгалтеру выдайте права на обработку «Настройки сверки», регистр подключения и HTTP-сервис — либо работайте из профиля, которому эти объекты уже доступны.
- Авансы в выборку не входят и не дают «нет пары». В УТ это отдельные
СчетФактураВыданныйАванс/СчетФактураПолученныйАванс. В БП — отбор поВидСчетаФактуры(НаАванс,НаАвансКомитента, …). - У
УТ: Документ.СчетФактураВыданныйв ТЧДокументыОснованиянетСумма. Если ТЧТоварыСФ пустая, итоги берём из оснований (СуммаДокументаи НДС ТЧ). У полученного СФ в той же ТЧ поля сумм есть. У полученного СФ в УТ входящий номер — реквизитНомер(подсказка «номер СФ поставщика»), отдельногоНомерВходящегоДокументанет; в БП поле есть. - Имена документов разные:
УТ: Документ.ПриобретениеТоваровУслуг↔БП: Документ.ПоступлениеТоваровУслуг,УТ: Документ.КорректировкаПриобретения↔БП: Документ.КорректировкаПоступления,УТ: Документ.ВозвратТоваровОтКлиента↔БП: Документ.ВозвратТоваровОтПокупателя. - Советую не снимать флажок «только проведённые»: непроведённые в сверку не попадают по постановке, отдельного режима «включая черновики» нет.
- Повторный запуск затирает предыдущий табличный документ. Сверяемые документы в базах не меняются.
Протестировано на «1С:Управление торговлей», редакция 11, 11.5.26.106 и «1С:Бухгалтерия предприятия», редакция 3.0, 3.0.195.36.
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 11, релизы 11.5.26.106
- Бухгалтерия предприятия, редакция 3.0, релизы 3.0.195.36
Вступайте в нашу телеграмм-группу Инфостарт