Настроил Jobmanager согласно мануалу, инсталлировал и запустил. 

Получаю ошибку:

JobLauncher: Script 'Method' execute error: Path not found

 

Система Windows Server 2019

Нравится

3 комментария

Добрый день,

 

Сложно сказать в чем именно причина, без анализа выполненных настроек и проведения отладки.

Проверьте, пожалуйста, все ли шаги настройки выполнены согласно документации (файлы во вложении).

Если да, значит остается только вариант с выполнением отладки. Примеры, как активировать отладчик, есть здесь на community.

Вот некоторые ссылки:

https://community.terrasoft.ru/questions/kakie-otladchiki-mozhno-ispolzovat

https://community.terrasoft.ru/questions/ne-rabotaet-debugger

 

 

С уважением,
Кучер Виталина
Оператор
Группа компаний Terrasoft

v.kucher@creatio.com,

TSJobmanager запускается на одной из машин, и работает там без ошибок. Пытаюсь перенести его на сервер. Все настройки соответствуют мануалу. Не совсем понимаю как мне использовать дебаг. Судя по всему, проблема не в запускаемом скрипте, а в конфигурации машины. Не могу понять чего не хватает.

Вопрос снят, оказалось в одном из скриптов был жестко прописан путь к файлу.

Показать все комментарии

Доброго времени суток, коллеги.

Есть ТеррасофтCRM 3.3.2.311. 

Пытаюсь добавить на форму компонент PivotTableControl. В результате получаю ошибку: "Класс не зарегистрирован". Переустановка не помогла, ошибка проявляется и на Windows 7 и на 10. 

Кому-нибудь приходилось работать со сводными таблицами в TerrasoftCRM?

Нравится

0 комментариев
Показать все комментарии

Добрый день.

Как можно сделать более красивый DataGrid в Terrasoft 3.x 

В свойствах объекта DataGridСolumn есть возможность изменить цвет самой колонки, а как поменять шрифт и цвет самого текста, как заглавного, так и вывода?

Нравится

7 комментариев

Алексей, в первую очередь нужно уточнить версию софта. При переходе с 3.4.0 на 3.4.1 было добавлено много возможностей со шрифтами. Проверьте, может, получится и то, что хотите.

Если же делать что-то совсем нестандартное, может подойти компонент веб-браузера и программное создание HTML-файла. Именно так для продавцов квартир делалась «шахматка» — схема дома с проданными и непроданными квартирами разных цветов с возможностью открыть карточку квартиры по гиперссылке.

У меня 3.4.0.

 

Нашел пример кода и решил подделать под свою задачу, но не получается:

function grdDataOnGetCellDrawInfo(DataGrid, Column, Color) {
    var DataFieldValue = gvData.Items('colstopgvData').DataField.Value;
    if (!IsEmptyValue(DataFieldValue)) {
        Color.Value = clRed;
    };
}

Мне кажется, это код для цвета фона, а не шрифта.

Зверев Александр,

Не подскажете, как обратиться к объекту colstopgvData, чтобы задать ему нужный цвет шрифт и форму. Разрисовать любую ячейку.

Во всех примерах доработок меняют только фон. Вы можете поставить точку остановки и посмотреть в отладчике, какие там вообще есть свойства в момент отработки этой функции.

Нечто получилось, но не то что хотел.

1. Включил в DataGrid два свойства: HasCustomCellDraw и HasCustomDraw. В противном случае, рисовать ничего в DataGrid не будет.

2. Добавил обработку события OnGetCellDrawInfo снабдив его функцией, где gvData - IDataGridView, а is_day - DataFieldName одной из IDataGridColumn:

function grdDataOnGetCellDrawInfo(DataGrid, Column, Color) {
    try {
        if(gvData.Items(Column).DataFieldName == 'is_block' || gvData.Items(Column).DataFieldName == 'is_day' || gvData.Items(Column).DataFieldName == 'is_stop') {       
            var DataFieldValue = gvData.Items(Column).DataField.Value;
            if (!IsEmptyValue(DataFieldValue) && DataFieldValue!=' '){
                Color.Value = clYellow;
            }
        }    
    } catch(E) {
        Log.Write(mdtError, '[grdDataOnGetCellDrawInfo] ' + E.message+' ['+E.number+']');
    } finally { }    
}

