Интеграция 1С:Бухгалтерии с Битрикс24: контрагенты и КП → сделки, обмен остатками

Авторское расширение на BSL для 1С:Бухгалтерии предприятия 3.0: контрагенты, контактные лица, номенклатура и коммерческие предложения автоматически попадают в Битрикс24 как компании, контакты, товары и сделки воронки — по OAuth2 и REST, событийно, с обменом остатками и защитой от дублей.

Заказчик: Компания на 1С:Бухгалтерии предприятия 3.0 с блоком коммерческих предложений
Стек: 1С:Предприятие 8 (Бухгалтерия предприятия 3.0), расширение конфигурации (BSL), REST Битрикс24, OAuth 2.0 (oauth.bitrix.info), crm.company/crm.contact/crm.deal/crm.product, воронка crm.status, регистры маппинга/настроек/логов, очередь изменений, обмен остатками

Задача

Учёт, контрагенты, договоры и коммерческие предложения ведутся в 1С:Бухгалтерии предприятия 3.0, а продажи и воронка — в Битрикс24. Ручной перенос давал дубли контрагентов в CRM и рассинхрон статусов. Нужен автоматический обмен: контрагенты и контакты — в компании и контакты CRM, коммерческие предложения — в сделки на нужной стадии воронки, остатки номенклатуры — в карточки товаров, и всё это без переписывания типовой конфигурации.

Результат

1С:Бухгалтерия и Битрикс24 синхронизируются автоматически. Контрагенты, контактные лица и номенклатура выгружаются как компании, контакты и товары; коммерческие предложения становятся сделками с переводом статуса в стадию воронки, а прикладные поля КП уезжают в пользовательские поля сделки. Отдельная очередь гонит остатки. Обмен двусторонний: из 1С — по очереди изменений, из CRM — инкрементально по дате сверки. Регистр сопоставления ID, самоочистка при удалении объекта и лог с консолью разработчика исключают дубли и упрощают диагностику. Типовая конфигурация не изменена — обновляется штатно.

Задача: контрагенты в бухгалтерии, продажи — в Битрикс24

Клиент ведёт учёт в 1С:Бухгалтерии предприятия 3.0 с доработанным блоком коммерческих предложений: там живут контрагенты, договоры, контактные лица, номенклатура и сами КП. А отдел продаж работает в Битрикс24 — воронка, компании, контакты, сделки. Пока данные переносили руками, менеджеры видели не тот статус, в CRM плодились дубли контрагентов, а бухгалтерия не знала, на какой стадии сделка.

Нужен был автоматический обмен: контрагент и контактное лицо из 1С должны появляться в Битрикс24 как компания и контакт, коммерческое предложение — как сделка на нужной стадии воронки, а остатки номенклатуры — подтягиваться в карточку товара CRM. Всё это — без переписывания типовой Бухгалтерии, чтобы конфигурация оставалась на поддержке и обновлялась штатно.

Решение: расширение-коннектор поверх типовой конфигурации

Интеграцию собрали как расширение конфигурации (Vendor — ИП Низамов Илья Юрьевич). Типовые объекты не меняли: справочники «Контрагенты», «Контактные лица», «Номенклатура» и документ коммерческого предложения заимствованы в расширение, и к ним добавлен лишь обработчик «после записи». Вся логика обмена вынесена в собственные общие модули по схеме MVC: контроллер (что синхронизируем), модель (как собрать данные объекта для CRM) и ядро (единая обёртка над REST Битрикс24).

  • Контроллерыns_Bitrix24Company, ns_Bitrix24Contact, ns_Bitrix24Deal, ns_Bitrix24Product;
  • Моделиns_Bitrix24CompanyModel, ns_Bitrix24DealModel и т.д. (сборка полей объекта);
  • Ядроns_Bitrix24Core: авторизация, HTTP, дженерик REST-методы;
  • Служебные регистры — сопоставление ID, очередь изменений, настройки, лог, даты сверки.

Авторизация: OAuth 2.0 к коробочному Битрикс24

Портал у клиента — коробочная версия Битрикс24, поэтому авторизация идёт по полному циклу OAuth 2.0: запрос authorize отдаёт редирект 302 с параметром code, затем code обменивается на access_token и refresh_token через oauth.bitrix.info. Токены и время их жизни хранятся в регистре настроек, а перед каждым запросом ядро само продлевает истёкший токен.

