Initial project import

This commit is contained in:
2026-08-14 09:40:51 +03:00
parent 00040e5ce4
commit d7099bf80d
146 changed files with 30509 additions and 1055 deletions
+32
View File
@@ -0,0 +1,32 @@
# Development oracle for additional requisites
`additional_attributes_readonly.bsl` is server-side BSL intended only for the
isolated `upo_test` development configuration. It is an oracle for comparing
the platform result with the SQL adapter result; it is never a dependency of
the adapter, including in `upo_test`. It does not write application data or
configuration metadata. `additional_attributes_http_handler.bsl` is an
optional URL-template handler for manual development checks.
The service must expose two authenticated read-only operations:
- `additional_attributes.find``НайтиДополнительныеРеквизиты`;
- `additional_attributes.storage.resolve``МаршрутЗначенийДополнительногоРеквизита`.
The HTTP wrapper must accept/return JSON and restrict calls to the test
network. It must pass only `query`, `include_deleted`, a property UUID, and
the public owner selector. Do not accept arbitrary BSL or query text.
Use the result only to create SQL adapter fixtures and verify its semantic
mapping. The adapter itself must not call this endpoint, read its URL, or
depend on a 1C runtime connection. A missing physical source in `upo_test`
must therefore produce explicit SQL diagnostics, never a platform fallback.
Before publishing:
1. Add both modules to a test-only extension or HTTP service in Designer and
bind `ОбработатьRPC` to `POST /rpc`.
2. Restrict the service to read-only calls and test-network access.
3. Create or identify a non-deleted test property `Ответственное направление`.
4. Verify that the service returns its UUID, formula identifier, property set,
and value type; then verify the storage-route response for
`Справочник.СтруктурныеЕдиницы`.
@@ -0,0 +1,60 @@
// Обработчик URL-шаблона HTTP-сервиса, например POST /runtime-bridge/rpc.
// Требует общий серверный модуль ДополнительныеРеквизитыReadOnly
// (additional_attributes_readonly.bsl) в составе тестового расширения.
Функция ОбработатьRPC(Запрос) Экспорт
Попытка
ДанныеЗапроса = ПрочитатьJSONИзСтроки(Запрос.ПолучитьТелоКакСтроку());
Метод = ДанныеЗапроса.method;
Параметры = ДанныеЗапроса.payload;
Если Метод = "additional_attributes.find" Тогда
ТекстПоиска = ПолучитьПараметр(Параметры, "query", "");
ВключатьУдаленные = ПолучитьПараметр(Параметры, "include_deleted", Ложь);
Результат = Новый Структура("status,properties", "found", ДополнительныеРеквизитыReadOnly.НайтиДополнительныеРеквизиты(ТекстПоиска, ВключатьУдаленные));
Если Результат.properties.Количество() = 0 Тогда
Результат.status = "not_found";
КонецЕсли;
ИначеЕсли Метод = "additional_attributes.storage.resolve" Тогда
СсылкаСвойства = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.ПолучитьСсылку(Новый УникальныйИдентификатор(Параметры.property_ref));
Маршрут = ДополнительныеРеквизитыReadOnly.МаршрутЗначенийДополнительногоРеквизита(СсылкаСвойства, Параметры.owner_ref);
Результат = Новый Структура("status,property_ref,owner_ref,storage,scd_join", "confirmed", Параметры.property_ref, Параметры.owner_ref,
Новый Структура("source_ref,source_kind,fields", Маршрут.source, "TabularSection", Новый Структура("object,property,value", Маршрут.object_field, Маршрут.property_field, Маршрут.value_field)),
Новый Структура("source,alias,condition,value_expression,parameters", Маршрут.source, "ДополнительныеРеквизиты", Маршрут.query_join, "ДополнительныеРеквизиты.Значение", Новый Структура("Свойство", Маршрут.parameter)));
Иначе
Возврат ОтветJSON(405, Новый Структура("status,error", "invalid_argument", "Unsupported read-only bridge method."));
КонецЕсли;
Возврат ОтветJSON(200, Результат);
Исключение
// Не передаем внутренний стек и сведения о подключении.
Возврат ОтветJSON(400, Новый Структура("status,error", "error", "Invalid read-only bridge request."));
КонецПопытки;
КонецФункции
Функция ПолучитьПараметр(СтруктураПараметров, Имя, ЗначениеПоУмолчанию) Экспорт
Значение = ЗначениеПоУмолчанию;
Если СтруктураПараметров.Свойство(Имя, Значение) Тогда
Возврат Значение;
КонецЕсли;
Возврат ЗначениеПоУмолчанию;
КонецФункции
Функция ПрочитатьJSONИзСтроки(ТекстJSON) Экспорт
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТекстJSON);
Попытка
Возврат ПрочитатьJSON(ЧтениеJSON);
Наконец
ЧтениеJSON.Закрыть();
КонецПопытки;
КонецФункции
Функция ОтветJSON(КодСостояния, Данные) Экспорт
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Данные);
ТекстJSON = ЗаписьJSON.Закрыть();
Ответ = Новый HTTPСервисОтвет(КодСостояния);
Ответ.УстановитьТелоИзСтроки(ТекстJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Возврат Ответ;
КонецФункции
@@ -0,0 +1,85 @@
// Общий модуль серверного HTTP-сервиса. Все экспортные методы только читают данные.
// Модуль предназначен для публикации в тестовой конфигурации, а не для выполнения
// из SQL-адаптера. Аутентификацию и разбор HTTP-запроса реализует модуль сервиса.
Функция НайтиДополнительныеРеквизиты(ТекстПоиска = "", ВключатьПомеченныеНаУдаление = Ложь) Экспорт
Результат = Новый Массив;
Выборка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.Выбрать();
Пока Выборка.Следующий() Цикл
Если Не ВключатьПомеченныеНаУдаление И Выборка.ПометкаУдаления Тогда
Продолжить;
КонецЕсли;
Если ЗначениеЗаполнено(ТекстПоиска)
И СтрНайти(НРег(Выборка.Наименование), НРег(ТекстПоиска)) = 0 Тогда
Продолжить;
КонецЕсли;
ОбъектСвойства = Выборка.ПолучитьОбъект();
СтрокаСвойства = Новый Структура;
СтрокаСвойства.Вставить("ref", Строка(Выборка.Ссылка.УникальныйИдентификатор()));
СтрокаСвойства.Вставить("description", Выборка.Наименование);
СтрокаСвойства.Вставить("marked_for_deletion", Выборка.ПометкаУдаления);
ДобавитьСвойствоЕслиЕсть(СтрокаСвойства, ОбъектСвойства, "Имя", "name");
ДобавитьСвойствоЕслиЕсть(СтрокаСвойства, ОбъектСвойства, "ИдентификаторДляФормул", "identifier_for_formula");
ДобавитьСвойствоЕслиЕсть(СтрокаСвойства, ОбъектСвойства, "НаборСвойств", "property_set");
ДобавитьСвойствоЕслиЕсть(СтрокаСвойства, ОбъектСвойства, "ТипЗначения", "value_type");
// Отдельно фиксируем наличие реквизита в объекте ПВХ. Это позволяет
// SQL-разработке отличить пустое значение от отсутствующей семантики.
СтрокаСвойства.Вставить("semantic_fields", Новый Структура(
"name,identifier_for_formula,property_set,value_type",
СтрокаСвойства.Свойство("name"),
СтрокаСвойства.Свойство("identifier_for_formula"),
СтрокаСвойства.Свойство("property_set"),
СтрокаСвойства.Свойство("value_type")));
Результат.Добавить(СтрокаСвойства);
КонецЦикла;
Возврат Результат;
КонецФункции
Функция МаршрутЗначенийДополнительногоРеквизита(Свойство, ВладелецМетаданных) Экспорт
Если ТипЗнч(Свойство) <> Тип("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения") Тогда
ВызватьИсключение "Свойство должно быть ссылкой ПВХ ДополнительныеРеквизитыИСведения.";
КонецЕсли;
Если ВладелецМетаданных <> "Справочник.СтруктурныеЕдиницы" Тогда
ВызватьИсключение "Маршрут подтвержден только для Справочник.СтруктурныеЕдиницы.";
КонецЕсли;
// Текст предназначен для СКД и не исполняется сервисом. В этой
// конфигурации значения подтверждённо находятся в табличной части владельца.
Возврат Новый Структура(
"source,object_field,property_field,value_field,query_join,parameter",
"Справочник.СтруктурныеЕдиницы.ДополнительныеРеквизиты",
"Ссылка",
"Свойство",
"Значение",
"ЛЕВОЕ СОЕДИНЕНИЕ Справочник.СтруктурныеЕдиницы.ДополнительныеРеквизиты КАК ДополнительныеРеквизиты "
+ "ПО ДополнительныеРеквизиты.Ссылка = СтруктурныеЕдиницы.Ссылка "
+ "И ДополнительныеРеквизиты.Свойство = &Свойство",
Строка(Свойство.УникальныйИдентификатор())
);
КонецФункции
Процедура ДобавитьСвойствоЕслиЕсть(Приемник, Источник, ИмяСвойства, ИмяПоля) Экспорт
ЗначениеСвойства = Неопределено;
Если Источник.Свойство(ИмяСвойства, ЗначениеСвойства) Тогда
Приемник.Вставить(ИмяПоля, ПредставлениеДляJSON(ЗначениеСвойства));
КонецЕсли;
КонецПроцедуры
Функция ПредставлениеДляJSON(ЗначениеСвойства) Экспорт
Если ЗначениеСвойства = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Если ТипЗнч(ЗначениеСвойства) = Тип("Структура") Или ТипЗнч(ЗначениеСвойства) = Тип("Массив") Тогда
Возврат ЗначениеСвойства;
КонецЕсли;
Попытка
УникальныйИдентификатор = ЗначениеСвойства.УникальныйИдентификатор();
Возврат Новый Структура("ref,presentation", Строка(УникальныйИдентификатор), Строка(ЗначениеСвойства));
Исключение
КонецПопытки;
Возврат Строка(ЗначениеСвойства);
КонецФункции