3. Добавил обработку события OnGetCellDrawInfo снабдив его функцией, где dlData - это DataSet, в котором формируются данные  для вывода в DataGrid:

function grdDataOnGetRowDrawInfo(DataGrid, Color, TextColor, ImageName, Font) {
    var Dataset = dlData.Dataset;
    var Current = GetFieldValueFromDisabledField(Dataset, 'is_block');
    if (!IsEmptyValue(Current )){
        TextColor.Value = clRed;
    }
    Current = GetFieldValueFromDisabledField(Dataset, 'is_day');
    if (!IsEmptyValue(Current )){
        TextColor.Value = clRed;
    }
    Current = GetFieldValueFromDisabledField(Dataset, 'is_stop');
    if (!IsEmptyValue(Current )){
        TextColor.Value = clRed;
    }
}

 

Итог сей махинации следующий:

Ряд в котором есть заполненное поле в одной из 3 колонок меняет цвет шрифта на красный, а ячейка заполненная данными окрашивается в желтый.

 

Я так и не понял, как поменять цвет нужной ячейки без закрашивания всего ряда.

Не совсем понял, почему Вы для красного цвета в if проверяете три разных поля. Может, для всех условия выполнились? Если оставить одно, тоже весь ряд закрасится? Не смотрели в отладке, как отработало?

Показать все комментарии

Добрый день.

Подскажите, пожалуйста, как в Терассофт 3.х реализовать запуск функции, допустим нажатия кнопки, через 5 минут при этом не делая зависание программы. Я нажимаю на кнопку и запуская функцию. Работаю далее и через 5 минут мне выскочит сообщение "Привет мир!".

Нравится

2 комментария

Алексей, в 3.Х на карточке есть возможность добавить невизуальный компонент «Таймер». Можно задать в дизайнере или программно ему длительность, включить и добавить в обработчик нужную логику.

Спасибо за подсказку. Нашел решение здесь: https://community.terrasoft.ru/articles/obnovlenie-reestra-zapisei-s-op…

Показать все комментарии

Добрый день.

Подскажите, пожалуйста, есть задача в Terrasoft при нажатии на кнопку создавать массив элементов edit и label с названиями и именами. Плюс, нужно еще edit присвоить событие onchange.

Нравится

5 комментариев
Лучший ответ

Задачу решил так :

function PacientEmailForm(Window) {
    //Создание дополнительных компонентов для вывода массива данных для пациентов   
    try {
        var PacientLabel = null;
        var PacientName = null;
        var PacientDate = null;
        var PacientTest = null;
        var PacientText = null;
        var PacientNumber = 0;
        for (var i = 0; i < 2; i++) {
            //Создание метки для структуризации компонентов - ЗАГОЛОВОК
            PacientLabel = EmailFormWindowValue.CreateComponent('Label','lbPacient'+i);
            fgPacient.Add(PacientLabel);
            PacientLabel.AlignHorizontal = alhCenter;
            PacientLabel.AutoSize = true;
            PacientNumber = i+1;
            PacientLabel.Caption = 'Пациент № '+PacientNumber;
            //Создание поля вывода для имени пациента
            PacientName = EmailFormWindowValue.CreateComponent('Edit','edtPacientName'+i);
            fgPacient.Add(PacientName);
            PacientName.AlignHorizontal = alhClient;
            PacientName.Caption = 'ФИО';
            //Создание поля вывода для даты рождения пациента
            PacientDate = EmailFormWindowValue.CreateComponent('Edit','edtPacientDate'+i);
            fgPacient.Add(PacientDate);
            PacientDate.AlignHorizontal = alhClient;
            PacientDate.EditMask = '99.99.9999';
            PacientDate.Caption = 'Дата рождения';
            //Создание поля вывода для тестов
            PacientTest = EmailFormWindowValue.CreateComponent('Edit','edtPacientTest'+i);
            fgPacient.Add(PacientTest);
            PacientTest.AlignHorizontal = alhClient;
            PacientTest.Caption = 'Тесты и услуги';
            //Создание поля вывода для инвалидности
            PacientText = EmailFormWindowValue.CreateComponent('Edit','edtPacientText'+i);
            fgPacient.Add(PacientText);
            PacientText.AlignHorizontal = alhClient;
            PacientText.Caption = 'Инвалидности';
            //Скрыть все элементы и использовать по надобности
            PacientLabel.isVisible = false;
            PacientName.isVisible = false; 
            PacientDate.isVisible = false; 
            PacientTest.isVisible = false; 
            PacientText.isVisible = false;
        }        
        //var Pacient = Window.CreateComponent('Label','PacientLabel');
        //fgPacient.Add(Pacient); 
        //Pacient.Caption = 'Проверка!';
    } catch(E) {
        Log.Write(mdtError, '[PacientEmailForm] ' + E.message+' ['+E.number+']');
    } finally {}
}