Функция ИнициализацияПодключения(НастройкаПодключения) Экспорт
    // 1. authorize -> редирект 302 с параметром code
    Соединение = ПолучитьHTTPСоединение(Перечисления.ns_ТипыHTTPЗапросов.oauth, НастройкаПодключения);
    Ответ = Соединение.Получить(ЗапросHTTP_Authorize(НастройкаПодключения));
    Если Ответ.КодСостояния <> 302 Тогда Возврат ОбработатьОшибку(...); КонецЕсли;

    ПараметрыОтвета = ПолучитьСписокПараметров(Ответ.Заголовки.Получить("Location"));
    Код    = ПараметрыОтвета.Получить("code");
    Cookie = Ответ.Заголовки.Получить("Set-Cookie");

    // 2. code -> access_token + refresh_token на oauth.bitrix.info
    Ответ = ПолучитьHTTPСоединение(Перечисления.ns_ТипыHTTPЗапросов.token, НастройкаПодключения)
              .Получить(ЗапросHTTP_Token(НастройкаПодключения, Код, Cookie));
    ДанныеТокена = ПрочитатьJSON(Ответ.ПолучитьТелоКакСтроку());

    РегистрыСведений.ns_Settings.RecordSetting(..AccessToken,  ДанныеТокена.access_token);
    РегистрыСведений.ns_Settings.RecordSetting(..RefreshToken, ДанныеТокена.refresh_token);
    РегистрыСведений.ns_Settings.RecordSetting(..RefreshTime,  ТекущаяДата() + ДанныеТокена.expires_in);
КонецФункции

// Перед каждым запросом — автопродление истёкшего токена:
Процедура ПроверитьТокен(Настройка)
    Если Настройка[..RefreshTime] < ТекущаяДата() Тогда
        ОбновитьТокен();
    КонецЕсли;
КонецПроцедуры

Единая обёртка над REST Битрикс24

Все вызовы CRM идут через один метод ядра. Он подставляет актуальный токен, разбирает ответ и различает result и error. Отдельно обрабатывается ситуация, когда объект в CRM уже удалён («Not found») — тогда сопоставление в регистре очищается, чтобы 1С не била в несуществующий ID. Поверх этого — тонкие дженерик-методы над <entity>.<method>: Добавить, Обновить, Получить, Удалить, Список.

Функция ОтправитьЗапрос(МетодREST, Данные = "", ...) Экспорт
    Настройка = РегистрыСведений.ns_Settings.GetAListOfSettings();
    ПроверитьТокен(Настройка);                       // авто-refresh

    Результат = ОтправитьRESTЗапрос(Настройка, МетодREST, Данные);
    Структура = JSONDecode(Результат);

    Если Структура.Получить("result") <> Неопределено Тогда
        Возврат Структура["result"];
    ИначеЕсли Структура.Получить("error") <> Неопределено Тогда
        Если СтрНайти(Структура["error_description"], "Not found") > 0 Тогда
            РегистрыСведений.ns_DataMapping.ОчиститьСопоставление(Сущность, id); // удалён в CRM
        КонецЕсли;
        Возврат ОбработатьОшибку("ОтправитьЗапрос", Структура["error_description"]);
    КонецЕсли;
КонецФункции

// Дженерик над любым методом CRM:
Функция Добавить(Сущность, Поля) Экспорт
    Тело = Новый Соответствие; Тело.Вставить("fields", Поля);
    Возврат ОтправитьЗапрос(Строка(Сущность) + ".add", JSONEncode(Тело));  // crm.company.add и т.п.
КонецФункции

Событийная выгрузка через очередь изменений

Обмен не дёргает CRM прямо в момент проведения документа. При записи заимствованного объекта обработчик «после записи» лишь регистрирует изменение в регистре-очереди ns_ExchangeBitrix24. Отдельный регламентный процесс разбирает очередь пачкой, диспетчеризуя объект по типу сущности. Так проведение документа не тормозит на сетевых запросах, а сбой связи не рушит запись в 1С.

// Заимствованный справочник «Контрагенты» — добавлен обработчик после записи:
&После("ПриЗаписи")
Процедура ns_ПриЗаписи(Отказ)
    Если НЕ Отказ Тогда
        УстановитьПривилегированныйРежим(Истина);
        ns_Bitrix24Server.RegistrationOfChanges(Перечисления.ns_EntitiesBitrix24.crm_company, Ссылка, Ложь);
    КонецЕсли;
КонецПроцедуры

// Регламентная обработка очереди — диспетчер по типу объекта:
Процедура ОбменBitrix24() Экспорт
    Для Каждого Изменение Из РегистрыСведений.ns_ExchangeBitrix24.ВыбратьИзменения() Цикл
        Если ТипЗнч(Изменение.ObjectReference) = Тип("ДокументСсылка.КоммерческоеПредложение") Тогда
            ns_Bitrix24Deal.DB_POST(Изменение.ObjectReference);       // КП -> сделка
        ИначеЕсли Изменение.Entity = Перечисления.ns_EntitiesBitrix24.crm_company Тогда
            ns_Bitrix24Company.DB_POST(Изменение.ObjectReference);    // контрагент -> компания
        ИначеЕсли Изменение.Entity = Перечисления.ns_EntitiesBitrix24.crm_contact Тогда
            ns_Bitrix24Contact.DB_POST(Изменение.ObjectReference);    // контактное лицо
        КонецЕсли;
        ns_Bitrix24Core.Pause();                                       // пауза между вызовами CRM
    КонецЦикла;
КонецПроцедуры

Контрагенты и контакты → компании и контакты CRM

Контроллер сущности решает: если для объекта уже есть ID в регистре сопоставления — делаем update, иначе add. Модель собирает поля для CRM, а полученный из ответа ID тут же записывается в ns_DataMapping. Один и тот же паттерн работает для контрагентов (crm.company), контактных лиц (crm.contact) и номенклатуры (crm.product).

