Вопрос

У клиента проблема с поиском дублей Контактов. Дубли система находит, карточку дублей открывает, а вот по нажатию кнопки «Сохранить» ничего не происходит.

Ответ

Проблема в том, что пользователь заместил объект «Contact» и поставил у него обязательным к заполнению поле «Email».

Если настройку снять, объединение дублей проходит без проблем.

Если же пользователю нужно будет запретить пользователям оставлять поле e-mail незаполненным, не повредив при этом базовую функциональность, это следует делать с помощью бизнес правил:

https://academy.terrasoft.ru/documents/technic-sdk/7-6/nastroyka-poley-stranicy-redaktirovaniya-s-pomoshchyu-biznes-pravil

 

Нравится

Поделиться

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

Вопрос

Построитель запросов при обращении с портала к таблице ServiceEngineer подставляет таблицу SysEmpty. вместо Service Engeneer. Запрос формируется в сервисе PortalCasePage.

Ответ

Для того, чтобы отрабатывали запросы к определенному объекту на портале, после включения прав для портальных пользователей, необходимо выполнить следующий скрипт:

insert into SysSSPEntitySchemaAccessList (EntitySchemaUId) values ('XXX')

где ХХХ – значение из колонки UId таблицы SysSchema, объекта «Сервисный инженер» в кастомном пакете.

Нравится

Поделиться

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

Вопрос

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

При конфигурировании настроек страницы раздела, можно добавлять колонки. Имеется ли возможность добавить не колонку, просто строку с фиксированной надписью (label).

Ответ

Вам необходимо в конфигураторе, в схеме страницы вашего раздела добавить локализируемую строку и следующий код в блоке diff:

{
    "operation": "insert",
    "name": "UsrTestLabel",
    "values": {
        "layout": {
            "column": 12,
            "row": 0,
            "colSpan": 12,
            "rowSpan": 1
        },
        "itemType": Terrasoft.ViewItemType.LABEL,
        "caption": {
            "bindTo": "Resources.Strings.UsrTestLabelString"
        }
    },
    "parentName": "Header",
    "propertyName": "items"
},

Блок "layout" описывает положение и размер элемента на сетке.

Нравится

Поделиться

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

Симптомы

При установке bpm'online mobile 7 для Windows 10 ошибка "The error code is 0x803F7000"

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

Причина

Ошибка связана с локальными настройками Windows 10.

Причины ошибки:

  • Windows Store Cache.
  • Неверные данные и время.
  • Окна не активировали.
  • Microsoft Сервер перегружен.

Решение

Ссылки, в которых описана причина и решение данной проблемы:

-      http://answers.microsoft.com/en-us/windows/forum/windows_10-win_upgrade/error-code-0x803f7000-in-windows-store-10/18f61f6f-009a-435f-8d33-6956e301a849?auth=1

-      http://www.fixerrs.com/2015/09/fix-error-0x803f7000-windows-10-store.html

-      http://errortools.com/windows/how-to-fix-windows-10-error-code-0x803f7000/

-      http://microsoftfixnow.com/error-code-0x803f7000-windows-10-while-accessing-windows-store/

Нравится

Поделиться

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

Задача

Есть некий объект – положим, контрагент, у которого есть параметр 1, параметр 2, параметр 3. 

У этого объекта есть деталь, в которой отображаются записи этого же типа объекта, например, контрагенты, у которых выполняется условие «параметр 1 + параметр 2 соответствуют основной записи», «параметр 2 + параметр 3 соответствуют основной записи», «параметр 1 + параметр 3 соответствуют основной записи».

В детали можно фильтровать по нескольким колонкам. Но как сделать UNION,  т.е. «просуммировать» несколько таких независимых наборов фильтров? 

Решение

Допустим есть наполнение таблицы контрагент:

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

Следовательно, по выше написанному наполнение карточки и детали будет следующим:

1) Первый вариант наполнения детали;

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

2) Второй вариант наполнения детали. Возможно, имелось в виду объединение значений, тогда деталь и карточка будет такой:

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