Задачу решил так :

function PacientEmailForm(Window) {
    //Создание дополнительных компонентов для вывода массива данных для пациентов   
    try {
        var PacientLabel = null;
        var PacientName = null;
        var PacientDate = null;
        var PacientTest = null;
        var PacientText = null;
        var PacientNumber = 0;
        for (var i = 0; i < 2; i++) {
            //Создание метки для структуризации компонентов - ЗАГОЛОВОК
            PacientLabel = EmailFormWindowValue.CreateComponent('Label','lbPacient'+i);
            fgPacient.Add(PacientLabel);
            PacientLabel.AlignHorizontal = alhCenter;
            PacientLabel.AutoSize = true;
            PacientNumber = i+1;
            PacientLabel.Caption = 'Пациент № '+PacientNumber;
            //Создание поля вывода для имени пациента
            PacientName = EmailFormWindowValue.CreateComponent('Edit','edtPacientName'+i);
            fgPacient.Add(PacientName);
            PacientName.AlignHorizontal = alhClient;
            PacientName.Caption = 'ФИО';
            //Создание поля вывода для даты рождения пациента
            PacientDate = EmailFormWindowValue.CreateComponent('Edit','edtPacientDate'+i);
            fgPacient.Add(PacientDate);
            PacientDate.AlignHorizontal = alhClient;
            PacientDate.EditMask = '99.99.9999';
            PacientDate.Caption = 'Дата рождения';
            //Создание поля вывода для тестов
            PacientTest = EmailFormWindowValue.CreateComponent('Edit','edtPacientTest'+i);
            fgPacient.Add(PacientTest);
            PacientTest.AlignHorizontal = alhClient;
            PacientTest.Caption = 'Тесты и услуги';
            //Создание поля вывода для инвалидности
            PacientText = EmailFormWindowValue.CreateComponent('Edit','edtPacientText'+i);
            fgPacient.Add(PacientText);
            PacientText.AlignHorizontal = alhClient;
            PacientText.Caption = 'Инвалидности';
            //Скрыть все элементы и использовать по надобности
            PacientLabel.isVisible = false;
            PacientName.isVisible = false; 
            PacientDate.isVisible = false; 
            PacientTest.isVisible = false; 
            PacientText.isVisible = false;
        }        
        //var Pacient = Window.CreateComponent('Label','PacientLabel');
        //fgPacient.Add(Pacient); 
        //Pacient.Caption = 'Проверка!';
    } catch(E) {
        Log.Write(mdtError, '[PacientEmailForm] ' + E.message+' ['+E.number+']');
    } finally {}
}

Теперь возник вопрос, как удалить элемент созданный таким образом?

Алексей, если добавляли при помощи CreateComponent, то удалить, соответственно, можно по RemoveComponent. См. примеры в теме.

Зверев Александр,

Спасибо. Так и сделал. Правда со 2 попытки. Первая была DeleteComponent. А не подскажете, как событие присвоить Edit