Функция ДобавитьОбновить(ID, СсылкаНаОбъект)
    Если ЗначениеЗаполнено(ID) Тогда
        Результат = ns_Bitrix24Core.Обновить(ПолучитьСущность(), ID,
                        ns_Bitrix24CompanyModel.ПолучитьДанныеОбъекта(СсылкаНаОбъект, Истина));
    Иначе
        Результат = ns_Bitrix24Core.Добавить(ПолучитьСущность(),
                        ns_Bitrix24CompanyModel.ПолучитьДанныеОбъекта(СсылкаНаОбъект));
    КонецЕсли;
    // сохраняем сопоставление «ссылка 1С — ID Битрикс24»
    ns_Bitrix24CompanyModel.ОбработатьРезультат(Результат, СсылкаНаОбъект);
    Возврат Результат;
КонецФункции

Коммерческое предложение → сделка воронки

Самая содержательная часть — маппинг КП на crm.deal. Из документа собираются заголовок, компания и контакт (через те же контроллеры), тип сделки, а статус КП переводится в стадию воронки Битрикс24 по справочнику стадий, который коннектор сам подтягивает из CRM (crm.status + типы сущностей). Прикладные атрибуты КП (номер, тип, количество продукции, адрес объекта и доставки) уезжают в пользовательские поля сделки UF_CRM_*.

Данные.Вставить("TITLE", "КП " + Выборка.Номер + " от " + Формат(Выборка.Дата, "ДЛФ=D"));
Данные.Вставить("COMPANY_ID", ns_Bitrix24Company.DB_POST(Выборка.Контрагент));   // контрагент -> компания
СписокКонтактов = Новый Массив;
СписокКонтактов.Добавить(ns_Bitrix24Contact.DB_POST(Выборка.КонтактноеЛицо));
Данные.Вставить("CONTACT_IDS", СписокКонтактов);
Данные.Вставить("TYPE_ID", "SALE");

// Статус КП -> стадия воронки
Если Выборка.Ссылка.ПометкаУдаления Тогда
    Данные.Вставить("STAGE_ID", 13);                         // «Проиграно»
ИначеЕсли ЗначениеЗаполнено(Выборка.Статус) Тогда
    Данные.Вставить("STAGE_ID", ns_Bitrix24Status.НайтиСтатусВВоронкеПоСсылке(Выборка.Статус));
Иначе
    Данные.Вставить("STAGE_ID", "NEW");
КонецЕсли;

// Прикладные атрибуты -> пользовательские поля сделки
Данные.Вставить("UF_CRM_1563552145", Выборка.Номер);                        // Номер КП
Данные.Вставить("UF_CRM_1560747914", ПолучитьТипКП(Выборка.ТипКП));         // Тип КП
Данные.Вставить("UF_CRM_1560747580", ПолучитьКоличествоПродукции(Выборка.Ссылка));

Обмен остатками номенклатуры

Для номенклатуры сделали отдельную очередь ns_ExchangeBitrixRemains и свой проход: остатки не смешиваются с обменом карточек товара и гонятся своим регламентом методом DB_POST_REMAINS. Так менеджер в CRM видит актуальное наличие, не заглядывая в 1С, а нагрузка на портал от частого обновления остатков не мешает основному обмену.

Двусторонняя синхронизация и защита от дублей

Обмен работает в обе стороны. Из 1С в CRM — по очереди изменений. Из CRM в 1С — инкрементально: коннектор запрашивает у Битрикс24 только записи с DATE_MODIFY позже последней даты сверки (регистр ns_DateVerification), находит объект по регистру сопоставления ns_DataMapping и создаёт/обновляет документ. Ключевые приёмы против дублей и зацикливания:

  • Регистр сопоставления «ссылка 1С ↔ ID Битрикс24» — один объект никогда не создаётся дважды;
  • Даты сверки по каждой сущности — тянем только дельту, а не всю базу;
  • Самоочистка сопоставления при ответе «Not found» — если объект удалён в CRM, 1С это замечает и не долбит мёртвый ID;
  • Лог и консоль разработчика (ns_DeveloperConsole) — видно каждый запрос и ответ, обмен диагностируется без отладчика.

Что не меняли и как это переносится

Типовую 1С:Бухгалтерию не трогали — вся интеграция изолирована в расширении, поэтому конфигурация обновляется штатно. Настройки портала (адрес, логин, ключи) вынесены в регистр, а не зашиты в код, так что тот же коннектор переносится на другой портал или базу заменой параметров подключения. Тот же авторский движок мы ставили и на другие конфигурации 1С — меняется только модель сущностей и набор синхронизируемых объектов.

Похожие интеграции 1С ↔ Битрикс24

Этот коннектор — часть линейки наших интеграций Битрикс24 под разные конфигурации:

Разбираем такую интеграцию по шагам — от OAuth 2.0 до обмена данными — на курсе «Интеграция 1С и Битрикс24 через расширения». Хотите такую же связку под свою базу — закажите разработку.

Частые вопросы

Нужен похожий проект?

Опишите задачу — оценю сроки и стоимость.