answer42 0.2.20__tar.gz → 0.2.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {answer42-0.2.20 → answer42-0.2.22}/PKG-INFO +1 -1
- {answer42-0.2.20 → answer42-0.2.22}/pyproject.toml +1 -1
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form/Module.bsl +301 -37
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/assets/MCPTestManager.cf +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/server.py +84 -3
- {answer42-0.2.20 → answer42-0.2.22}/.gitignore +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/LICENSE +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/README.md +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/credentials.example.json +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/docs/agent-installation.md +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/docs/architecture.md +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/docs/assets/answer42-logo.png +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/docs/assets/platform42-logo.svg +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/docs/installation.md +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/scripts/build_cf.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/scripts/build_pages.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/scripts/e2e_stable.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/scripts/openclaw_mcp_autoreload.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/scripts/rag_cli.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/Configuration.xml +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/DataProcessors/MCPTestManager.xml +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/Ext/ManagedApplicationModule.bsl +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Catalogs//320/237/320/241_/320/222/320/273/320/260/320/264/320/265/320/273/320/265/321/206.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Catalogs//320/237/320/241_/320/241/320/277/321/200/320/260/320/262/320/276/321/207/320/275/320/270/320/2721.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Configuration.xml +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ManagerModule.bsl" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ObjectModule.bsl" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205/Ext/Template.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262.xml" +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/__init__.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/assets/MCPTestClient.cf +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/assets/__init__.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/assets/skills/answer42/SKILL.md +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/assets/skills/answer42-rag/SKILL.md +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/bridge.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/credentials.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/os_support.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/platform.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/protocol.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/rag/__init__.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/rag/detect.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/rag/model.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/rag/parsers.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/rag/service.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/rag/store.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/recorder.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/release_helper.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/runtime.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/skill_installer.py +0 -0
- {answer42-0.2.20 → answer42-0.2.22}/src/mcp_1c/window_control.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: answer42
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.22
|
|
4
4
|
Summary: Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API
|
|
5
5
|
Author: Marvin (AI Assistant), 42Clouds, and contributors
|
|
6
6
|
Author-email: "Kosolapov Stanislav (proDOOMman)" <prodoomman@gmail.com>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "answer42"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.22"
|
|
4
4
|
description = "Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -412,6 +412,10 @@
|
|
|
412
412
|
Возврат ДобавитьСтрокуТаблицыMCP(Параметры);
|
|
413
413
|
ИначеЕсли Метод = "table_set_field" Тогда
|
|
414
414
|
Возврат УстановитьПолеТаблицыMCP(Параметры);
|
|
415
|
+
ИначеЕсли Метод = "table_set_row_values" Тогда
|
|
416
|
+
Возврат УстановитьЗначенияСтрокиТаблицыMCP(Параметры);
|
|
417
|
+
ИначеЕсли Метод = "set_form_fields" Тогда
|
|
418
|
+
Возврат УстановитьЗначенияПолейФормыMCP(Параметры);
|
|
415
419
|
ИначеЕсли Метод = "table_choose_field_from_list" Тогда
|
|
416
420
|
Возврат ВыбратьПолеТаблицыИзСпискаMCP(Параметры);
|
|
417
421
|
ИначеЕсли Метод = "table_edit_info" Тогда
|
|
@@ -3021,7 +3025,7 @@
|
|
|
3021
3025
|
Имя = СвойствоСтруктуры(Параметры, "name", "");
|
|
3022
3026
|
Заголовок = СвойствоСтруктуры(Параметры, "title", "");
|
|
3023
3027
|
Путь = СвойствоСтруктуры(Параметры, "path", "");
|
|
3024
|
-
ФорматФайла = СвойствоСтруктуры(Параметры, "format", "pdf");
|
|
3028
|
+
ФорматФайла = НРег(СвойствоСтруктуры(Параметры, "format", "pdf"));
|
|
3025
3029
|
Глубина = СвойствоСтруктуры(Параметры, "max_depth", 8);
|
|
3026
3030
|
Поле = НайтиТабличныйДокументПоПараметрам(АктивноеОкно, Имя, Заголовок, 0, Глубина);
|
|
3027
3031
|
Если Поле = Неопределено Тогда
|
|
@@ -3030,12 +3034,119 @@
|
|
|
3030
3034
|
Если ПустаяСтрока(Путь) Тогда
|
|
3031
3035
|
Путь = КаталогВременныхФайлов() + "tabular_document_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + "." + ФорматФайла;
|
|
3032
3036
|
КонецЕсли;
|
|
3037
|
+
|
|
3038
|
+
// Для tested form field extension for spreadsheet document direct Записать()
|
|
3039
|
+
// недоступен/ненадежен; используем штатный метод tested field
|
|
3040
|
+
// ЗаписатьСодержимоеВФайл(<СохранитьКак>) и очередь результата файлового
|
|
3041
|
+
// диалога. Для PDF пробуем несколько индексов фильтра и оба значения
|
|
3042
|
+
// <СохранитьКак> (Истина/Ложь), чтобы не угадывать поведение конкретной формы.
|
|
3043
|
+
Если ФорматФайла = "pdf" Тогда
|
|
3044
|
+
Файлы = Новый Массив;
|
|
3045
|
+
Ошибки = Новый Массив;
|
|
3046
|
+
ВариантыСохранитьКак = Новый Массив;
|
|
3047
|
+
ВариантыСохранитьКак.Добавить(Истина);
|
|
3048
|
+
ВариантыСохранитьКак.Добавить(Ложь);
|
|
3049
|
+
Для Каждого СохранитьКак Из ВариантыСохранитьКак Цикл
|
|
3050
|
+
Для ИндексФильтра = 1 По 10 Цикл
|
|
3051
|
+
ПутьПопытки = ДобавитьСуффиксКПутиMCP(Путь, "_saveas_" + ?(СохранитьКак, "true", "false") + "_filter" + Строка(ИндексФильтра));
|
|
3052
|
+
Попытка
|
|
3053
|
+
ТестируемоеПриложение.УстановитьРезультатДиалогаВыбораФайла(Истина, ПутьПопытки, ИндексФильтра);
|
|
3054
|
+
Поле.ЗаписатьСодержимоеВФайл(СохранитьКак);
|
|
3055
|
+
ОписаниеФайла = Новый Структура("path,filter_index,save_as", ПутьПопытки, ИндексФильтра, СохранитьКак);
|
|
3056
|
+
Файлы.Добавить(ОписаниеФайла);
|
|
3057
|
+
Исключение
|
|
3058
|
+
Ошибки.Добавить(Новый Структура("filter_index,save_as,error", ИндексФильтра, СохранитьКак, ОписаниеОшибки()));
|
|
3059
|
+
КонецПопытки;
|
|
3060
|
+
КонецЦикла;
|
|
3061
|
+
КонецЦикла;
|
|
3062
|
+
Если Файлы.Количество() > 0 Тогда
|
|
3063
|
+
Возврат Новый Структура("saved,path,format,method,files,errors", Истина, Путь, ФорматФайла, "write_content_to_file_dialog_filters", Файлы, Ошибки);
|
|
3064
|
+
КонецЕсли;
|
|
3065
|
+
Возврат Новый Структура("saved,path,format,method,files,errors", Ложь, Путь, ФорматФайла, "write_content_to_file_dialog_filters", Файлы, Ошибки);
|
|
3066
|
+
КонецЕсли;
|
|
3067
|
+
|
|
3068
|
+
ОшибкаЗаписатьСодержимое = "";
|
|
3033
3069
|
Попытка
|
|
3034
|
-
|
|
3035
|
-
|
|
3070
|
+
ТестируемоеПриложение.УстановитьРезультатДиалогаВыбораФайла(Истина, Путь, ИндексФильтраДиалогаТабличногоДокументаMCP(ФорматФайла));
|
|
3071
|
+
Поле.ЗаписатьСодержимоеВФайл(Истина);
|
|
3072
|
+
Возврат Новый Структура("saved,path,format,method,save_as", Истина, Путь, ФорматФайла, "write_content_to_file_dialog", Истина);
|
|
3036
3073
|
Исключение
|
|
3037
|
-
|
|
3074
|
+
ОшибкаЗаписатьСодержимое = ОписаниеОшибки();
|
|
3038
3075
|
КонецПопытки;
|
|
3076
|
+
Попытка
|
|
3077
|
+
ТестируемоеПриложение.УстановитьРезультатДиалогаВыбораФайла(Истина, Путь, ИндексФильтраДиалогаТабличногоДокументаMCP(ФорматФайла));
|
|
3078
|
+
Поле.ЗаписатьСодержимоеВФайл(Ложь);
|
|
3079
|
+
Возврат Новый Структура("saved,path,format,method,save_as", Истина, Путь, ФорматФайла, "write_content_to_file_dialog", Ложь);
|
|
3080
|
+
Исключение
|
|
3081
|
+
Если Не ПустаяСтрока(ОшибкаЗаписатьСодержимое) Тогда
|
|
3082
|
+
ОшибкаЗаписатьСодержимое = ОшибкаЗаписатьСодержимое + Символы.ПС + ОписаниеОшибки();
|
|
3083
|
+
Иначе
|
|
3084
|
+
ОшибкаЗаписатьСодержимое = ОписаниеОшибки();
|
|
3085
|
+
КонецЕсли;
|
|
3086
|
+
КонецПопытки;
|
|
3087
|
+
|
|
3088
|
+
Попытка
|
|
3089
|
+
ТипФайла = ТипФайлаТабличногоДокументаMCP(ФорматФайла);
|
|
3090
|
+
Поле.Записать(Путь, ТипФайла);
|
|
3091
|
+
Возврат Новый Структура("saved,path,format,method", Истина, Путь, ФорматФайла, "write_direct");
|
|
3092
|
+
Исключение
|
|
3093
|
+
Возврат Новый Структура("saved,path,format,error,content_error", Ложь, Путь, ФорматФайла, ОписаниеОшибки(), ОшибкаЗаписатьСодержимое);
|
|
3094
|
+
КонецПопытки;
|
|
3095
|
+
КонецФункции
|
|
3096
|
+
|
|
3097
|
+
&НаКлиенте
|
|
3098
|
+
Функция ДобавитьСуффиксКПутиMCP(Путь, Суффикс)
|
|
3099
|
+
ПозицияТочки = 0;
|
|
3100
|
+
Для Индекс = СтрДлина(Путь) По 1 Цикл
|
|
3101
|
+
Если Сред(Путь, Индекс, 1) = "." Тогда
|
|
3102
|
+
ПозицияТочки = Индекс;
|
|
3103
|
+
Прервать;
|
|
3104
|
+
КонецЕсли;
|
|
3105
|
+
КонецЦикла;
|
|
3106
|
+
Если ПозицияТочки = 0 Тогда
|
|
3107
|
+
Возврат Путь + Суффикс;
|
|
3108
|
+
КонецЕсли;
|
|
3109
|
+
Возврат Лев(Путь, ПозицияТочки - 1) + Суффикс + Сред(Путь, ПозицияТочки);
|
|
3110
|
+
КонецФункции
|
|
3111
|
+
|
|
3112
|
+
&НаКлиенте
|
|
3113
|
+
Функция ТипФайлаТабличногоДокументаMCP(ФорматФайла)
|
|
3114
|
+
Формат = НРег(Строка(ФорматФайла));
|
|
3115
|
+
Если Формат = "pdf" Тогда
|
|
3116
|
+
Возврат ТипФайлаТабличногоДокумента.PDF;
|
|
3117
|
+
ИначеЕсли Формат = "xlsx" Тогда
|
|
3118
|
+
Возврат ТипФайлаТабличногоДокумента.XLSX;
|
|
3119
|
+
ИначеЕсли Формат = "xls" Тогда
|
|
3120
|
+
Возврат ТипФайлаТабличногоДокумента.XLS;
|
|
3121
|
+
ИначеЕсли Формат = "mxl" Тогда
|
|
3122
|
+
Возврат ТипФайлаТабличногоДокумента.MXL;
|
|
3123
|
+
ИначеЕсли Формат = "html" Или Формат = "htm" Тогда
|
|
3124
|
+
Возврат ТипФайлаТабличногоДокумента.HTML;
|
|
3125
|
+
ИначеЕсли Формат = "txt" Тогда
|
|
3126
|
+
Возврат ТипФайлаТабличногоДокумента.TXT;
|
|
3127
|
+
Иначе
|
|
3128
|
+
Возврат ТипФайлаТабличногоДокумента.PDF;
|
|
3129
|
+
КонецЕсли;
|
|
3130
|
+
КонецФункции
|
|
3131
|
+
|
|
3132
|
+
&НаКлиенте
|
|
3133
|
+
Функция ИндексФильтраДиалогаТабличногоДокументаMCP(ФорматФайла)
|
|
3134
|
+
Формат = НРег(Строка(ФорматФайла));
|
|
3135
|
+
Если Формат = "pdf" Тогда
|
|
3136
|
+
Возврат 1;
|
|
3137
|
+
ИначеЕсли Формат = "xlsx" Тогда
|
|
3138
|
+
Возврат 2;
|
|
3139
|
+
ИначеЕсли Формат = "xls" Тогда
|
|
3140
|
+
Возврат 3;
|
|
3141
|
+
ИначеЕсли Формат = "mxl" Тогда
|
|
3142
|
+
Возврат 4;
|
|
3143
|
+
ИначеЕсли Формат = "html" Или Формат = "htm" Тогда
|
|
3144
|
+
Возврат 5;
|
|
3145
|
+
ИначеЕсли Формат = "txt" Тогда
|
|
3146
|
+
Возврат 6;
|
|
3147
|
+
Иначе
|
|
3148
|
+
Возврат 1;
|
|
3149
|
+
КонецЕсли;
|
|
3039
3150
|
КонецФункции
|
|
3040
3151
|
|
|
3041
3152
|
&НаКлиенте
|
|
@@ -3046,13 +3157,8 @@
|
|
|
3046
3157
|
Попытка
|
|
3047
3158
|
Подчиненные = БезопасныеПодчиненные(РодительскийОбъект);
|
|
3048
3159
|
Для Каждого Подчиненный Из Подчиненные Цикл
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
ИмяТек = БезопасноеСвойство(Подчиненный, "Имя", "");
|
|
3052
|
-
ЗаголовокТек = БезопасныйЗаголовок(Подчиненный);
|
|
3053
|
-
Если (ПустаяСтрока(Имя) Или ИмяТек = Имя) И (ПустаяСтрока(Заголовок) Или ЗаголовокТек = Заголовок) Тогда
|
|
3054
|
-
Возврат Подчиненный;
|
|
3055
|
-
КонецЕсли;
|
|
3160
|
+
Если ЭтоИскомоеПолеТабличногоДокумента(Подчиненный, Имя, Заголовок) Тогда
|
|
3161
|
+
Возврат Подчиненный;
|
|
3056
3162
|
КонецЕсли;
|
|
3057
3163
|
КонецЦикла;
|
|
3058
3164
|
Для Каждого Подчиненный Из Подчиненные Цикл
|
|
@@ -3068,6 +3174,31 @@
|
|
|
3068
3174
|
Возврат Неопределено;
|
|
3069
3175
|
КонецФункции
|
|
3070
3176
|
|
|
3177
|
+
&НаКлиенте
|
|
3178
|
+
Функция ЭтоИскомоеПолеТабличногоДокумента(Объект, Имя, Заголовок)
|
|
3179
|
+
ТипТек = НормализованноеИмяТипа(Строка(ТипЗнч(Объект)));
|
|
3180
|
+
ЭтоПолеТабличногоДокумента = ТипТек = "тестируемоеполетабличногодокументаформы";
|
|
3181
|
+
Если Не ЭтоПолеТабличногоДокумента И ТипТек = "тестируемоеполеформы" Тогда
|
|
3182
|
+
ЭтоПолеТабличногоДокумента = ПредставлениеДанныхПоляТабличныйДокумент(Объект);
|
|
3183
|
+
КонецЕсли;
|
|
3184
|
+
Если Не ЭтоПолеТабличногоДокумента Тогда
|
|
3185
|
+
Возврат Ложь;
|
|
3186
|
+
КонецЕсли;
|
|
3187
|
+
ИмяТек = БезопасноеСвойство(Объект, "Имя", "");
|
|
3188
|
+
ЗаголовокТек = БезопасныйЗаголовок(Объект);
|
|
3189
|
+
Возврат (ПустаяСтрока(Имя) Или ИмяТек = Имя) И (ПустаяСтрока(Заголовок) Или ЗаголовокТек = Заголовок);
|
|
3190
|
+
КонецФункции
|
|
3191
|
+
|
|
3192
|
+
&НаКлиенте
|
|
3193
|
+
Функция ПредставлениеДанныхПоляТабличныйДокумент(Поле)
|
|
3194
|
+
Попытка
|
|
3195
|
+
Представление = Поле.ПолучитьПредставлениеДанных();
|
|
3196
|
+
Возврат НРег(Строка(Представление)) = "табличныйдокумент";
|
|
3197
|
+
Исключение
|
|
3198
|
+
Возврат Ложь;
|
|
3199
|
+
КонецПопытки;
|
|
3200
|
+
КонецФункции
|
|
3201
|
+
|
|
3071
3202
|
|
|
3072
3203
|
|
|
3073
3204
|
&НаКлиенте
|
|
@@ -3981,11 +4112,98 @@
|
|
|
3981
4112
|
Возврат ИмяТек = ИмяПоля Или ЗаголовокТек = ИмяПоля Или СтрНайти(НРег(ИмяТек), НРег(ИмяПоля)) > 0 Или СтрНайти(НРег(ЗаголовокТек), НРег(ИмяПоля)) > 0;
|
|
3982
4113
|
КонецФункции
|
|
3983
4114
|
|
|
4115
|
+
&НаКлиенте
|
|
4116
|
+
Функция КлючСтрокиСоответствуетПолюMCP(Ключ, ИмяПоля, ИскатьПоЗаголовку)
|
|
4117
|
+
Если ИскатьПоЗаголовку Тогда
|
|
4118
|
+
Возврат Строка(Ключ) = ИмяПоля Или СтрНайти(НРег(Строка(Ключ)), НРег(ИмяПоля)) > 0;
|
|
4119
|
+
КонецЕсли;
|
|
4120
|
+
Возврат Строка(Ключ) = ИмяПоля Или СтрНайти(НРег(Строка(Ключ)), НРег(ИмяПоля)) > 0;
|
|
4121
|
+
КонецФункции
|
|
4122
|
+
|
|
4123
|
+
&НаКлиенте
|
|
4124
|
+
Функция НормализоватьЗначениеДляПроверкиMCP(Значение)
|
|
4125
|
+
Результат = НРег(СокрЛП(Строка(Значение)));
|
|
4126
|
+
Результат = СтрЗаменить(Результат, Символ(160), "");
|
|
4127
|
+
Результат = СтрЗаменить(Результат, " ", "");
|
|
4128
|
+
Результат = СтрЗаменить(Результат, ",", ".");
|
|
4129
|
+
Возврат Результат;
|
|
4130
|
+
КонецФункции
|
|
4131
|
+
|
|
4132
|
+
&НаКлиенте
|
|
4133
|
+
Функция ЗначенияСовпадаютДляПроверкиMCP(ФактическоеЗначение, ОжидаемоеЗначение)
|
|
4134
|
+
Факт = НормализоватьЗначениеДляПроверкиMCP(ФактическоеЗначение);
|
|
4135
|
+
Ожидание = НормализоватьЗначениеДляПроверкиMCP(ОжидаемоеЗначение);
|
|
4136
|
+
Если Факт = Ожидание Тогда
|
|
4137
|
+
Возврат Истина;
|
|
4138
|
+
КонецЕсли;
|
|
4139
|
+
Если Не ПустаяСтрока(Ожидание) И СтрНайти(Факт, Ожидание) > 0 Тогда
|
|
4140
|
+
Возврат Истина;
|
|
4141
|
+
КонецЕсли;
|
|
4142
|
+
Если Не ПустаяСтрока(Факт) И СтрНайти(Ожидание, Факт) > 0 Тогда
|
|
4143
|
+
Возврат Истина;
|
|
4144
|
+
КонецЕсли;
|
|
4145
|
+
Возврат Ложь;
|
|
4146
|
+
КонецФункции
|
|
4147
|
+
|
|
4148
|
+
&НаКлиенте
|
|
4149
|
+
Функция ЗначениеКолонкиТекущейСтрокиMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку)
|
|
4150
|
+
ТекущаяСтрока = Таблица.ПолучитьТекущуюСтроку();
|
|
4151
|
+
Если ТекущаяСтрока = Неопределено Тогда
|
|
4152
|
+
Возврат Новый Структура("found,key,value", Ложь, "", "");
|
|
4153
|
+
КонецЕсли;
|
|
4154
|
+
Для Каждого КЗ Из ТекущаяСтрока Цикл
|
|
4155
|
+
Если КлючСтрокиСоответствуетПолюMCP(КЗ.Ключ, ИмяПоля, ИскатьПоЗаголовку) Тогда
|
|
4156
|
+
Возврат Новый Структура("found,key,value", Истина, Строка(КЗ.Ключ), Строка(КЗ.Значение));
|
|
4157
|
+
КонецЕсли;
|
|
4158
|
+
КонецЦикла;
|
|
4159
|
+
Возврат Новый Структура("found,key,value", Ложь, "", "");
|
|
4160
|
+
КонецФункции
|
|
4161
|
+
|
|
4162
|
+
&НаКлиенте
|
|
4163
|
+
Процедура ОбеспечитьРедактированиеТекущейСтрокиТаблицыMCP(Таблица)
|
|
4164
|
+
Таблица.Активизировать();
|
|
4165
|
+
Попытка
|
|
4166
|
+
Если Не Таблица.ТекущийРежимРедактирование() Тогда
|
|
4167
|
+
Таблица.ИзменитьСтроку();
|
|
4168
|
+
КонецЕсли;
|
|
4169
|
+
Исключение
|
|
4170
|
+
Таблица.ИзменитьСтроку();
|
|
4171
|
+
КонецПопытки;
|
|
4172
|
+
КонецПроцедуры
|
|
4173
|
+
|
|
3984
4174
|
&НаКлиенте
|
|
3985
4175
|
Функция НайтиПолеТаблицыMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку)
|
|
3986
4176
|
Возврат НайтиПолеТаблицыРекурсивноMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку, 0, 8);
|
|
3987
4177
|
КонецФункции
|
|
3988
4178
|
|
|
4179
|
+
&НаКлиенте
|
|
4180
|
+
Функция НайтиПолеРедактораТаблицыMCP(АктивноеОкно, Таблица, ИмяТаблицы, ИмяПоля, ИскатьПоЗаголовку, МаксимальнаяГлубина)
|
|
4181
|
+
Кандидаты = Новый Массив;
|
|
4182
|
+
Если Не ПустаяСтрока(ИмяТаблицы) И Не ПустаяСтрока(ИмяПоля) Тогда
|
|
4183
|
+
Кандидаты.Добавить(ИмяТаблицы + ИмяПоля);
|
|
4184
|
+
КонецЕсли;
|
|
4185
|
+
Кандидаты.Добавить(ИмяПоля);
|
|
4186
|
+
|
|
4187
|
+
Для Каждого Кандидат Из Кандидаты Цикл
|
|
4188
|
+
Если ПустаяСтрока(Кандидат) Тогда
|
|
4189
|
+
Продолжить;
|
|
4190
|
+
КонецЕсли;
|
|
4191
|
+
Поле = НайтиОбъектРекурсивно(АктивноеОкно, Кандидат, "", "тестируемоеполеформы", 0, МаксимальнаяГлубина);
|
|
4192
|
+
Если Поле <> Неопределено Тогда
|
|
4193
|
+
Возврат Поле;
|
|
4194
|
+
КонецЕсли;
|
|
4195
|
+
КонецЦикла;
|
|
4196
|
+
|
|
4197
|
+
Если ИскатьПоЗаголовку Тогда
|
|
4198
|
+
Поле = НайтиОбъектРекурсивно(АктивноеОкно, "", ИмяПоля, "тестируемоеполеформы", 0, МаксимальнаяГлубина);
|
|
4199
|
+
Если Поле <> Неопределено Тогда
|
|
4200
|
+
Возврат Поле;
|
|
4201
|
+
КонецЕсли;
|
|
4202
|
+
КонецЕсли;
|
|
4203
|
+
|
|
4204
|
+
Возврат НайтиПолеТаблицыMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку);
|
|
4205
|
+
КонецФункции
|
|
4206
|
+
|
|
3989
4207
|
&НаКлиенте
|
|
3990
4208
|
Функция НайтиПолеТаблицыРекурсивноMCP(Элемент, ИмяПоля, ИскатьПоЗаголовку, Глубина, МаксимальнаяГлубина)
|
|
3991
4209
|
Если Элемент = Неопределено Или Глубина > МаксимальнаяГлубина Тогда
|
|
@@ -4018,45 +4236,91 @@
|
|
|
4018
4236
|
ИмяПоля = СвойствоСтруктуры(Параметры, "field", "");
|
|
4019
4237
|
Значение = СвойствоСтруктуры(Параметры, "value", "");
|
|
4020
4238
|
ИскатьПоЗаголовку = СвойствоСтруктуры(Параметры, "search_by_title", Ложь);
|
|
4239
|
+
МаксимальнаяГлубина = СвойствоСтруктуры(Параметры, "max_depth", 20);
|
|
4021
4240
|
АктивноеОкно = ТестируемоеПриложение.ПолучитьАктивноеОкно();
|
|
4022
|
-
Таблица = НайтиТаблицуПоПараметрам(АктивноеОкно, ИмяТаблицы, "", 0,
|
|
4241
|
+
Таблица = НайтиТаблицуПоПараметрам(АктивноеОкно, ИмяТаблицы, "", 0, МаксимальнаяГлубина);
|
|
4023
4242
|
Если Таблица = Неопределено Тогда
|
|
4024
4243
|
ВызватьИсключение "Таблица не найдена: " + ИмяТаблицы;
|
|
4025
4244
|
КонецЕсли;
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
КонецЕсли;
|
|
4031
|
-
Исключение
|
|
4032
|
-
Попытка
|
|
4033
|
-
Таблица.ИзменитьСтроку();
|
|
4034
|
-
Исключение
|
|
4035
|
-
КонецПопытки;
|
|
4036
|
-
КонецПопытки;
|
|
4037
|
-
Поле = НайтиПолеТаблицыMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку);
|
|
4245
|
+
|
|
4246
|
+
ОбеспечитьРедактированиеТекущейСтрокиТаблицыMCP(Таблица);
|
|
4247
|
+
АктивноеОкно = ТестируемоеПриложение.ПолучитьАктивноеОкно();
|
|
4248
|
+
Поле = НайтиПолеРедактораТаблицыMCP(АктивноеОкно, Таблица, ИмяТаблицы, ИмяПоля, ИскатьПоЗаголовку, МаксимальнаяГлубина);
|
|
4038
4249
|
Если Поле = Неопределено Тогда
|
|
4039
|
-
ВызватьИсключение "Поле таблицы не найдено: " + ИмяПоля;
|
|
4250
|
+
ВызватьИсключение "Поле редактора таблицы не найдено: " + ИмяПоля;
|
|
4040
4251
|
КонецЕсли;
|
|
4252
|
+
ИмяРедактора = БезопасноеСвойство(Поле, "Имя", "");
|
|
4041
4253
|
Поле.Активизировать();
|
|
4254
|
+
|
|
4255
|
+
ПараметрыПоля = Новый Структура("field_name,value,search_by_title,max_depth", ИмяРедактора, Значение, Ложь, МаксимальнаяГлубина);
|
|
4256
|
+
ОшибкаУстановки = "";
|
|
4257
|
+
РезультатУстановки = Новый Структура("method", "set_field_value");
|
|
4042
4258
|
Попытка
|
|
4043
|
-
|
|
4259
|
+
РезультатУстановки = УстановитьЗначениеПоля(ПараметрыПоля);
|
|
4044
4260
|
Исключение
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
Исключение
|
|
4051
|
-
ВызватьИсключение "Не удалось установить поле таблицы " + ИмяПоля + ": " + ОшибкаВвестиТекст + "; " + ОписаниеОшибки();
|
|
4052
|
-
КонецПопытки;
|
|
4261
|
+
// Для числовых полей табличной части ВвестиТекст() может фактически
|
|
4262
|
+
// изменить значение, но представление текущей строки обновится только
|
|
4263
|
+
// после ЗакончитьРедактированиеСтроки(). Поэтому не падаем сразу:
|
|
4264
|
+
// завершаем редактирование и ниже проверяем значение в текущей строке.
|
|
4265
|
+
ОшибкаУстановки = ОписаниеОшибки();
|
|
4053
4266
|
КонецПопытки;
|
|
4267
|
+
|
|
4054
4268
|
Попытка
|
|
4055
|
-
Таблица.ЗакончитьРедактированиеСтроки();
|
|
4269
|
+
Таблица.ЗакончитьРедактированиеСтроки(Ложь);
|
|
4056
4270
|
Исключение
|
|
4057
|
-
|
|
4271
|
+
Попытка
|
|
4272
|
+
Таблица.ЗакончитьРедактированиеСтроки();
|
|
4273
|
+
Исключение
|
|
4274
|
+
КонецПопытки;
|
|
4058
4275
|
КонецПопытки;
|
|
4059
|
-
|
|
4276
|
+
|
|
4277
|
+
Проверка = ЗначениеКолонкиТекущейСтрокиMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку);
|
|
4278
|
+
Проверено = Проверка.found И ЗначенияСовпадаютДляПроверкиMCP(Проверка.value, Значение);
|
|
4279
|
+
Если Не Проверено Тогда
|
|
4280
|
+
ДополнениеОшибки = ?(ПустаяСтрока(ОшибкаУстановки), "", "; ошибка set_field_value: " + ОшибкаУстановки);
|
|
4281
|
+
ВызватьИсключение "Поле таблицы " + ИмяПоля + " установлено через " + ИмяРедактора + ", но значение не подтвердилось; текущее значение: " + Проверка.value + ДополнениеОшибки;
|
|
4282
|
+
КонецЕсли;
|
|
4283
|
+
|
|
4284
|
+
МетодУстановки = СвойствоСтруктуры(РезультатУстановки, "method", "set_field_value");
|
|
4285
|
+
Если Не ПустаяСтрока(ОшибкаУстановки) Тогда
|
|
4286
|
+
МетодУстановки = МетодУстановки + "+verified_after_exception";
|
|
4287
|
+
КонецЕсли;
|
|
4288
|
+
Возврат Новый Структура("set,table,field,value,editor_field,verified,verified_key,verified_value,method,current_row", Истина, ИмяТаблицы, ИмяПоля, Значение, ИмяРедактора, Проверено, Проверка.key, Проверка.value, МетодУстановки, СоответствиеВСтруктуру(Таблица.ПолучитьТекущуюСтроку()));
|
|
4289
|
+
КонецФункции
|
|
4290
|
+
|
|
4291
|
+
&НаКлиенте
|
|
4292
|
+
Функция СтруктураИзJSONПараметраMCP(Параметры, ИмяПараметра)
|
|
4293
|
+
СтрокаJSON = СвойствоСтруктуры(Параметры, ИмяПараметра, "{}");
|
|
4294
|
+
Если ТипЗнч(СтрокаJSON) = Тип("Структура") Тогда
|
|
4295
|
+
Возврат СтрокаJSON;
|
|
4296
|
+
КонецЕсли;
|
|
4297
|
+
Возврат JSONВЗначение(СтрокаJSON);
|
|
4298
|
+
КонецФункции
|
|
4299
|
+
|
|
4300
|
+
&НаКлиенте
|
|
4301
|
+
Функция УстановитьЗначенияСтрокиТаблицыMCP(Параметры)
|
|
4302
|
+
Значения = СтруктураИзJSONПараметраMCP(Параметры, "values");
|
|
4303
|
+
ИмяТаблицы = СвойствоСтруктуры(Параметры, "table", "ДополнительнаяИнформация");
|
|
4304
|
+
ИскатьПоЗаголовку = СвойствоСтруктуры(Параметры, "search_by_title", Ложь);
|
|
4305
|
+
Результаты = Новый Массив;
|
|
4306
|
+
Для Каждого КЗ Из Значения Цикл
|
|
4307
|
+
ПараметрыПоля = Новый Структура("table,field,value,search_by_title", ИмяТаблицы, Строка(КЗ.Ключ), Строка(КЗ.Значение), ИскатьПоЗаголовку);
|
|
4308
|
+
Результаты.Добавить(УстановитьПолеТаблицыMCP(ПараметрыПоля));
|
|
4309
|
+
КонецЦикла;
|
|
4310
|
+
Возврат Новый Структура("set,table,values,results", Истина, ИмяТаблицы, Значения, Результаты);
|
|
4311
|
+
КонецФункции
|
|
4312
|
+
|
|
4313
|
+
&НаКлиенте
|
|
4314
|
+
Функция УстановитьЗначенияПолейФормыMCP(Параметры)
|
|
4315
|
+
Значения = СтруктураИзJSONПараметраMCP(Параметры, "values");
|
|
4316
|
+
ИскатьПоЗаголовку = СвойствоСтруктуры(Параметры, "search_by_title", Ложь);
|
|
4317
|
+
МаксимальнаяГлубина = СвойствоСтруктуры(Параметры, "max_depth", 20);
|
|
4318
|
+
Результаты = Новый Массив;
|
|
4319
|
+
Для Каждого КЗ Из Значения Цикл
|
|
4320
|
+
ПараметрыПоля = Новый Структура("field_name,value,search_by_title,max_depth", Строка(КЗ.Ключ), Строка(КЗ.Значение), ИскатьПоЗаголовку, МаксимальнаяГлубина);
|
|
4321
|
+
Результаты.Добавить(УстановитьЗначениеПоля(ПараметрыПоля));
|
|
4322
|
+
КонецЦикла;
|
|
4323
|
+
Возврат Новый Структура("set,values,results", Истина, Значения, Результаты);
|
|
4060
4324
|
КонецФункции
|
|
4061
4325
|
|
|
4062
4326
|
&НаКлиенте
|
|
Binary file
|
|
@@ -3294,7 +3294,59 @@ async def tabular_document_save(
|
|
|
3294
3294
|
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3295
3295
|
) -> Any:
|
|
3296
3296
|
"""Save a tabular document field to a file in the selected format."""
|
|
3297
|
-
|
|
3297
|
+
result = await _bridge_call_recorded(session_id, "tabular_document_save", {"name": name, "title": title, "path": path, "format": format, "max_depth": max_depth})
|
|
3298
|
+
return _select_saved_tabular_document_file(result, format)
|
|
3299
|
+
|
|
3300
|
+
|
|
3301
|
+
def _select_saved_tabular_document_file(result: Any, format: str) -> Any:
|
|
3302
|
+
if not isinstance(result, dict):
|
|
3303
|
+
return result
|
|
3304
|
+
files = result.get("files")
|
|
3305
|
+
if not isinstance(files, list) or not files:
|
|
3306
|
+
return result
|
|
3307
|
+
selected = _find_saved_tabular_document_file(files, format)
|
|
3308
|
+
if selected is None:
|
|
3309
|
+
result["selected"] = None
|
|
3310
|
+
return result
|
|
3311
|
+
selected_path = selected.get("path")
|
|
3312
|
+
requested_path = result.get("path")
|
|
3313
|
+
if isinstance(selected_path, str) and isinstance(requested_path, str) and requested_path and selected_path != requested_path:
|
|
3314
|
+
with suppress(Exception):
|
|
3315
|
+
shutil.copyfile(selected_path, requested_path)
|
|
3316
|
+
selected = dict(selected)
|
|
3317
|
+
selected["copied_to"] = requested_path
|
|
3318
|
+
result["path"] = requested_path
|
|
3319
|
+
result["selected"] = selected
|
|
3320
|
+
result["saved"] = True
|
|
3321
|
+
return result
|
|
3322
|
+
|
|
3323
|
+
|
|
3324
|
+
def _find_saved_tabular_document_file(files: list[Any], format: str) -> dict[str, Any] | None:
|
|
3325
|
+
wanted = format.lower()
|
|
3326
|
+
for item in files:
|
|
3327
|
+
if not isinstance(item, dict):
|
|
3328
|
+
continue
|
|
3329
|
+
file_path = item.get("path")
|
|
3330
|
+
if not isinstance(file_path, str):
|
|
3331
|
+
continue
|
|
3332
|
+
p = Path(file_path)
|
|
3333
|
+
if not p.is_file():
|
|
3334
|
+
continue
|
|
3335
|
+
try:
|
|
3336
|
+
header = p.read_bytes()[:8]
|
|
3337
|
+
except OSError:
|
|
3338
|
+
continue
|
|
3339
|
+
if wanted == "pdf" and header.startswith(b"%PDF"):
|
|
3340
|
+
return item
|
|
3341
|
+
if wanted in {"xlsx", "docx"} and header.startswith(b"PK\x03\x04"):
|
|
3342
|
+
return item
|
|
3343
|
+
if wanted == "xls" and header.startswith(bytes.fromhex("d0cf11e0a1b11ae1")):
|
|
3344
|
+
return item
|
|
3345
|
+
if wanted in {"html", "htm"} and (header.startswith(b"<") or header.startswith(b"\xef\xbb\xbf<")):
|
|
3346
|
+
return item
|
|
3347
|
+
if wanted in {"txt", "mxl"} and p.stat().st_size > 0:
|
|
3348
|
+
return item
|
|
3349
|
+
return None
|
|
3298
3350
|
|
|
3299
3351
|
|
|
3300
3352
|
@mcp.tool()
|
|
@@ -3871,11 +3923,40 @@ async def table_set_field(
|
|
|
3871
3923
|
field: Annotated[str, "Column field technical name or title"],
|
|
3872
3924
|
value: Annotated[str, "Value to set"],
|
|
3873
3925
|
search_by_title: Annotated[bool, "If true, match visible title instead of object name"] = False,
|
|
3926
|
+
max_depth: Annotated[int, "Maximum UI search depth"] = 20,
|
|
3927
|
+
*,
|
|
3928
|
+
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3929
|
+
) -> Any:
|
|
3930
|
+
"""Set a field in the currently edited row of a form table.
|
|
3931
|
+
|
|
3932
|
+
Finds the editor field for the column (e.g. ТоварыНоменклатура), activates it,
|
|
3933
|
+
delegates to the general set_field_value logic, ends row editing, and verifies
|
|
3934
|
+
the value in the current table row."""
|
|
3935
|
+
return await _bridge_call_recorded(session_id, "table_set_field", {"table": table, "field": field, "value": value, "search_by_title": search_by_title, "max_depth": max_depth})
|
|
3936
|
+
|
|
3937
|
+
|
|
3938
|
+
@mcp.tool()
|
|
3939
|
+
async def table_set_row_values(
|
|
3940
|
+
table: Annotated[str, "Table technical name"],
|
|
3941
|
+
values: Annotated[str, "JSON object mapping column names/titles to values"],
|
|
3942
|
+
search_by_title: Annotated[bool, "If true, match visible title instead of object name"] = False,
|
|
3943
|
+
*,
|
|
3944
|
+
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3945
|
+
) -> Any:
|
|
3946
|
+
"""Set multiple fields in the current row of a form table and verify each value."""
|
|
3947
|
+
return await _bridge_call_recorded(session_id, "table_set_row_values", {"table": table, "values": values, "search_by_title": search_by_title})
|
|
3948
|
+
|
|
3949
|
+
|
|
3950
|
+
@mcp.tool()
|
|
3951
|
+
async def set_form_fields(
|
|
3952
|
+
values: Annotated[str, "JSON object mapping field names/titles to values"],
|
|
3953
|
+
search_by_title: Annotated[bool, "If true, match visible title instead of object name"] = False,
|
|
3954
|
+
max_depth: Annotated[int, "Maximum UI search depth"] = 20,
|
|
3874
3955
|
*,
|
|
3875
3956
|
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3876
3957
|
) -> Any:
|
|
3877
|
-
"""Set
|
|
3878
|
-
return await _bridge_call_recorded(session_id, "
|
|
3958
|
+
"""Set multiple ordinary form fields using the same logic as set_field_value."""
|
|
3959
|
+
return await _bridge_call_recorded(session_id, "set_form_fields", {"values": values, "search_by_title": search_by_title, "max_depth": max_depth})
|
|
3879
3960
|
|
|
3880
3961
|
|
|
3881
3962
|
@mcp.tool()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{answer42-0.2.20 → answer42-0.2.22}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|