.OnChange ?

Присваивают обработчики так, см. src_Main:

var MenuItem = Window.CreateComponent('ActionMenuItem', Name);
MenuItem.Caption = CaptionDataField.ValAsStr;
MenuItem.Tag = ParentIDDataField.ValAsStr;
SetObjectEventDispatcher(Window, MenuItem, MenuItem.Name, 'OnExecute',
	'DictionaryMenuItemOnExecute');

Если компонентов будет произвольное количество, можно обработчик сделать один и тот же, а в нём считывать значение свойства Tag, которое перед этим присвоить каждому разное.

Показать все комментарии

Добрый день.

Возникла интересная задача. Можно ли в Terrasoft сделать запуск функции Terrasoft из окна вывода html при событии click? 

Функция alert() обрабатывается нормально. А вот запуск функции, которая лежит в Terrasoft, как сделать? 

К примеру, в php и js связке можно обратится из js к php при помощи ajax. Есть ли тут аналог?

 

Нравится

1 комментарий

Алексей, такое возможно, так работают гиперссылки на разные сущности системы в почте. Ссылки стандартно есть на открытие карточки (open) и на переход в раздел с нужной записью (goto). Увидеть их обе можно, в реестре нажав правую кнопку и выбрав пункт «Копировать ссылку», они скопируются в буфер.

Чтобы сделать другие обработчики, нужно вносить правки в сервис scr_HyperlinkUtils, добавить в функции RunHyperlink дополнительное ветвление к тем двум, что там есть:

function RunHyperlink(Action, Params) {
	Action = Action.toLowerCase();
	switch (Action) {
		case 'goto':
			HyperlinkGotoWorkspace(Params);
			break;
		case 'open':
			HyperlinkOpenCard(Params);
			break;
	}
}

А затем написать аналогичную упомянутым функцию, выполняющую нужные действия в зависимости от параметров. Пример с запуском так БП есть тут.

 

Показать все комментарии

Добрый день.

Как реализовать многострочный заголовок в объекте DataGrid?

Дни недели | Рабочие часы | ФИО сотрудника

превратить в:

Дни       | Рабочие     | ФИО

недели | часы            | сотрудника

Нравится

5 комментариев

Алексей, в свойствах колонки в Dataset такое свойство настраивается, но оно предназначено для другого, общего заголовка для нескольких колонок:

Заголовок у меня есть

 

Но в Grid он не многострочный

 

Эта настройка для другого: если нескольким полям там вписать одинаковое до черты, то они сгруппируются с общей «шапкой». Пример настройки из этой темы:

Немного не то, но за это спасибо. Буду иметь ввиду функционал с |

Алексей, нашёл тему именно по тому, что Вы хотели. Увы, такого не прредумотрено.

Показать все комментарии

Добрый день.

Хочу реализовать такие функции. Данные, которые я планирую получать,  это значения с таблицы. Есть ли в террасофт возможнось напрямую сделать запрос к БД для получения нужных результатов?

К примеру, как на php mysql_query + mysql_feach_array

function FillMemoryDataset(Dataset) {
    var Items = GetAttribute(Dataset, 'Items');
    if (!Assigned(Items)) { return; }
    Dataset.DisableEvents();
    try {
        for (var i = 0; i < Items.length; i++) {
            var Item = Items[i];                    
            Dataset.Append();
            Dataset.ValAsInt('id') = Item['id'];
            Dataset.ValAsStr('type') = Item['type'];
            Dataset.ValAsStr('pricecode') = Item['pricecode'];
            Dataset.ValAsStr('title') = Item['title'];
            Dataset.ValAsStr('text_method') =
                PrepareTestInfoStringToSearch(Item['text_method']);
            Dataset.ValAsStr('material') =
                PrepareTestInfoStringToSearch(Item['material']);                
            Dataset.ValAsStr('is_block') = GetBlockedTestInformation(Item['pricecode']);                
            Dataset.ValAsStr('is_day') = GetDayTestInformation(Item['pricecode']);                
            Dataset.ValAsStr('is_stop') = GetStopedTestInformation(Item['pricecode']);
            Dataset.ValAsBool('is_custom') = (Item['is_custom'] == true);
            Dataset.Post();
        }
    }
    finally {
        Dataset.EnableEvents();  
        Dataset.GoToFirst();
    }
}
function GetBlockedTestInformation(pricecode)
{
    Result = '';

//Тут нужно получить данные из другого запроса sq_
    return Result;
}
function GetDayTestInformation(pricecode)
{
    Result = '';
    return Result;
}
function GetStopedTestInformation(pricecode)
{
    Result = '';
    return Result;
}

