Вопрос

По поводу изменения доступности кнопки без обновления реестра - подскажите, пожалуйста, где можно посмотреть реализацию сообщений sandbox?

Ответ

Примеров реализации сообщений в нашей системе довольно много. Самым ярким примером могут служить модули BasePageV2 и BaseSectionV2. В этих модулях при инициализации вызывается метод subscribeSandboxEvents(), который выполняет подписку на сообщения sandbox.

Например, в модуле BaseSectionV2 выполняется подписка на сообщение [CardChanged], и когда модуль получает это сообщение, он устанавливает изменённое значение соответствующему атрибуту. Само же сообщение отправляет (публикует) модуль BasePageV2 при вызове метода publishPropertyValueToSection(). В свою очередь, метод publishPropertyValueToSection() вызывается при изменении некоторых атрибутов модели карточки редактирования.

Вы можете поступить похожим образом. Например, в методе init() Вашей карточки редактирования (CasePage) подписаться на изменение поля [ServiceCategory]:

init: function() {
    this.callParent(arguments);
    this.on("change:ServiceCategory", function(model, value) {
        this.publishPropertyValueToSection("CurrentServiceCategory",value);
    }this);
}

Таким образом, при изменении поля [ServiceCategory] карточки новое значение будет записываться в атрибут [CurrentServiceCategory] раздела CaseSection.

После этого в разделе Вы сможете получить значение текущей категории, обратившись к атрибуту [CurrentServiceCategory]:

isEnableButtonColumbus: function() {
    var serviceCategory = this.get("CurrentServiceCategory");
    if (!serviceCategory) {
        // Ваш код
    } else {
        return (serviceCategory.value ===UsrConsts.ServiceCategory.Dynamix);
    }
}

 

Нравится

Поделиться

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

Симптомы

Кейс воспроизведения:

1) открыть задачу в расписании, на детали "Связи" которой заполнен лид, счет, проект и т.д.;

2) перейти по гиперссылке в карточку связанного объекта;

3) открыть вкладку "История" и деталь "Активности";

4) добавить на деталь новую задачу.

В результате получаем ошибку в консоли с сообщением: 

message: Cannot read property 'replaceCls' of null.

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

Причина

Происходит это из-за того, что в ActivitySectionV2 перекрыт метод openCardInChain следующим образом:

openCardInChain: function(config) {
   if (this.isSchedulerDataView() && (config.operation === ConfigurationEnums.CardStateV2.ADD)) {
      var historyStateInfo = this.getHistoryStateInfo();
      if (historyStateInfo.workAreaMode === ConfigurationEnums.WorkAreaMode.COMBINED) {
         this.closeCard();
      }
   }
   return this.callParent(arguments);
},

Этот код присутствует начиная с версии 7.3.0.

Решение

В версии 7.7.0 данное поведение должно быть исправлено.

Для быстрого исправления в конфигурации необходимо заместить схему ActivitySectionV2 и переопределить в ней метод openCardInChain так:

openCardInChain: function(config) {
   if (config.isLinkClick) {
      return false;
   }
   this.saveCardScroll();
   this.scrollCardTop();
   this.showBodyMask();
   var historyState = this.sandbox.publish("GetHistoryState");
   var stateObj = config.stateObj || {
            isSeparateMode: config.isSeparateMode || true,
            schemaName: config.schemaName,
            entitySchemaName: config.entitySchemaName,
            operation: config.action || config.operation,
            primaryColumnValue: config.id,
            valuePairs: config.defaultValues,
            isInChain: true
 };
   this.sandbox.publish("PushHistoryState", {
      hash: historyState.hash.historyState,
      silent: config.silent,
      stateObj: stateObj
   });
   var moduleName = config.moduleName || "CardModuleV2";
   var moduleParams = {
      renderTo: config.renderTo || this.renderTo,
      id: config.moduleId,
      keepAlive: (config.keepAlive !== false)
   };
   var instanceConfig = config.instanceConfig;
   if (instanceConfig) {
      this.Ext.apply(moduleParams, {
         instanceConfig: instanceConfig
 });
   }
   this.sandbox.loadModule(moduleName, moduleParams);
   return true;
}

 

Нравится

Поделиться

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

Вопрос

Как включить автоматическое обновление Dashboard-ов?

Ответ