«В детали можно фильтровать по нескольким колонкам. Но вот как сделать UNION,  т.е. «просуммировать» несколько таких независимых наборов фильтров?»

Если имелся в виду первый вариант наполнения детали, то filterGroup в методе фильтрации на карточке будет выглядеть следующим образом:

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

Если имелся в виду второй вариант наполнения детали, то filterGroup в методе фильтрации на карточке будет выглядеть следующим образом:

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

Также ошибка в добалении групп – не указаны их ключи. Правильное добавление групп:

filterGroup.add(1”, filterGroup1);
filterGroup.add(2”, filterGroup2);
filterGroup.add(3”, filterGroup3);

                                                           

Нравится

Поделиться

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

Вопрос

У нас в энтерпрайз есть в моб приложении чек-ин и чек-аут. Снимает время и координаты.

После попадания в основную систему, где можно их увидеть?

Ответ

К сожалению, в базовой версии продукта эти данные не отображаются.

Найти эти данные можно в таблице БД, которая называется CheckInOutResult.

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

Информацию о визите на  мы храним локально на устройстве и затем при синхронизации передаем ее.

Получение данных при чекине (схема «FieldForceMobileUtilitiesV2»):

checkInOut: function(activityId, isCheckIn) {
    Terrasoft.Geolocation.getCurrentCoordinates({
        success: function(latitude, longitude) {
            var checkinResultModelName = "CheckInOutResult";
            var saveQueryConfig = Ext.create("Terrasoft.QueryConfig", {
                modelName: checkinResultModelName,
                columns: ["GpsX", "GpsY", "Activity", "IsCheckIn", "ActionTime"]
            });
            var checkInOutRecord = Ext.create("CheckInOutResult", {
                Activity: activityId,
                GpsX: String(latitude),
                GpsY: String(longitude),
                IsCheckIn: isCheckIn,
                ActionTime: new Date()
            });
            checkInOutRecord.save({
                queryConfig: saveQueryConfig,
                success: function() {
                    this.changeActivityStatusByCheckInOut(isCheckIn);
                },
                failure: this.failureHandler
            }, this);
        },
        failure: this.failureHandler,
        scope: this
    });
},
 

Получение текущих координат описано в схеме «FieldForceMapsModule»

Также, координаты, которые получает bpm'online, можно управлять. Приведу пример текущей реализации метода «Terrasoft.Geolocation.getCurrentCoordinates»:

getCurrentCoordinates: function(config) {
   var enableHighAccuracy = !Terrasoft.Connection.isOnline() ||
      Terrasoft.Connection.getType() !== Terrasoft.ConnectionTypes.WiFi;
   var geo = Ext.create("Ext.util.Geolocation", {
      autoUpdate: false,
      allowHighAccuracy: enableHighAccuracy,
      timeout: 60000,
      listeners: {
         scope: this,
         locationupdate: function(geo) {
            Ext.callback(config.success, config.scope, [geo.getLatitude(), geo.getLongitude()]);
         },
         locationerror: function(geo, timeout, permissionDenied, locationUnavailable, message) {
            …
         }
      }
   });
   geo.updateLocation();
}

Сейчас, если нет интернет-соединения или это соединение – не WiFi (типа, EDGE, 3G), то будет использоваться «точное» позиционирование (с использованием GPS), иначе данные будут получены с использованием WiFi, кеширования и т.д., т.е. способами дающими неточные представления о местоположении устройства, но вполне достаточные для выполнения бизнес-задач.

Если нужно получать данные с использованием GPS, можно создать свою реализацию действия, по аналогии с тем, как это реализовано в bpm'online:

getCurrentCoordinates: function(config) {
   var geo = Ext.create("Ext.util.Geolocation", {
      autoUpdate: false,
      allowHighAccuracy: true,
      timeout: 60000,
      listeners: {
         scope: this,
         locationupdate: function(geo) {
            Ext.callback(config.success, config.scope, [geo.getLatitude(), geo.getLongitude()]);
         },
         locationerror: function(geo, timeout, permissionDenied, locationUnavailable, message) {
            …
         }
      }
   });
   geo.updateLocation();
}

