Files
bit-flight-deck/bitra-patch/HTTPServices/bfd_IntegrationAPI/Module.bsl
T

505 lines
29 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
////////////////////////////////////////////////////////////////////////////////
// HTTPService bfd_IntegrationAPI — read-only REST API для bit-flight-deck.
//
// Корневой URL (RootURL) — bfd-api
// После публикации: http://<host>/<dbname>/hs/bfd-api/v1/...
//
// Все методы GET. Аутентификация Basic (пользователь bfd_api_user).
// Ошибки → JSON {"error":"..."} с HTTP-кодом 500.
// Все ID объектов сериализуются как строковый UUID без префикса класса.
////////////////////////////////////////////////////////////////////////////////
#Область ОбработчикиЗапросов
// GET /v1/health
//
Функция HealthGet(Запрос) Экспорт
Ответ = Новый Структура;
Ответ.Вставить("status", "ok");
Ответ.Вставить("service", "bfd_IntegrationAPI");
Ответ.Вставить("server_time", Формат(ТекущаяДатаСеанса(), "ДФ=yyyy-MM-ddTHH:mm:ss"));
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Ответ);
КонецФункции
// GET /v1/employees
//
// Email — через JOIN к табличной части КонтактнаяИнформация.
// В BIT.RA у ТЧ есть кастомное поле АдресЭП (адрес электронной почты) —
// это специфика данной БСП, заполняется при сохранении объекта.
//
Функция EmployeesGet(Запрос) Экспорт
Попытка
Запрос1С = Новый Запрос;
Запрос1С.УстановитьПараметр("ТипEmail", Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты);
Запрос1С.Текст =
"ВЫБРАТЬ
| Пользователи.Ссылка КАК Ссылка,
| Пользователи.Наименование КАК ФИО,
| Пользователи.EVA_ID КАК EvaID,
| Пользователи.Офис КАК Офис,
| Пользователи.Подразделение КАК Подразделение,
| Пользователи.Ставка КАК Ставка,
| Пользователи.Недействителен КАК Недействителен,
| Пользователи.ДолженЗаполнятьОтчет КАК ДолженЗаполнятьОтчет,
| МАКСИМУМ(КИ.АдресЭП) КАК Email
|ИЗ
| Справочник.Пользователи КАК Пользователи
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Пользователи.КонтактнаяИнформация КАК КИ
| ПО КИ.Ссылка = Пользователи.Ссылка
| И КИ.Тип = &ТипEmail
|ГДЕ
| НЕ Пользователи.ПометкаУдаления
|СГРУППИРОВАТЬ ПО
| Пользователи.Ссылка,
| Пользователи.Наименование,
| Пользователи.EVA_ID,
| Пользователи.Офис,
| Пользователи.Подразделение,
| Пользователи.Ставка,
| Пользователи.Недействителен,
| Пользователи.ДолженЗаполнятьОтчет
|УПОРЯДОЧИТЬ ПО
| Пользователи.Наименование";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Email = ?(Выборка.Email = Null, "", Строка(Выборка.Email));
Запись = Новый Структура;
Запись.Вставить("id", bfd_IntegrationAPIHelpers.UUID(Выборка.Ссылка));
Запись.Вставить("full_name", Выборка.ФИО);
Запись.Вставить("email", НРег(Email));
Запись.Вставить("eva_id", Выборка.EvaID);
Запись.Вставить("office", Строка(Выборка.Офис));
Запись.Вставить("department", Строка(Выборка.Подразделение));
Запись.Вставить("rate", Выборка.Ставка);
Запись.Вставить("is_active", НЕ Выборка.Недействителен);
Запись.Вставить("should_fill_report", Выборка.ДолженЗаполнятьОтчет);
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/works?modified_since=<ISO_DATE>&limit=N
//
Функция WorksGet(Запрос) Экспорт
Попытка
МодифицированоПосле = bfd_IntegrationAPIHelpers.ПарсДатуISO(Запрос.ПараметрыЗапроса.Получить("modified_since"));
Лимит = bfd_IntegrationAPIHelpers.ПарсЛимит(Запрос, 1000, 10000);
Запрос1С = Новый Запрос;
Запрос1С.УстановитьПараметр("МодифицированоПосле", МодифицированоПосле);
Запрос1С.Текст =
"ВЫБРАТЬ ПЕРВЫЕ " + Формат(Лимит, "ЧГ=") + "
| ДокРаботы.Ссылка КАК Ссылка,
| ДокРаботы.Номер КАК Номер,
| ДокРаботы.Дата КАК Дата,
| ДокРаботы.Исполнитель КАК Исполнитель,
| ДокРаботы.Автор КАК Автор,
| ДокРаботы.Подразделение КАК Подразделение,
| ДокРаботы.Офис КАК Офис,
| ДокРаботы.Утвержден КАК Утвержден,
| ДокРаботы.Комментарий КАК Комментарий,
| ДокРаботы.ИтогоЧасов КАК ИтогоЧасов
|ИЗ
| Документ.Работы КАК ДокРаботы
|ГДЕ
| ДокРаботы.Дата >= &МодифицированоПосле
| И ДокРаботы.Проведен
|УПОРЯДОЧИТЬ ПО
| ДокРаботы.Дата УБЫВ";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Запись = Новый Структура;
Запись.Вставить("id", bfd_IntegrationAPIHelpers.UUID(Выборка.Ссылка));
Запись.Вставить("number", Выборка.Номер);
Запись.Вставить("date", Формат(Выборка.Дата, "ДФ=yyyy-MM-ddTHH:mm:ss"));
Запись.Вставить("employee_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Исполнитель));
Запись.Вставить("author_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Автор));
Запись.Вставить("department", Строка(Выборка.Подразделение));
Запись.Вставить("office", Строка(Выборка.Офис));
Запись.Вставить("approved", Выборка.Утвержден);
Запись.Вставить("comment", Выборка.Комментарий);
Запись.Вставить("total_hours", Выборка.ИтогоЧасов);
Запись.Вставить("rows", ПолучитьСтрокиРаботы(Выборка.Ссылка));
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/projects
//
Функция ProjectsGet(Запрос) Экспорт
Попытка
Запрос1С = Новый Запрос;
Запрос1С.Текст =
"ВЫБРАТЬ
| Проекты.Ссылка КАК Ссылка,
| Проекты.Код КАК Код,
| Проекты.Наименование КАК Наименование,
| Проекты.EVA_ID КАК EvaID,
| Проекты.Кодификатор КАК Кодификатор,
| Проекты.Клиент КАК Клиент,
| Проекты.Клиент.Наименование КАК КлиентИмя,
| Проекты.Договор КАК Договор,
| Проекты.Конфигурация КАК Конфигурация,
| Проекты.Офис КАК Офис,
| Проекты.РуководительПроекта КАК РуководительПроекта,
| Проекты.МенеджерПроекта КАК МенеджерПроекта,
| Проекты.СтатусПроекта КАК СтатусПроекта,
| Проекты.СтатусДоговора КАК СтатусДоговора,
| Проекты.ДатаСтарта КАК ДатаСтарта,
| Проекты.ДатаФиниш КАК ДатаФиниш,
| Проекты.Бюджет КАК Бюджет,
| Проекты.ПометкаУдаления КАК ПометкаУдаления
|ИЗ
| Справочник.Проекты КАК Проекты";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Запись = Новый Структура;
Запись.Вставить("id", bfd_IntegrationAPIHelpers.UUID(Выборка.Ссылка));
Запись.Вставить("code", Выборка.Код);
Запись.Вставить("name", Выборка.Наименование);
Запись.Вставить("eva_id", Выборка.EvaID);
Запись.Вставить("project_code", Выборка.Кодификатор);
Запись.Вставить("client_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Клиент));
Запись.Вставить("client_name", Выборка.КлиентИмя);
Запись.Вставить("contract_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Договор));
Запись.Вставить("configuration", Строка(Выборка.Конфигурация));
Запись.Вставить("office", Строка(Выборка.Офис));
Запись.Вставить("manager_id", bfd_IntegrationAPIHelpers.UUID(Выборка.РуководительПроекта));
Запись.Вставить("project_manager_id", bfd_IntegrationAPIHelpers.UUID(Выборка.МенеджерПроекта));
Запись.Вставить("status", Строка(Выборка.СтатусПроекта));
Запись.Вставить("contract_status", Строка(Выборка.СтатусДоговора));
Запись.Вставить("start_date", ?(ЗначениеЗаполнено(Выборка.ДатаСтарта), Формат(Выборка.ДатаСтарта, "ДФ=yyyy-MM-dd"), ""));
Запись.Вставить("finish_date", ?(ЗначениеЗаполнено(Выборка.ДатаФиниш), Формат(Выборка.ДатаФиниш, "ДФ=yyyy-MM-dd"), ""));
Запись.Вставить("budget", Выборка.Бюджет);
Запись.Вставить("deleted", Выборка.ПометкаУдаления);
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/stages
//
// Catalog.ЭтапыПроектов — подчинённый справочник, Владелец = Catalog.Проекты
// (стандартный реквизит, через Subordination ToItems).
//
Функция StagesGet(Запрос) Экспорт
Попытка
Запрос1С = Новый Запрос;
Запрос1С.Текст =
"ВЫБРАТЬ
| ЭтапыПроектов.Ссылка КАК Ссылка,
| ЭтапыПроектов.Код КАК Код,
| ЭтапыПроектов.Наименование КАК Наименование,
| ЭтапыПроектов.Владелец КАК Проект,
| ЭтапыПроектов.Родитель КАК Родитель,
| ЭтапыПроектов.ЭтоГруппа КАК ЭтоГруппа,
| ЭтапыПроектов.Кодификатор КАК Кодификатор,
| ЭтапыПроектов.ДатаНачала КАК ДатаНачала,
| ЭтапыПроектов.ДатаОкончания КАК ДатаОкончания,
| ЭтапыПроектов.Выполнен КАК Выполнен,
| ЭтапыПроектов.АктПодписан КАК АктПодписан,
| ЭтапыПроектов.ПометкаУдаления КАК ПометкаУдаления
|ИЗ
| Справочник.ЭтапыПроектов КАК ЭтапыПроектов";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Запись = Новый Структура;
Запись.Вставить("id", bfd_IntegrationAPIHelpers.UUID(Выборка.Ссылка));
Запись.Вставить("code", Выборка.Код);
Запись.Вставить("name", Выборка.Наименование);
Запись.Вставить("project_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Проект));
Запись.Вставить("parent_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Родитель));
Запись.Вставить("is_folder", Выборка.ЭтоГруппа);
Запись.Вставить("codifier", Выборка.Кодификатор);
Запись.Вставить("start_date", ?(ЗначениеЗаполнено(Выборка.ДатаНачала), Формат(Выборка.ДатаНачала, "ДФ=yyyy-MM-dd"), ""));
Запись.Вставить("end_date", ?(ЗначениеЗаполнено(Выборка.ДатаОкончания), Формат(Выборка.ДатаОкончания, "ДФ=yyyy-MM-dd"), ""));
Запись.Вставить("completed", Выборка.Выполнен);
Запись.Вставить("act_signed", Выборка.АктПодписан);
Запись.Вставить("deleted", Выборка.ПометкаУдаления);
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/work_types
//
Функция WorkTypesGet(Запрос) Экспорт
Попытка
Результат = Новый Массив;
МетаОбъект = Метаданные.Перечисления.ВидыРабот;
Для Каждого ЗначениеМД Из МетаОбъект.ЗначенияПеречисления Цикл
Запись = Новый Структура;
Запись.Вставить("code", ЗначениеМД.Имя);
Запись.Вставить("label", ЗначениеМД.Синоним);
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/dictionaries
//
Функция DictionariesGet(Запрос) Экспорт
Попытка
Ответ = Новый Структура;
Ответ.Вставить("offices", ПростойСправочник("Офис"));
Ответ.Вставить("departments", ПростойСправочник("Подразделение"));
Ответ.Вставить("managers", ПростойСправочник("Менеджеры"));
Ответ.Вставить("configurations", ПростойСправочник("Конфигурации"));
Ответ.Вставить("contracts", ПростойСправочник("Договоры"));
Ответ.Вставить("planning_scenarios", ПростойСправочник("СценарииПланирования"));
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Ответ);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/dept_history?modified_since=<ISO_DATE>
//
Функция DeptHistoryGet(Запрос) Экспорт
Попытка
МодифицированоПосле = bfd_IntegrationAPIHelpers.ПарсДатуISO(Запрос.ПараметрыЗапроса.Получить("modified_since"));
Запрос1С = Новый Запрос;
Запрос1С.УстановитьПараметр("МодифицированоПосле", МодифицированоПосле);
Запрос1С.Текст =
"ВЫБРАТЬ
| ИсторияПодразделений.Период КАК Период,
| ИсторияПодразделений.Сотрудник КАК Сотрудник,
| ИсторияПодразделений.Подразделение КАК Подразделение
|ИЗ
| РегистрСведений.ПодразделениеСотрудников КАК ИсторияПодразделений
|ГДЕ
| ИсторияПодразделений.Период >= &МодифицированоПосле";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Запись = Новый Структура;
Запись.Вставить("period", Формат(Выборка.Период, "ДФ=yyyy-MM-dd"));
Запись.Вставить("employee_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Сотрудник));
Запись.Вставить("department_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Подразделение));
Запись.Вставить("department_name", Строка(Выборка.Подразделение));
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/project_register?modified_since=<ISO_DATE>
// Для MVP-3, на старте можно не использовать.
//
Функция ProjectRegisterGet(Запрос) Экспорт
Попытка
МодифицированоПосле = bfd_IntegrationAPIHelpers.ПарсДатуISO(Запрос.ПараметрыЗапроса.Получить("modified_since"));
Запрос1С = Новый Запрос;
Запрос1С.УстановитьПараметр("МодифицированоПосле", МодифицированоПосле);
Запрос1С.Текст =
"ВЫБРАТЬ
| Регистр.Период КАК Период,
| Регистр.Регистратор КАК Регистратор,
| Регистр.Сценарий КАК Сценарий,
| Регистр.Проект КАК Проект,
| Регистр.ЭтапПроекта КАК ЭтапПроекта,
| Регистр.ВидАналитики КАК ВидАналитики,
| Регистр.Исполнитель КАК Исполнитель,
| Регистр.Сумма КАК Сумма,
| Регистр.СуммаАкт КАК СуммаАкт,
| Регистр.СуммаРасход КАК СуммаРасход
|ИЗ
| РегистрНакопления.ОборотыПроектныхПоказателей_v2 КАК Регистр
|ГДЕ
| Регистр.Период >= &МодифицированоПосле";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Запись = Новый Структура;
Запись.Вставить("period", Формат(Выборка.Период, "ДФ=yyyy-MM-ddTHH:mm:ss"));
Запись.Вставить("registrator_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Регистратор));
Запись.Вставить("scenario", Строка(Выборка.Сценарий));
Запись.Вставить("project_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Проект));
Запись.Вставить("stage_id", bfd_IntegrationAPIHelpers.UUID(Выборка.ЭтапПроекта));
Запись.Вставить("analytics_type", Строка(Выборка.ВидАналитики));
Запись.Вставить("employee_id", bfd_IntegrationAPIHelpers.UUID(Выборка.Исполнитель));
Запись.Вставить("sum_total", Выборка.Сумма);
Запись.Вставить("sum_acted", Выборка.СуммаАкт);
Запись.Вставить("sum_expense", Выборка.СуммаРасход);
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
// GET /v1/eva_mapping/projects
//
Функция EvaMappingProjectsGet(Запрос) Экспорт
Возврат ОтдатьРегистрМаппинга("СоответствиеПроектовEVA_РА");
КонецФункции
// GET /v1/eva_mapping/clients
//
Функция EvaMappingClientsGet(Запрос) Экспорт
Возврат ОтдатьРегистрМаппинга("СоответствиеКонтрагентовEVA_РА");
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Возвращает массив строк ТЧ "Работы" документа.
//
Функция ПолучитьСтрокиРаботы(Знач ДокументСсылка)
Объект = ДокументСсылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
Возврат Новый Массив;
КонецЕсли;
Строки = Новый Массив;
Для Каждого Стр Из Объект.Работы Цикл
Запись = Новый Структура;
Запись.Вставить("row_index", Стр.НомерСтроки);
Запись.Вставить("description", Стр.СодержаниеРабот);
Запись.Вставить("hours", Стр.КоличествоЧасов);
Запись.Вставить("work_type", Строка(Стр.ВидРаботы));
Запись.Вставить("work_type_code", ?(ЗначениеЗаполнено(Стр.ВидРаботы), XMLСтрока(Стр.ВидРаботы), ""));
Запись.Вставить("client_id", bfd_IntegrationAPIHelpers.UUID(Стр.Клиент));
Запись.Вставить("client_name", Строка(Стр.Клиент));
Запись.Вставить("manager_id", bfd_IntegrationAPIHelpers.UUID(Стр.Менеджер));
Запись.Вставить("project_id", bfd_IntegrationAPIHelpers.UUID(Стр.Проект));
Запись.Вставить("stage_id", bfd_IntegrationAPIHelpers.UUID(Стр.Этап));
Запись.Вставить("request_number", Стр.НомерЗаявки);
Запись.Вставить("lt_id", bfd_IntegrationAPIHelpers.UUID(Стр.ЛТ));
Запись.Вставить("work_done", Стр.РаботаВыполнена);
Строки.Добавить(Запись);
КонецЦикла;
Возврат Строки;
КонецФункции
// Возвращает простой плоский справочник как массив объектов {id, code, name}.
//
Функция ПростойСправочник(Знач ИмяСправочника)
Запрос1С = Новый Запрос;
Запрос1С.Текст =
"ВЫБРАТЬ
| Спр.Ссылка КАК Ссылка,
| Спр.Код КАК Код,
| Спр.Наименование КАК Наименование
|ИЗ
| Справочник." + ИмяСправочника + " КАК Спр
|ГДЕ
| НЕ Спр.ПометкаУдаления";
Выборка = Запрос1С.Выполнить().Выбрать();
Результат = Новый Массив;
Пока Выборка.Следующий() Цикл
Запись = Новый Структура;
Запись.Вставить("id", bfd_IntegrationAPIHelpers.UUID(Выборка.Ссылка));
Запись.Вставить("code", Выборка.Код);
Запись.Вставить("name", Выборка.Наименование);
Результат.Добавить(Запись);
КонецЦикла;
Возврат Результат;
КонецФункции
// Универсальный helper для регистров маппинга EVA_РА.
// Перебирает колонки регистра, ссылки сериализует UUID, даты ISO.
//
Функция ОтдатьРегистрМаппинга(Знач ИмяРегистра)
Попытка
Запрос1С = Новый Запрос;
Запрос1С.Текст = "ВЫБРАТЬ * ИЗ РегистрСведений." + ИмяРегистра;
ТЗ = Запрос1С.Выполнить().Выгрузить();
Результат = Новый Массив;
Для Каждого Стр Из ТЗ Цикл
Запись = Новый Структура;
Для Каждого Колонка Из ТЗ.Колонки Цикл
Значение = Стр[Колонка.Имя];
Если ТипЗнч(Значение) = Тип("Дата") Тогда
Запись.Вставить(Колонка.Имя, Формат(Значение, "ДФ=yyyy-MM-ddTHH:mm:ss"));
ИначеЕсли ТипЗнч(Значение) = Тип("Булево") ИЛИ ТипЗнч(Значение) = Тип("Число") ИЛИ ТипЗнч(Значение) = Тип("Строка") Тогда
Запись.Вставить(Колонка.Имя, Значение);
Иначе
Запись.Вставить(Колонка.Имя, ?(ЗначениеЗаполнено(Значение), bfd_IntegrationAPIHelpers.UUID(Значение), ""));
КонецЕсли;
КонецЦикла;
Результат.Добавить(Запись);
КонецЦикла;
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветJSON(Результат);
Исключение
Возврат bfd_IntegrationAPIHelpers.СформироватьОтветОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
#КонецОбласти