На данный момент (версия 7.6.Х) на пользовательском уровне автоматическое обновление включить нельзя, но можно использовать для решения этой задачи подписку на сообщения ReloadDashboard, которая есть у всех виджетов панели итогов (dashboard).

Для этого можно создать свой модуль без родительского объекта, например UsrDashboardHelper,

в сообщениях добавить ReloadDashboard (Направление: Публикация, Режим: Адресное).

Код возможной реализации генерации событий может быть следующим:

define("UsrDashboardHelper", ["ext-base", "terrasoft", "sandbox"], function(Ext, Terrasoft, sandbox) {
   var getView = function() {
      var config = {
         id: "UsrDashboardHelper",
         selectors: {
            wrapEl: "#UsrDashboardHelper"
         },
         items: []
      };
      return Ext.create("Terrasoft.Container", config);
   };
   return {
      timerId: 0,
      myTimer: function() {
         console.log("tik");
         sandbox.publish("ReloadDashboard", null, ["SectionModuleV2_UsrAutomobileSectionSectionDashboardDashboardModule"]);
      },
      init: function() {
         console.log("UsrDashboardHelper is on in: " + sandbox.id);
         this.timerId = setInterval(this.myTimer, 30000);
      },
      render: function(renderTo) {
         var view = getView();
         view.render(renderTo);
      },
      destroy: function() {
         console.log("UsrDashboardHelper is off!");
         clearInterval(this.timerId);
      }
   };
});

После создания модуля, его можно добавить как виджет, в настройках "dashboard-а", что приведет к выполнению его кода на странице. Данная его реализация будет обновлять все виджеты на странице, имеющие подписку на событие ReloadDashboard, и находящиеся в песочнице, указанной третьим параметром в методе sandbox.publish(...) каждые 300000 миллисекунды (5 минут).



Id песочницы вашей страницы итогов можно узнать посмотрев значение "sandbox.id",

в методе подписки всех "виджетов" на событие "ReloadDashboard", поставив точку остановки в модуле DashboardModule.js на строке:

 

sandbox.subscribe("ReloadDashboard", this.onReloadDashboard, this, [sandbox.id]);

 

Нравится

Поделиться

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

Вопрос

Можно ли как-то отключить на время все email-уведомления из системы?

Ответ

В базовой версии bpm'online нет возможности отключить уведомления по новым письмам.

Необходимо вносить изменения напрямую в базу sql-запросом. 

В таблице MailboxSyncSettings нужно отключить уведомления 

update MailboxSyncSettings set SendWebsocketNotifications = 'false'

Обратите внимание! В этом случае может возникнуть ситуация, когда новое письмо не будет отображаться на коммуникационной панели. Необходимо будет перейти в другую папку в почте (входящие/исходящие) или обновить страницу браузера.

Нравится

Поделиться

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

Вопрос

Можно ли сделать так, чтобы срок реакции/разрешения считался от момента назначения ответственного? (сейчас он считается от момента регистрации обращения)

Ответ

Расчет дат происходит во время изменения Сервиса в методе onServiceItemChanged() при создании обращения. Вы можете создать метод, который будет обрабатывать изменение ответственного и проводить расчет срока, однако все необходимы поля должны быть уже заполнены(в частности поле Сервис).

Нравится

Поделиться

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

Вопрос

Можно ли убрать эту всплывающую подсказку New ... ?

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

правильно ли я понимаю, что getPreventQuickAddSchemaNames нужно добавлять в конкретные страницы карточек, откуда необходимо исключить добавление новых элементов справочников?



Нельзя ли это исключить один раз в LookupQuickAddMixin ?

Ответ

Если во всем приложении, то можете попробовать перекрыть метод onLookupDataLoaded

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

(код ниже и UsrLookupQuickAddMixin - название пользовательской схемы):

 

define("UsrLookupQuickAddMixin", ["LookupQuickAddMixin"], function() {
    Ext.define("Terrasoft.UsrLookupQuickAddMixin", {
        override: "Terrasoft.LookupQuickAddMixin",
 
        onLookupDataLoaded: Terrasoft.emptyFn
    });
});





и затем подключить модуль в BootstrapModulesV2 (необходимо заместить)

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

 

define("BootstrapModulesV2", ["UsrLookupQuickAddMixin"], function() {
    return {};
});

после этого очистить кэш.