При реализации нужно учитывать, что у такого способа есть ряд проблем:

- несмотря, что метод GPS более точен, время получения таких данных может быть достаточно больших (до 10-15 минут);

- соответсвенно время ожидания получения ответа нужно увеличить, т.е. параметр timeout выше в коде нужно будет устанавливать больше, чем 1 минуту (60000 мс);

- любые перекрытия, помехи в виде любых объектов могут не позволить получить координаты (например, у нас в офисе это нереально);

- быстрее садится батарея, что для Android-устройств весьма критично.

Нравится

Поделиться

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

Вопрос

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

Ответ

У пользователя в таблице БД не заполнено поле CreatedById, для решение проблемы поле было дозаполнено, создателем был выставлен Supervisor:

Update Account --необходимо изменить объект
SET CreatedById = (SELECT id FROM Contact c WHERE c.Name = 'Supervisor')
where CreatedById is null;

 

Нравится

Поделиться

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

Симптомы

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

После запуска синхронизации возникает ошибка:

Bpm'online mobile bug report

Type: Terrasoft.ODataException 

Message: An error occurred while processing this request. 

Сообщение содержит: Невозможно получить значение колонки Data, так как она не была загружена

Причина

В процессе схемы File в скрипте ScriptFileSaving есть код:

var data = Entity.GetColumnValue("Data") as byte[];

И если обновлять данные в этой схеме (через OData) и не указывать колонку Data, то появляется сообщение, что она не загружена.

Такая ситуация может происходить если в таблице файлов (ActivityFile, OpportunityFile и т.п.) есть циклическая связь.

Например в таблице ActivityFile есть колонка Activity, которая ссылается на таблицу Activity, в которой, в свою очередь, есть справочная колонка UsrActivityFile, которая ссылается на таблицу ActivityFile.

Мобильное приложение это отслеживает и разбивает один запрос

 

INSERT INTO ActivityFile (Id, Name, Data, Activity) VALUES (1, 2, 3, 4)

На два запроса:

INSERT INTO ActivityFile (Id, Name, Data) VALUES (1, 2, 3)
UPDATE ActivityFile SET Activity = 4 WHERE Id = 1

Вот этот второй запрос и не срабатывает.

Решение

Есть обходное решение. Для требуемой таблицы в манифесте установить признак IgnoreSplitLogActions

