Введение
Я работаю в ПИК Digital — ИТ-компания, которая делает стройку технологичной. В прошлом году мы перевели Группу Компаний ПИК на G Suite. Для полноценной работы с Google Таблицами и Документами потребовалось доработать наши системы. Одна из таких доработок — расширение для выгрузки отчетов и форм из 1С в Google Диск в формате Google Таблиц и Google Документов. В статье мы поделимся готовым решением и полезной информацией по его внедрению.
Для работы расширения потребуется:
- Зарегистрировать аккаунт Google
- Создать проект в Google Cloud Platform
- Создать OAuth-клиент
- Настроить доступ к Google Drive API
- Установить расширение 1С
- Настроить подключение к Google API в 1С
Далее рассмотрим каждый этап в отдельности и приведем примеры кода.
Регистрация аккаунта Google
Для работы потребуется аккаунт Google. Без него расширение не сможет взаимодействовать с сервисами G Suite. Уже есть действующая учетка — используйте её.
Создание проекта в GCP
Для активации доступа к Google Drive API необходимо создать проект в Google Cloud Platform (GCP). Есть два варианта бесплатной работы с GCP:
- 12-месячный пробный период — с бюджетом в 300 долларов США.
- Always Free — доступ к большинству ресурсов GCP.
Оба способа имеют ограничения, подробнее о них рассказано в тут. Рекомендуем вариант с 12-месячным пробным периодом. После окончания пробного периода деньги не будут списываться, если вы не начнете пользоваться платными услугами. Все, что необходимо для работы интеграции бесплатно.
Регистрируем проект по ссылке console.cloud.google.com, жмём «Выберите проект», затем — «Создать проект». После создания проекта выбираем его повторным нажатием кнопки «Выберите проект».
Создание OAuth-клиента
Создадим учетные данные для подключения к G Suite по протоколу OAUth 2.0. В GCP идём в пункт меню «API и сервисы» — «Учетные данные» — «Создать учетные данные» — «Идентификатор ключа OAUth».
Появится предложение создать окно запроса доступа. Это окно формируется, когда у пользователя спрашивают разрешение на доступ к его данным.
Оставьте тип доступа «Открытый доступ» и введите название приложения, которое будет отображаться, когда сотрудник запустит проект и потребуется согласие на доступ к данным. Нажмите «Сохранить».
После этого задайте «Тип приложения». Выберите «Другие типы» и введите идентификатор клиента OAuth. Обратите внимание, что это не то же самое, что отображаемое название приложения. В результате откроется окно с идентификатором и секретом клиента. Сохраните их, это важно.
Подключение библиотеки Google Drive API
Для получения доступа к функционалу API перейдите в пункт меню «Библиотека API», найдите нужную библиотеку и подключите ее.
Поскольку мы хотим работать с форматами G Suite, необходимо подключить к проекту библиотеку Google Drive API. Кроме того, нам понадобится библиотека Google Sheets API, Google Docs API. Найдите и подключите ее таким же способом.
Установка расширения в пользовательском режиме
Теперь можно формировать запросы к API. Напомним: наша задача — выгрузить данные из отчета 1С стандартной формы в Google Таблицу или Google Документ.
Скачайте расширение 1С.
В 1С есть возможность самостоятельно устанавливать расширения конфигурации. Если вы сталкиваетесь с этой задачей впервые, посмотрите наше короткое видео о том, как это сделать.
Наше расширение работает с платформой начиная с версии 8.3.10, на конфигурациях БП (начиная с 3.0.65 и выше), ERP (начиная с 2.4.6 и выше) и УТ (начиная с 11.4.6 и выше).
Если при установке расширения у вас отобразится предупреждение безопасности, нажимайте «Да». Вы увидите сообщение о том, что «Текущее выполнение действия было прервано для выдачи предупреждения». Это означает, что у вас включен безопасный режим, поэтому процедуру добавления расширения нужно повторить, а безопасный режим — отключить. После добавления перезапустите 1С.
Если установка прошла успешно, то вы увидите кнопку «Сохранить на Google Drive» в отчётах и печатных формах.
Настройка параметров подключения к Google API в 1С
Осталось настроить параметры подключения к Google API, и можно работать. Снова выбираем в меню пункт «Все функции» и в разделе «Обработки» ищем пункт «Параметры подключения к Google API».
Заполняем поля Clientid, Clientsecret и «Порт» значениями, полученными при создании проекта в GCP. По умолчанию подставляются имя файла и папки, где будут сохранены временные ключи, используемые для подключения. Данные о ключах (refresh и access-токены) пользователя в целях безопасности сохраняются в каталог временных файлов текущего пользователя, в папку <имя папки> и в файл <имя файла>. Если один и тот же проект Google создается в разных конфигурациях, имя файла можно сделать одинаковым во всех из них, чтобы не создавать несколько файлов с одинаковой информацией. При сохранении параметры подключения сохраняются в хранилище общих настроек.
Сохранение отчета
Теперь вы сможете сохранять отчеты в формате Google Таблиц и Google Документов на Google Диске.
При первой попытке сохранить отчет вам потребуется пройти в каждой конфигурации разовую процедуру авторизация пользователя, чтобы сервис получил права доступа для сохранения данных.
В появившемся окне введите адрес своей электронной почты Gmail и пароль. Далее в открывшемся окне нажмите «Разрешить». Так вы даёте приложению сохранить информацию в вашем Google Диске.
Вам потребуется ввести имя файла, выбрать его тип и каталог для сохранения на общем или личном диске. Нажмите «Сохранить». После сохранения отчет откроется в браузере. Приятного просмотра.
Техническая сторона вопроса
Теперь разберемся, как это работает внутри платформы 1С.
Для подключения формируется следующая строка запроса к сервису Google:
АдресПодключения="https://accounts.google.com/o/oauth2/auth"+"?"
+ "response_type=code"
+ "&client_id=" + ид_клиента
+ "&redirect_uri=urn:ietf:wg:oauth:2.0:oob"
+ "&access_type=offline"
+ "&scope=https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.apps.readonly https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.metadata;
ид_клиента— идентификатор клиента, в котором мы ранее сохранили значение переменной.
scope — адреса библиотек API, которые мы будем использовать. Если необходимо подключить несколько библиотек, перечислите их через пробел.
Эта строка запроса нужна для одноразового подключения нашего клиентского приложения к сервису Google. Можно ввести строку запроса в браузере, в ответ сервис вернет URL примерно такого содержания:
Success code=<КОД>&scope=https://www.googleapis.com/auth/admin.directory.user%20https://www.googleapis.com/auth/admin.directory.orgunit
Можно в конструкторе форм 1С добавить поле для HTML-данных и выполнить запрос через него. Нам необходимо из этого URL получить значение <КОД> — код доступа к сервису.
Осталось получить два токена, сделав HTTP-запрос. В результате запрос вернет строку со значениями access и refresh в формате JSON. Refresh-токен не теряет актуальности с течением времени, а access-токен живет 60 минут и затем требует обновления. Для получения этих токенов нам понадобятся только что полученный <КОД>, а также идентификатор и секрет клиента, которые мы сохранили ранее.
Код может быть примерно таким:
Сервер = "accounts.google.com";
Ресурс = "/o/oauth2/token";
СтрокаЗапроса = СтрШаблон("client_id=%1&client_secret=%2&grant_type=authorization_code&code=%3&redirect_uri=urn:ietf:wg:oauth:2.0:oob",
ид_клиента,
секрет_клиента,
КодДоступа);
Соединение = Новый HTTPСоединение(Сервер,443,,,,,Новый ЗащищенноеСоединениеOpenSSL);
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type","application/x-www-form-urlencoded”)
ЗапросHTTP = Новый HTTPЗапрос(Ресурс,Заголовки);
ЗапросHTTP.УстановитьТелоИзСтроки(СтрокаЗапроса);
Ответ = Соединение.ВызватьHTTPМетод("POST", ЗапросHTTP);
Если НЕ Ответ.КодСостояния = 200 Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(СтрШаблон("Ошибка получения параметров авторизации: %1", Ответ.ПолучитьТелоКакСтроку()));
Возврат;
КонецЕсли;
Строка = Ответ.ПолучитьТелоКакСтроку();
Чтение = Новый ЧтениеJSON();
Чтение.УстановитьСтроку(Строка);
Фабрика = ФабрикаXDTO.ПрочитатьJSON(Чтение);
Чтение.Закрыть();
ТокенДоступа = Фабрика.access_token;
ТокенОбновления = Фабрика.refresh_token;
ВремяЖизниТокена = Фабрика.expires_in;
В переменной expires_in содержится время жизни access-токена.
Ниже показан запрос на обновление токена:
Сервер = "accounts.google.com";
Ресурс = "/o/oauth2/token";
ТокенОбновления = GoogleНастройки.refresh_token;
ид_клиента = GoogleНастройки.client_id;
секрет_клиента = GoogleНастройки.client_secret;
СтрокаЗапроса = "grant_type=refresh_token"
+ "&client_id=" + ид_клиента
+ "&client_secret=" + секрет_клиента
+ "&refresh_token=" + ТокенОбновления;
Сохранение табличного документа на Google Диск
Теперь посмотрим, как сохранять табличный документ на Google Drive с последующей его конвертацией в формат Google Таблиц.
//разделитель для HTTP сообщения
Разделитель = "file_for_drive";
//определяем HTTP заголовок по типу файла
ЗаголовокПоТипуФайла = СоответствиеТипуФайлаЗаголовкамGoogle()[ТипФайла];
ЗаголовкиОсновногоЗапроса.Вставить("Content-Type", "multipart/related; boundary=" + Разделитель);
//-----
//первый запрос
//-----
//заголовки
Заголовки = Новый Массив;
Заголовки.Добавить("Content-Type: application/json; charset=UTF-8");
//запрос метаданных
//формируем json с параметрами имя файла, заголовок и родитель
ТелоЗапроса = СформироватьТелоЗапросаСозданиеФайлаGSs(ИмяФайла, ЗаголовокПоТипуФайла, id_папки);
ДвоичныеДанныеСообщения = GoogleAPI_ОбщегоНазначения.СоздатьСообщение_Текст(Заголовки, ТелоЗапроса);
//-----
//конец первого запроса
//-----
//-----
//второй запрос
//-----
//заголовки
Заголовки.Очистить();
Заголовки.Добавить("Content-Type: " + ЗаголовокПоТипуФайла);
Заголовки.Добавить("uploadType: media");
//запрос метаданных
ВременныйФайл = ПолучитьИмяВременногоФайла(ТипФайла);
ТабДок.Записать(ВременныйФайл, ТипТабличногоДокументаПоТипуФайла()[ТипФайла]);
ДвоичныеДанныеФайла = GoogleAPI_ОбщегоНазначения.СоздатьСообщение_Файл(Заголовки, Новый ДвоичныеДанные(ВременныйФайл));
//-----
//конец второго запроса
//-----
//-----
// Формируем основное составное сообщение.
МассивСообщений = Новый Массив;
МассивСообщений.Добавить(ДвоичныеДанныеСообщения);
МассивСообщений.Добавить(ДвоичныеДанныеФайла);
ДвоичныеДанныеТело = GoogleAPI_ОбщегоНазначения.ПолучаемДвоичныеДанныеДляПакетныхСообщенийHTTP(Разделитель, МассивСообщений);
//-----
ЗапросHTTP = Новый HTTPЗапрос("https://infostart.ru/upload/drive/v2/files" + "?uploadType=multipart&convert=true",ЗаголовкиОсновногоЗапроса);
ЗапросHTTP.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТело);
Ответ =Соединение.ВызватьHTTPМетод("POST", ЗапросHTTP);
Если Не Ответ.КодСостояния = 200 Тогда
ТекстОшибок = "Ошибка HTTP запроса " + Ответ.ПолучитьТелоКакСтроку() + ", код ошибки " + Ответ.КодСостояния;
GoogleAPI_ОбщегоНазначения.ЗаписьОшибкиПриРаботеСGS(ТекстОшибок, ". Запись документа");
Возврат "";
КонецЕсли;
HTTPСоединение = Неопределено;
ЗапросHTTP = Неопределено;
Попытка
УдалитьФайлы(ВременныйФайл);
Исключение
ЗаписьЖурналаРегистрации("Удалить файлы",УровеньЖурналаРегистрации.Ошибка,,,ОписаниеОшибки());
КонецПопытки;
ОтветHTTPТело = Ответ.ПолучитьТелоКакСтроку();
ОбъектJSON = GoogleAPI_ПроцедурыРаботыСGSheets.СформироватьЗначениеОбъектаJSON(ОтветHTTPТело);
//возвращаем ссылку на документ из google drive
Возврат GoogleAPI_ПроцедурыРаботыСGSheets.ПрочитатьСвойствоВСтрокеОбъектаJSON(ОбъектJSON, "alternateLink");
В этом коде для загрузки файла используется способ multipart upload.
Мы формируем POST-запрос из двух блоков данных. В первом блоке прописываем title и mimeType файла. Во втором блоке передается содержимое файла. Блоки определяются разделителями, которые указаны в конце и начале блока.
Подробнее об этом в статье о вставке файлов базы знаний Google Диск.
Вот так это работает. Надеемся, что теперь вы не будете тратить время на конвертацию выгруженных из 1С данных.
а где взять поле «Порт»?
При первоначальной авторизации идет редирект на локалхост.. А что делать, если нет никакого локалхост и редиректить некуда?
Может быть должно быть ещё какое то СДК, или ещё что-то?
(1)порт по умолчанию 443, нужен для подключения к gs
(2)нам нужен только код из значения ссылки (саму ссылку не нужно открывать), ссылка:
http://localhost/?code=
<24 символа кода для авторизации>
&scope=https://www.googleapis.com/auth/drive+https://www.googleapis.com/auth/spreadsheets+https://www.googleapis.com/auth/drive.apps.readonly+https://www.googleapis.com/auth/drive.file+https://www.googleapis.com/auth/drive.appdata+https://www.googleapis.com/auth/drive.metadata+https://www.googleapis.com/auth/drive.metadata.readonly+https://www.googleapis.com/auth/drive.photos.readonly+https://www.googleapis.com/auth/drive.readonly+https://www.googleapis.com/auth/spreadsheets.readonly
(4)Ну на данный момент программа не получает никакого кода, т.к. при редиректе браузер говорит что все плохо, локалхост не найден. Возможно имеет смысл выбор браузера по-умолчанию или какие то специфичные настройки?
(5)На каком этапе возникает ошибка? После нажатия на «Allow»?
(6)Да
(7)Можно либо открыть 80 порт на машине, с которой происходит запуск.
Либо редиректить не на локалхост. В обработке GoogleAPI_АвторизацияПользователя в процедуре Авторизоваться заменить строку «redirect_uri=http://localhost».
Мария добрый день! Попробовал поставить ваше расширение на УТ 11.4, появились ошибки отсутствия некоторых объектов. Например в расширении используется объект ПланСчетов.Хозрасчетный, в УТ в принципе планов счетов нет. Как то решается эта проблема в пользовательском режиме, помимо удаления отсутствующих объектов из расширения?
(9) Добрый день!
К сожалению нет, это ограничение расширения. Могу отправить расширение без плана счетов и бух.отчетов, если нужно.
А если самописная конфигурация?
(11)Если конфигурация на БСП, основная форма отчета в конфигурации ОбщаяФорма.ФормаОтчета и форма в отчете не переопределена, то работать будет без доработок. Если форма отчета переопределена, то эту форму нужно добавить в расширение и в нее добавить общую команду GoogleAPI_СохранитьОтчетСФормы.