Нравится

Поделиться

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

А как это делать после 7.13, когда нельзя замещать модули?

Владимир, BootstrapModulesV2 замещать как раз можно.

 

Функциональность схемы BootstrapModulesV2, заключается в том, что она загружается сразу при логине. Соответственно в ней можно инициализировать модули логику которых потом можно будет использовать.

 

Это часто используется как замена запрещённому замещению модулей, когда делают свой аналог в схеме с другим названием, замещают им стандартный при помощи override, а затем подключают в BootstrapModulesV2, чтобы доработанная версия грузилась при старте.

 

Ещё один пример этого подхода для доработки стандартных элементов есть тут в нижнем комментарии.

Можно, например, вместо onLookupDataLoaded,  заместить getPreventQuickAddSchemaNames добавим нужные сущности, например Продажи - "Opportunity":

 

define("UsrLookupQuickAddMixin", ["LookupQuickAddMixin"], function() {

    Ext.define("Terrasoft.UsrLookupQuickAddMixin", {

        override: "Terrasoft.LookupQuickAddMixin",

        getPreventQuickAddSchemaNames: function() {

            return ["SysAdminUnit", "VwSysSchemaInfo", "VwQueueSysProcess", "Opportunity"];

        },

    });

});

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

Вопрос

Как отобразить другую колонку в реестре "Контрагенты" в мобильном приложении? Например, колонку "Адрес".

Ответ

Для реализации, так как базовую схему MobileAccountModuleConfig нельзя изменять, то Вам необходимо создать свою схему UsrMobileAccountModuleConfig (в пользовательском пакете создать схему расширения страницы соответствующего раздела. Для этого в разделе [Конфигурация] выбрать Добавить  > Исходный код. Для схемы заполнить свойства[Заголовок], [Название], [Пакет]. В качестве языка для схемы выбрать JavaScript) и подключить ее в манифесте.

"Models": {
"Account": {
"RequiredModels": [
. . .
],
"ModelExtensions": [
. . .
],
"ModelExtensions": [],
            "PagesExtensions": [
                "MobileAccountRecordPageSettingsDefaultWorkplace",
                "MobileAccountGridPageSettingsDefaultWorkplace",
                "MobileAccountActionsSettingsDefaultWorkplace",
                "MobileAccountModuleConfig",
                "UsrMobileAccountModuleConfig"
            ]

В ней прописать такой код:

Terrasoft.sdk.GridPage.setSecondaryColumn("Account", {
    columns: ["Address"],
    convertFunction: function(values) {
        return values.Address;
    }
});

В манифесте для импорта прописать необходимые колонки:

{
            "Name": "Account",
            "SyncColumns": [
                "Address"
            ]
        }

После этого желательно перегенерировать исходный код и скомпилировать конфигурацию.

Для наглядности прикрепил на деталь «Файлы» скриншот и примеры с полным листингом кода.

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

Нравится

Поделиться

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

Вопрос

При нажатии на кнопку "добавить" детали "Продукты в заказе" возникала следующая ошибка.

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

Аналогичная ошибка возникала про попытке добавить "График поставок и оплат" 

Ответ

Проблема в следующем: при попытке добавить продукт предварительно выполняется сохранение страницы, однако по неизвестным причинам был изменен базовый спрвочник "OrderStatus". Во время сохранения выполняется проверка на равенство сумм и код страницы OrderPageV2 пакета Passport отрабатывает некорректно:

validateOrderStatus: function(callback, scope) {
    var result = {
        success: true
    };
    var status = this.get("Status");
    var primaryAmount = this.get("PrimaryAmount");
    var OrderStatus = OrderConfigurationConstants.Order.OrderStatus;
    if (status && (status.value === OrderStatus.InPlanned || status.value === OrderStatus.Canceled)) {
        callback.call(scope || this, result);
        return;
    }
    var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
        rootSchemaName: "SupplyPaymentElement"
    });
    esq.addAggregationSchemaColumn("PrimaryAmountPlan", Terrasoft.AggregationType.SUM,
"PrimaryAmountPlanSum");
    var filters = Terrasoft.createFilterGroup();
    filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
"Order", this.get("Id")));
    filters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
