Вопрос

Как быстро сгенерировать код страницы для мобильного приложения

Можно использовать для:

  • Edit
  • Grid
  • Preview

Ответ

Выполнять в консоли браузера эмулятора 

(new Terrasoft.CodeGeneration.PageCodeGenerator({
    modelName: "Contact", 
    pageType: Terrasoft.PageTypes.Edit
})).generate()

В modelName указываем нужный объект

В pageType  указываем тип страницы: 

pageType: Terrasoft.PageTypes.Grid
pageType: Terrasoft.PageTypes.Edit
pageType: Terrasoft.PageTypes.Preview

Изображение удалено.

В итоге получается:

Terrasoft.LastLoadedPageData = {
    controllerName: "Terrasoft.configuration.ContactEditPageController",
    viewXClass: "Terrasoft.configuration.ContactEditPageView"
};
 
Ext.define("Terrasoft.configuration.view.ContactEditPage", {
    extend: "Terrasoft.view.BaseEditPage",
    alternateClassName: "Terrasoft.configuration.ContactEditPageView",
    config: {
        id: "ContactEditPage"
    }
});
 
Ext.define("Terrasoft.configuration.controller.ContactEditPage", {
    extend: "Terrasoft.controller.BaseEditPage",
    alternateClassName: "Terrasoft.configuration.ContactEditPageController",
    statics: {
        Model: Contact
    },
    config: {
        refs: {
            view: "#ContactEditPage"
        }
    }
});

 

Нравится

Поделиться

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

Задача

Необходимо иметь возможность создавать пользователя для сотрудника любой компании с типом "Наша компания" а не только для сотрудников существующей в коробочном решении Нашей компании.

Решение

Необходимо заменить метод PrepareEmployeeEditFilter схемы UserEditPage на следующий:

var filters = e.Filters;
filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.Equal},
    {"leftExpressionColumnPath", "[SysAdminUnit:Contact].Id"},
    {"aggregationType", AggregationTypeStrict.Count},
    {"useDisplayValue", false},
    {"rightExpressionParameterValues", new object[] {0}}});
filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.Equal},
    {"leftExpressionColumnPath", "Account.Type"},
    {"useDisplayValue", false},
    {"rightExpressionParameterValues", new object[] { new Guid("57412fad-53e6-df11-971b-001d60e938c6")}}});
e.ParametersValue.Add("hideButtons", true);

Где "57412fad-53e6-df11-971b-001d60e938c6" - айди таблицы AccountType соответствующий значению "Наша компания".

Необходимые условия

Для версии 7.4

Нравится

Поделиться

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

Симптомы

Bug mobile report:

Type: Terrasoft.SyncException 

Message: В процессе синхронизации произошла ошибка 

Stack trace: 



Type: Terrasoft.FileException 

Message: В процессе записи в файл произошла ошибка 

AdditionalInfo: Имя: BPMonline700/Downloads/6005bfc5-5ea7-42da-82e6-15f5f4c9e80a/счет на оплату #6.pdf

Type: Terrasoft.FileSystemException 

Message: undefined 

AdditionalInfo: Код: undefined 

Data: 4 

Model Name: iPhone8,2 (0x0)

Platform: iOS

Platform Version: 9.2.1

IsOnlineMode: false

UIVersion: 2

ApplicationVersion: 7.7.8

ApplicationMajorVersion: 7.7

ContactId: c41b4784-a414-438c-a846-c5bf418f0056

CultureName: ru-RU

ApplicationRevision: 0

BackgroundSyncMode: 3

WorkplaceCode: DefaultWorkplace

Причина

Данная ошибка возникает из-за того, что в приложении присутствует файл «счет на оплату #6.pdf» (деталь «Файлы и ссылки»), в котором есть спецсимвол «#». В мобильном устройстве на платформе iOS есть ограничения по использованию спецсимволов при передаче запросов/файлов.

Решение

Для исправления необходимо переименовать файл и убрать символ «#». Это можно сделать, например, следующими способами:

- найти прикрепленный файл вручную открывая каждую запись в приложении;

- по ID записи (например, «6005bfc5-5ea7-42da-82e6-15f5f4c9e80a») в БД найти родительский объект, чтобы понять в каком разделе и в какой записи находиться данный файл и также переименовать через БД или на уровне приложения. Для упрощения поиска прикрепил скрипт, который можно выполнить на уровне БД и определить в каком объекте находиться данный файл.  

-- Вхідні параметри - назва та значення стовпчика:
DECLARE @COLUMN_NAME NVarChar(100) = 'Id'
DECLARE @COLUMN_VALUE NVarChar(100) = '6005bfc5-5ea7-42da-82e6-15f5f4c9e80a'
DECLARE @tableName VARCHAR(50)
DECLARE tablesCursor CURSOR LOCAL FORWARD_ONLY STATIC FOR
    -- Запит повертає імена таблиць в БД, у яких є стовпчик @COLUMN_VALUE:
    SELECT table_name = sysobjects.name
    FROM sysobjects
    JOIN syscolumns ON sysobjects.id = syscolumns.id         
    WHERE sysobjects.xtype='U'
    and syscolumns.name = @COLUMN_NAME
OPEN tablesCursor
FETCH NEXT FROM tablesCursor INTO @tableName
WHILE @@FETCH_STATUS = 0
BEGIN  
    -- Якщо в якійсь таблиці є стопчик @COLUMN_NAME зі значенням @COLUMN_VALUE -
    -- вивести ім'я таблиці, запит і кількість рядків у запиті
    EXEC ('DECLARE @recordCount INT;
        DECLARE @quotesChar CHAR = char(39);
        DECLARE @tabChar CHAR = char(9);
        BEGIN TRY
            SET @recordCount =
                (SELECT COUNT(*)
                FROM [' + @tableName + '] where ' + @COLUMN_NAME + ' = ''' + @COLUMN_VALUE + ''')
                IF @recordCount > 0
                    BEGIN                                                 
                        PRINT ''''
                        PRINT ''-- ' + @tableName + ':''
                        PRINT ''     SELECT * FROM ' + @tableName +
                            ' WHERE ' + @COLUMN_NAME +
                            ' = '' + @quotesChar + ''' + @COLUMN_VALUE + ''' + @quotesChar + ''''                                          
                        PRINT ''     -- Кількість рядків у запиті: '' + CAST(@recordCount as VARCHAR(5))
                    END
        END TRY        
        BEGIN CATCH                                   
        END CATCH;                      
    ');
    FETCH NEXT FROM tablesCursor INTO @tableName
END
CLOSE tablesCursor
DEALLOCATE tablesCursor

Необходимые условия и возможные ограничения

Данная ошибка актуальна для iOS (iPhone)

Нравится

Поделиться

0 комментариев
Показать все комментарии
Публикация
//Добавляем в методы
methods: {
    //TODO: Изначальная инициализация
    tabRender: function(tabObject) {
        //TODO
    },
    subscribeForEvents: function() {
        this.on("change:UsrType", this.changeTabsVisibility.bind(this)); //UsrType - поле, по которому будут скрываться вкладки
    },
    changeTabsVisibility: function() {
        var usrType = this.get("UsrType") || {}; //"UsrType" - поле, по которому будут скрываться вкладки
        switch(usrType.value) {
            case "933b3812-4882-484f-9ba7-37b272443f36": //id одного из состояний из поля UsrType
                this.hideTabByName( "Tab98e9ceedTabLabel", true ); //Имя нужной вкладки, в diff выглядит так "name": "Tab98e9ceedTabLabel",
                this.hideTabByName( "Tabc65f2ae2TabLabel", true ); //Имя нужной вкладки. Та, что true будет скрыта
                this.hideTabByName( "Tabfcd67f08TabLabel", false ); //Имя нужной вкладки. Та, что false будет отображаться
                break;
            case "49bbaa75-dfdd-4de5-a2fa-4d9b2ba54b96": //id одного из состояний из поля UsrType
                case "8daf0d76-5522-4444-843d-54f05bae3ad9": //id одного из состояний из поля UsrType
                    this.hideTabByName( "Tabfcd67f08TabLabel", true ); //Имя нужной вкладки
                    this.hideTabByName( "Tabc65f2ae2TabLabel", true ); //Имя нужной вкладки
                    this.hideTabByName( "Tab98e9ceedTabLabel", false ); //Имя нужной вкладки
                    break;
                case "b74416cd-ae95-4e6c-b7f9-fc80dcbcf7af": //id одного из состояний из поля UsrType
                    this.hideTabByName( "Tabfcd67f08TabLabel", true ); //Имя нужной вкладки
                    this.hideTabByName( "Tab98e9ceedTabLabel", true ); //Имя нужной вкладки
                    this.hideTabByName( "Tabc65f2ae2TabLabel", false ); //Имя нужной вкладки
                    break;
                default: //Если состояние не указано
                    this.hideTabByName( "Tabfcd67f08TabLabel", false ); //Имя нужной вкладки
                    this.hideTabByName( "Tab98e9ceedTabLabel", false ); //Имя нужной вкладки
                    this.hideTabByName( "Tabc65f2ae2TabLabel", false ); //Имя нужной вкладки
        }
    },
    init: function() {
        this.callParent(arguments);
        this.subscribeForEvents();
    },
    hideTabByName: function(tabName, isHide){
        var tabsCollection = this.get("TabsCollection");
        if(tabsCollection){
            var tabIndex = tabsCollection.collection.keys.indexOf(tabName);
            var tabsPanelDomElement = document.getElementById("ActivityPageV2TabsTabPanel-tabpanel-items"); // Вместо "ActivityPageV2..." в этой строке подставьте своё)
            if(tabsPanelDomElement){
                tabDomElement = tabsPanelDomElement.querySelector('[data-item-index="'+tabIndex.toString()+'"]');
                if(tabDomElement){
                    if(isHide){
                        tabDomElement.style.display = "none";
                    }else{
                        tabDomElement.style.display = null;
                    }
                }
            }    
        }
    }
},

 

Нравится

Поделиться

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

Вопрос

В каких таблицах базы данных  можно найти связь между Обращением и правами доступа на его чтение?

Ответ

Каждый объект имеет таблицу прав имеющую следующее имя Sys + объект + Right, (для обращения это будет SySCaseRight),в данную таблицу заносятся права с указанием SySAdminUnitId - идентификатор записи SySAdminUnit(таблица пользователей и групп). Таблица содержит поле RecorId - id записи к которой применяются права, Operation - операцию на которую выдаются права и RightLevel - уровень прав.

В SourceId находится Id из таблицы SysEntitySchemaRecRightSource, это источник раздавший права(Владелец, автор, Default)

Значения для RightLevel:

      0 - Deny

      1 - CanRead

      2 - CanEdit

Значения для Operation:

      0 - Чтение

      1 - Изменение

      2 - Удаление

Нравится

Поделиться

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

Симптомы

Не работает "Перейти к справке" ("Online help"). При переходе ошибка:

Изображение удалено.

Например, воспроизведется если переходит к продукту Customer Engagement Centre, который в 7.7., который уже называется просто Customer Centre, поэтому справку и не находит.

Причина

Некорретно прописаны системные настройки "Редакция продукта" ("Product") или "Версия конфигурации" ("Configuration version").

Решение

Для решения необходимо поменять значение в системной настройке «Product» (прописать корректное название используемого продукта).

Изображение удалено.

И убедиться, что в системной настройке «Configuration version» проставлено значение «7.7.0».

Изображение удалено.

Нравится

Поделиться

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

Вопрос

Как поменять местами кнопки? 

Изображение удалено.

Ответ

Данное расположение с версии 7.8 изначально было задумано из-за того, что пользователь случайно («автоматически») удаляет запись.

В данном случае пользователь немного задумается, что именно он нажимает.

Данная функциональность реализована в схеме «GridUtilitiesV2» (пакет «NUI»). Метод называется «checkCanDeleteCallback».

Изображение удалено.Если Вы хотите поменять местами кнопки, то Вам необходимо заместить «BaseSectionV2» и скопировать метод «checkCanDeleteCallback» и поменять местами «Terrasoft.MessageBoxButtons.NO.returnCode» и «Terrasoft.MessageBoxButtons.YES.returnCode».

Нравится

Поделиться

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

Вопрос

Как добавить кнопку в реестр детали для активной строки?

Ответ

Можно реализовать следующим образом:

В скрипте детали в блок diff добавить дополнительные свойства для DataGrid (название и заголовок кнопки приведены в качестве примера):

{
        "operation": "merge",
        "name": "DataGrid",
        "values": {
                "activeRowAction": {"bindTo": "onActiveRowAction"},
                "activeRowActions": [
                        {
                                "className": "Terrasoft.Button",
                                "style":this.Terrasoft.controls.ButtonEnums.style.BLUE,
                                "markerValue": "myButtonAction",
                                "tag": "myAction",
                                "caption": "MyButton"
                        }
                ]
        }
}

После этого при выделении активной строки в детали должна появиться синяя кнопка с заголовком MyButton.

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

Далее в методах той же детали необходимо реализовать метод onActiveRowAction. Данный метод в качестве аргументов принимает тэг кнопки и значение ключевой колонки выделенной строки. Если необходимо получить какие-либо другие значения выделенной строки, можно вызвать метод this.getActiveRow(), который возвращает всю модель выделенной строки:

methods: {
        onActiveRowAction: function(buttonTag, primaryColumnValue) {
                if (buttonTag === "myAction") {
                        // весь код ниже можно убрать, он демонстрирует, что значения
                        // primaryColumnValue и activeRowId равны
                        var activeRow = this.getActiveRow();
                        var activeRowId = activeRow.get("Id");
                        console.log(primaryColumnValue);
                        console.log(activeRowId);
                        // дальше Ваша реализация
                        ...
                }
        },
        ...
}

 

Нравится

Поделиться

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

Вопрос

Установила в мобильном приложении Automatic Synchronization – Only through Wifi. Скажите, с какой периодичностью запускатся автоматическая синхронизация данных?

 Изображение удалено.

Ответ

Каждый раз при сворачивании приложения синхронизация происходит через 30 сек. И если пользователь активирует снова приложение эта синхронизация останавливается.

Примечание. Из-за специфики операционной системы на Iphone, может останавливать все процессы в фоне приблизительно через 3 минуты. Т.е. если синхронизация не успела завершится в фоне – то она по факту не прошла. 

Нравится

Поделиться

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

Вопрос

Пользователь создает визит в мобильном приложении, синхронизируется. Удаляет визит в веб версии.

Пользователь синхронизируется в мобильном приложении, визиты не удаляются. Пользователь делает очистку кэша – визиты удаляются. 

Возможно ли выполнять синхронизацию (чтобы удалялясь записи, уже удаленные в веб-версии) без сброса кэша?

Ответ

В мобильном приложении не реализовано удаление удаленных в десктопе записей. Это объясняется тем, что на сервере по умолчанию не выполняется никакого логирования, соотвественно, мобильное приложение не знает, что произошло удаление. 



Если вы хотите, чтобы удаление происходило, то для нужных вам моделей, например, модели Активности, нужно включить дополнительную опцию в манифесте "IsAdministratedByRights": true. 



Например: 

{
   "SyncOptions": {
      "ModelDataImportConfig": [
         {
            "Name": "Activity",
            "IsAdministratedByRights": true
         }
      ]
   }
}

Этот признак добавляет в синхронизацию дополнительный шаг, в котором отбирается выборка данных с сервера и сравнивается с выборкой данных, которые есть в мобильном приложении. "Лишние" записи удаляются. Время синхронизации увеличится пропорционально объему выборок, которые нужно сравнить (чем больше будет данных, тем дольше будет проходить синхронизация). 

Нравится

Поделиться

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