{
   "SyncOptions": {
      "ModelDataExportConfig": [
         {
            "Name": "ActivityFile",
            "IgnoreSplitLogActions": true
         }
      ],

Тогда вставка файла не будет разбиваться на два запроса.

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

Для UIV1 необходимо дополнительно "заоверрайдить" схему:

if (!Terrasoft.SysSettingsValue.getBooleanValue("UseMobileUIV2")) {
    /*
     * Moved from UIV2
     */
    Ext.define("Terrasoft.Sync.LogManager.override", {
        override: "Terrasoft.Sync.LogManager",
        /**
         * @private
         */
        ignoreSplitLogActions: function(logAction) {
            var modelName = logAction.get("ModelName");
            var manifest = Terrasoft.ApplicationConfig.manifest;
            var ignore = false;
            if (manifest.SyncOptions) {
                var modelDataExportConfig = manifest.SyncOptions.ModelDataExportConfig || [];
                for (var i = 0, ln = modelDataExportConfig.length; i < ln; i++) {
                    var modelConfig = modelDataExportConfig[i];
                    if (Ext.isObject(modelConfig) && modelConfig.Name === modelName) {
                        ignore = modelConfig.IgnoreSplitLogActions;
                        break;
                    }
                }
            }
            return ignore === true;
        },
        /**
         * @private
         */
        splitLogActions: function() {
            var firstTierActions = this.firstTierActions = [];
            var secondTierActions = this.secondTierActions = [];
            for (var i = 0, ln = this.mergedLogActions.length; i < ln; i++) {
                var logAction = this.mergedLogActions[i];
                if (this.isCreateAction(logAction) && !this.ignoreSplitLogActions(logAction)) {
                    firstTierActions.push(logAction);
                    this.splitLogActionWithLoopColumns(logAction);
                    this.splitLogActionWithBinaryColumns(logAction);
                } else {
                    secondTierActions.push(logAction);
                    if (this.isUpdateAction(logAction)) {
                        this.splitLogActionWithBinaryColumns(logAction);
                    }
                }
            }
        }
    });
}

 

Нравится

Поделиться

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

Вопрос

Веб-сервис без авторизации для вызова БП (Бизнесс процесса) с параметрами.

Ответ

Инструкция по написанию сервиса, вызывающего БП, доступного по HTTP\GET с передачей параметров в БП:  https://community.terrasoft.ru/articles/veb-servis-dostupnyi-bez-avtorizacii-cors

Сервис:

namespace Terrasoft.Configuration
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using System.Linq;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.ServiceModel.Activation;
    using System.Web;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Drawing;
    using System.Globalization;
    using System.Net;
    using System.Text;
    using System.IO;
 
    using Terrasoft.Core;
    using Terrasoft.Core.Configuration;
    using Terrasoft.Core.DB;
    using Terrasoft.Core.Entities;
    using Terrasoft.Core.Process;
    using Terrasoft.Web.Common;
    using Terrasoft.Common;
    using Terrasoft.Common.Json;
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class UsrLaunchProccService : BaseService
    {
        private UserConnection SystemUserConnection {
            get {
                return AppConnection.SystemUserConnection;
            }
        }
 
        public ProcessSchemaManager ProcessSchemaManager {
            get {
                return (ProcessSchemaManager)SystemUserConnection.GetSchemaManager("ProcessSchemaManager");
            }
        }
 
        [OperationContract]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json, UriTemplate = "runUsrTestProcc/{ustTestPhone}/")]
        public string runUsrTestProcc(string ustTestPhone)
        {
            ///////
            var currentWebOperationContext = WebOperationContext.Current;
            var outgoingResponseHeaders = currentWebOperationContext.OutgoingResponse.Headers;
            var incomingRequestOrigin = currentWebOperationContext.IncomingRequest.Headers["Origin"];
            outgoingResponseHeaders.Add("Access-Control-Allow-Origin", incomingRequestOrigin);
            ///////
            var result = "";
            try {
                var UserConnection = this.SystemUserConnection;
 
                var manager = UserConnection.ProcessSchemaManager;
                var processSchema = manager.GetInstanceByName("UsrTestProcc");
                var process = processSchema.CreateProcess(UserConnection);
                if (processSchema.Parameters.ExistsByName("UstTestPhone"))
                {
                process.SetPropertyValue("UstTestPhone", ustTestPhone);
                }
                process.Execute(UserConnection);
                result = "OK for ustTestPhone = " + ustTestPhone;
            } catch (Exception ex) {
                result = ex.Message;
            };
            return result;
        }
 
 
        [OperationContract]
        [WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
        public void GetWebFormLeadDataRequestOptions() {
            var outgoingResponseHeaders = WebOperationContext.Current.OutgoingResponse.Headers;
            outgoingResponseHeaders.Add("Access-Control-Allow-Origin", "*");
            outgoingResponseHeaders.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
            outgoingResponseHeaders.Add("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, X-Requested-With, X-Requested-With, x-request-source");
            outgoingResponseHeaders.Add("Access-Control-Request-Headers", "X-Requested-With, x-request-source, accept, content-type");
        }
    }
}

 

Нравится

Поделиться

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

Вопрос

Мы обнаружили, что пользователей системы можно создать только для контактов, у которых в поле контрагент указана "Наша компания". Однако ввиду специфики оргструктуры организации клиента нам необходимо, чтобы была возможность создавать пользователей для контактов, контрагент которого является, допустим, дочерним для "Нашей компании". Есть ли возможность включить таких контактов в список сотрудников, который выдается при создании пользователя?

Ответ

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

Логика фильтра в поле «Сотрудник» карточки пользователя задаётся в функции «PrepareEmployeeEditFilter» страницы «UserEditPage».

Вы можете модифицировать (или вообще отключить) фильтры, ограничивающие выбор контакта.

Нравится

Поделиться

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