"Type", OrderConfigurationConstants.SupplyPaymentElement.Type.Payment));
    esq.filters = filters;
    esq.getEntityCollection(function(response) {
        if (response.success) {
            var collection = response.collection;
            if (collection.getCount() > 0 && primaryAmount !==
collection.getByIndex(0).get("PrimaryAmountPlanSum")) {
                result.message = this.get("Resources.Strings.ValidateOrderStatus");
                result.success = false;
            }
        } else {
            return;
        }
        callback.call(this, result);
    }, scope);

Инструкция

var status = this.get("Status"); - возвращает undefined

collection.getByIndex(0).get("PrimaryAmountPlanSum"))  - возвращает 0

Из-за это не проходит проверка и выдается предупреждения для статуса "В планах"

Для решения необходимо заместить модуль OrderConfigurationConstant и указать в нем корректные id, тогда код:

if (status && (status.value === OrderStatus.InPlanned || status.value === OrderStatus.Canceled)) {
    callback.call(scope || this, result);
    return;
}

будет выполняться корректно.

 

Нравится

Поделиться

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

Вопрос

Не даёт из активностей удалить участника,

Пишет, что ответственного удалить нельзя, но он НЕ ЯВЛЯЕТСЯ ответственным.

Ответ

-- понижение для не ответственных до учасника
SELECT ac.Id, Title, OwnerId, ap.ParticipantId, ap.Id as ApId FROM Activity ac
LEFT JOIN ActivityParticipant ap on ap.RoleId = '53fc4a92-b0ea-e111-96c4-00165d094c12'
AND ac.Id = ap.ActivityId
WHERE OwnerId <> ap.ParticipantId
--
UPDATE ActivityParticipant SET RoleId = '1a8324e8-a6e1-df11-971b-001d60e938c6'
WHERE Id In (
SELECT ap.Id FROM Activity ac
LEFT JOIN ActivityParticipant ap on ap.RoleId = '53fc4a92-b0ea-e111-96c4-00165d094c12'
AND ac.Id = ap.ActivityId
WHERE OwnerId <> ap.ParticipantId
)
-- повышение ответственных до ответственного
SELECT ac.Id, Title, OwnerId, ap.ParticipantId, ap.Id as AppId, ap.RoleId FROM Activity ac
LEFT JOIN ActivityParticipant ap on ac.Id = ap.ActivityId
WHERE ac.OwnerId = ap.ParticipantId AND
ap.RoleId <> '53fc4a92-b0ea-e111-96c4-00165d094c12'
--
UPDATE ActivityParticipant Set RoleId = '53fc4a92-b0ea-e111-96c4-00165d094c12'
WHERE Id In (
SELECT ap.Id FROM Activity ac
LEFT JOIN ActivityParticipant ap on ac.Id = ap.ActivityId
WHERE ac.OwnerId = ap.ParticipantId AND
ap.RoleId <> '53fc4a92-b0ea-e111-96c4-00165d094c12'
)

 

Нравится

Поделиться

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

Вопрос

В версии 7.7.0.2293 SalesEnterprise + Marketing + CustomerCenter в редактируемом реестре все поля изменяемой записи доступны для изменений. Как можно заблокировать от изменений отдельные поля? 

Ответ

1) Создать деталь с помощью мастера деталей, на закладке страницы вывести хотя бы несколько полей. Сохранить.

2) Зарегистрировать мастером разделов деталь на странице в разделе. Настроить колонки.

3) Для того, чтобы деталь стала редактируемой, добавляем зависимости, миксин, атрибут и мердж грида в блоке дифф как показано в примере ниже:

define("UsrSchema1Detail", ["ConfigurationGrid", "ConfigurationGridGenerator",
"ConfigurationGridUtilities"], function() {
    return {
        entitySchemaName: "UsrTestContactDetail",
        attributes: {
            "IsEditable": {
                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                value: true
            }
        },
        mixins: {
            ConfigurationGridUtilites: "Terrasoft.ConfigurationGridUtilities"
        },
        details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
        diff: /**SCHEMA_DIFF*/[
            {
            "operation": "merge",
            "name": "DataGrid",
            "values": {
               "className": "Terrasoft.ConfigurationGrid",
               "generator": "ConfigurationGridGenerator.generatePartial",
               "generateControlsConfig": {"bindTo": "generatActiveRowControlsConfig"},
               "changeRow": {"bindTo": "changeRow"},
               "unSelectRow": {"bindTo": "unSelectRow"},
               "onGridClick": {"bindTo": "onGridClick"},
               "activeRowActions": [
                  {
                     "className": "Terrasoft.Button",
                     "style": this.Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
                     "tag": "save",
                     "markerValue": "save",
                     "imageConfig": {"bindTo": "Resources.Images.SaveIcon"}
                  },
                  {
                     "className": "Terrasoft.Button",
                     "style": this.Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
                     "tag": "cancel",
                     "markerValue": "cancel",
                     "imageConfig": {"bindTo": "Resources.Images.CancelIcon"}
                  },
                  {
                     "className": "Terrasoft.Button",
                     "style": this.Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
                     "tag": "remove",
                     "markerValue": "remove",
                     "imageConfig": {"bindTo": "Resources.Images.RemoveIcon"}
                  }
               ],
               "initActiveRowKeyMap": {"bindTo": "initActiveRowKeyMap"},
               "activeRowAction": {"bindTo": "onActiveRowAction"},
               "multiSelect": false
            }
         }
        ]/**SCHEMA_DIFF*/,
        methods: {}
    };
});

5) В схеме страницы редактирования детали описываем бизнес-правило по правилам написания бизнес-правил - http://academy.terrasoft.ua/documents/docs/technic/SDK/7.6.0/BlockingFieldByCondition.html

define("UsrUsrTestContactDetail1Page", ["BusinessRuleModule"], function(BusinessRuleModule) {
    return {
        entitySchemaName: "UsrTestContactDetail",
        details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
        diff: /**SCHEMA_DIFF*/[
            {
                "operation": "insert",
                "name": "UsrContact",
                "values": {
                    "layout": {
                        "colSpan": 12,
                        "rowSpan": 1,
                        "column": 0,
                        "row": 0,
                        "layoutName": "Header"
                    },
                    "bindTo": "UsrContact"
                },
                "parentName": "Header",
                "propertyName": "items",
                "index": 0
            },
            {
                "operation": "insert",
                "name": "UsrTestInt1",
                "values": {
                    "layout": {
                        "colSpan": 12,
                        "rowSpan": 1,
                        "column": 12,
                        "row": 0,
                        "layoutName": "Header"
                    },
                    "bindTo": "UsrTestInt1"
                },
                "parentName": "Header",
                "propertyName": "items",
                "index": 1
            },
            {
                "operation": "insert",
                "name": "UsrTestInt2",
                "values": {
                    "layout": {
                        "colSpan": 12,
                        "rowSpan": 1,
                        "column": 0,
                        "row": 1,
                        "layoutName": "Header"
                    },
                    "bindTo": "UsrTestInt2"
                },
                "parentName": "Header",
                "propertyName": "items",
                "index": 2
            },
            {
                "operation": "insert",
                "name": "CreatedBy",
                "values": {
                    "layout": {
                        "colSpan": 12,
                        "rowSpan": 1,
                        "column": 12,
                        "row": 1,
                        "layoutName": "Header"
                    },
                    "bindTo": "CreatedBy"
                },
                "parentName": "Header",
                "propertyName": "items",
                "index": 3
            }
        ]/**SCHEMA_DIFF*/,
        methods: {},
        rules: {
            "UsrTestInt1": {
                "EnabledUsrTestInt1": {
                    "ruleType": BusinessRuleModule.enums.RuleType.BINDPARAMETER,
                    "property": BusinessRuleModule.enums.Property.ENABLED,
                    "conditions": [
                        {
                            "leftExpression": {
                                "type": BusinessRuleModule.enums.ValueType.CONSTANT,
                                "value": true
                            },
                            comparisonType: Terrasoft.ComparisonType.NOT_EQUAL,
                            rightExpression: {
                                type: BusinessRuleModule.enums.ValueType.CONSTANT,
                                value: true
                            }
                        }
                    ]
                }
            }
        }
    };
});

В результате поле заблокировано. Если же деталь существующая, и у нее нет страницы редактирования, то необходимо либо удалить информацию в таблице SysDetail и SysModuleEdit по данной детали, и пересоздать ее мастером деталей, либо страницу редактирования создать и зарегистрировать в таблице SysModuleEdit по аналогии с существующими. Затем написать в схеме страницы редактирования детали необходимый для блокировки код.

Нравится

Поделиться

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