Нравится

7 комментариев
Лучший ответ

Сделал так

var ds = Services.GetNewItemByUSI('mds_KsCallInvitroApiTestAdds');
            ApplyDatasetFilter(ds, 'pricecode', Item['pricecode'], true); 
            var IsBlock = '';
            var IsDay = '';
            var IsStop = '';
            ds.Open();                
            IsBlock = ds.ValAsStr('is_block');
            IsDay = ds.ValAsStr('is_day');
            IsStop = ds.ValAsStr('is_stop');            
            ds.close();
            Dataset.ValAsStr('is_block') = IsBlock;                
            Dataset.ValAsStr('is_day') = IsDay;                
            Dataset.ValAsStr('is_stop') = IsStop;

Добрый день.

 

Вы можете реализовать представление (view) и использовать его в Вашем гриде.

 

Посмотрите похожая тема обсуждается здесь.

Возможно ли это функциями Террасофта провернуть без использования Dataset?

Сделал так

var ds = Services.GetNewItemByUSI('mds_KsCallInvitroApiTestAdds');
            ApplyDatasetFilter(ds, 'pricecode', Item['pricecode'], true); 
            var IsBlock = '';
            var IsDay = '';
            var IsStop = '';
            ds.Open();                
            IsBlock = ds.ValAsStr('is_block');
            IsDay = ds.ValAsStr('is_day');
            IsStop = ds.ValAsStr('is_stop');            
            ds.close();
            Dataset.ValAsStr('is_block') = IsBlock;                
            Dataset.ValAsStr('is_day') = IsDay;                
            Dataset.ValAsStr('is_stop') = IsStop;

Для тех кто хочет получить данные из другого dataset это прост отлично подходит

Алексей, кроме предложенного Аллой варианта есть и более простой штатный способ: можно в дизайнере sq настроить колонку-подзапрос или колонку с произвольным SQL-кодом, где и реализовать вычисление нужного значения или вызов SQL-функции.

Спасибо. Но для моей задачи подошел мой вариант. Так как основной dataset формируется не по sql, а с выборки в api и мне нужно было к нему приплюсовать еще и sq.

Алексей, сразу не заметил, что Вам нужно обязательно через программное наполнение полей MemoryDataset.

Если оба источника данных, и основной, и вспомогательный типа MemoryDataset, то так, как Вы написали.

А если вспомогательный — обычный Dataset, считывающий из базы по sq и ds, то его при желании тоже можно программно создать, наложить фильтр, открыть и считать значения полей.

 

Показать все комментарии

Добрый день.

 У мне при работе Выборки выбрасывает значения городов неверно, через LIKE, где мне в функции изменить фильтрацию по строгому соответствию.

function CreateSearchCityFilters(SelectQuery, SearchValue) {
    var FiltersGroupCode = 'SearchFilters';
    var Parameters = SelectQuery.Parameters;
    var Table = SelectQuery.Items(0).FromTable;
    var Filters = SelectQuery.Items(0).Filters;
    var FiltersGroup = Filters.ItemsByCode(FiltersGroupCode);
    if (FiltersGroup != null) {
        Filters.Remove(FiltersGroup);
    }
    FiltersGroup = Filters.CreateFilters();
    FiltersGroup.Code = FiltersGroupCode;
    FiltersGroup.LogicalOperator = lotAnd;
    FiltersGroup.IsNot = false;
    //Parameters.ItemsByName('SearchString').Value = Trim(SearchValue);
    var SearchValues = SearchValue.split(' ');
    var IsAddLikeFilter = false;
    for (var i = 0; i < SearchValues.length; i++) {
        var SearchValue = Trim(SearchValues[i]);
        if (IsEmptyValue(SearchValue)) { continue; }
        if (SearchValue.length < 3) { continue; }        
        var LikeParameterName = 'SearchLikeParameter'+i.toString();
        var LikeParameter = Parameters.ItemsByName(LikeParameterName);
        if (LikeParameter == null) {
            LikeParameter = Parameters.CreateItem();
            LikeParameter.Name = LikeParameterName;
            LikeParameter.DataType = pdtUnicodeString;
            Parameters.Add(LikeParameter);
        }    
        LikeParameter.Value = SearchValue;        
        var LikeFilterCode = 'SearchLikeFilter'+i.toString();
        var LikeFilter = Filters.ItemsByCode(LikeFilterCode);
        if (LikeFilter != null) {
            Filters.Remove(LikeFilter);     
        }
        LikeFilter = Filters.CreateLikeFilter();
        LikeFilter.Code = LikeFilterCode;
        var LikeTestExpression = LikeFilter.CreateFieldFilterExpression();
        var LikeValueExpression = LikeFilter.CreateParamFilterExpression();    
        LikeValueExpression.Parameter = LikeParameter;
        LikeTestExpression.Field = Table.Fields.ItemsByName('Name');
        LikeFilter.TestExpression = LikeTestExpression;
        LikeFilter.ValueExpression = LikeValueExpression;    
        LikeFilter.LikeType = ltContain;
        LikeFilter.IsEnabled = true;  
        FiltersGroup.Add(LikeFilter);
        IsAddLikeFilter = true; 
    }
    Filters.Add(FiltersGroup);
    if (IsAddLikeFilter) {
        return FiltersGroupCode;
    } else { return ''; }    
}

Нравится

2 комментария
Лучший ответ

Алексей, почему сразу неверно? В коде написали CreateLikeFilter, вот он и применяется. А у фильтра параметр типа равен ltContain, означающий поиск по вхождению. Эта константа, как и другие, определена в скрипте scr_SysEnums:

// Constants for enum _LikeTypeEnum
ltEqual = 0x00000000;
ltContain = 0x00000001;
ltStartsWith = 0x00000002;
ltEndsWith = 0x00000003;

Попробуйте для начала заменить ltContain на ltEqual.

 

Алексей, почему сразу неверно? В коде написали CreateLikeFilter, вот он и применяется. А у фильтра параметр типа равен ltContain, означающий поиск по вхождению. Эта константа, как и другие, определена в скрипте scr_SysEnums:

// Constants for enum _LikeTypeEnum
ltEqual = 0x00000000;
ltContain = 0x00000001;
ltStartsWith = 0x00000002;
ltEndsWith = 0x00000003;

Попробуйте для начала заменить ltContain на ltEqual.

 

Спасибо, помогли.

Показать все комментарии

Вопрос:

При входе в Terrasoft 3.X под новыми пользователями выдается ошибка открытия конфигурации «Could not convert variant of type (NULL) into type (olestr)»

В чём может быть проблема?

Ответ:

Такое сообщение «Could not convert variant of type (Null) into type (OleStr)» говорит о том, что у пользователя нет доступа на свой контакт и/или контрагент.

Для решения нужно: 

1)       Авторизуйтесь в системе под администратором, перейдите в Администрирование-Пользователи
2)       Кликните правой кнопкой на пользователе, под которым возникает ошибка входа, Перейти к -> Контакт и Перейти к -> Контрагент
3)       На детали «Доступ» к контакту добавьте пользователя, под которым происходит сбой или группу, в которую он входит.
4)       На детали «Доступ» к контрагенту добавьте пользователя, под которым происходит сбой или группу, в которую он входит.
5)       Проверьте корректность авторизации пользователя.

Нравится

Поделиться

0 комментариев
Показать все комментарии