Коллеги, добрый день!

Компания пользователь bpmonline запускает новое направление. Возникла потребность дать доступ на работу в системе аутсорсному сотруднику, работа только в новом направлении. По этой причине нужно настроить отображение разделов и активностей для этого сотрудника таким образом что бы он видел только те продажи, лиды, заказы которые имеют привязку к этому новому направлению. А те что не не имеют и давно живущие в системе - не видеть.

Пока не могу придумать логику как это сделать оптимально.

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

Если раздел продажи - то к "типу продажи" или "поставщику".

Если заказы то к продаже соответсвующей заказу.

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

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

Нравится

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

Денис Королев,

Проще всего это сделать с помощью элемента раздачи прав через бизнес-процесс (выше в комментарии Александра есть ссылка с описанием, как работать с данным элементом).

Если у Вас нет опыта подобной настройки, то сначала можете попробовать настроить нужный процесс и протестировать его на тестовой среде, а потом сам процесс перенесете на рабочую среду.

Всё вышеупомянутое можно регулировать правами доступа на записи в разделах. Включить нового пользователя в специальную группу (вдруг появится второй такой же), а этой группе выдать права на одни записи раздела и не выдать на остальные. При этом нужно учитывать, что новый пользователь тоже входит во «Все пользователи» и этой группе не надо давать права на те записи, которые Вы не хотите, чтобы он видел.

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

Более гибко можно в БП с элементом раздачи прав, стартующим при вставке записи.

А раздачу прав на старые записи в зависимости от значения поля в этом или связанном объекте можно сделать SQL-запросом в базе или тоже запущенным один раз БП.

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

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

Денис Королев,

Проще всего это сделать с помощью элемента раздачи прав через бизнес-процесс (выше в комментарии Александра есть ссылка с описанием, как работать с данным элементом).

Если у Вас нет опыта подобной настройки, то сначала можете попробовать настроить нужный процесс и протестировать его на тестовой среде, а потом сам процесс перенесете на рабочую среду.

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

На прод среде имеется бизнес-процесс в пакете Custom. Я хочу изменить этот процесс, внести его в свой пакет разработки. Что собственно уже сделал на среде разработки. Однако при импорте на тестовую заметил, что этот БП не импортируется, так как такой уже есть в пакете Custom. Есть какие нибудь методы решения такой проблемы? только удаление из Custom на прод перед импортом? Или лучше всё таки новый бп создать?

Нравится

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

Добрый день!

Можно у себя на стенде перетащить БП в свой пакет (сменить пакет у БП), а при установке в прод ставить архивом изменяемые пакеты (включая Custom) через установку приложения (не импорт схемы)

Добрый день!

Можно у себя на стенде перетащить БП в свой пакет (сменить пакет у БП), а при установке в прод ставить архивом изменяемые пакеты (включая Custom) через установку приложения (не импорт схемы)

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

Добрый день!



Почему-то не получается прочитать данные из объекта view:

1) создал view

2) создал объект в системе

3) в БП выбрал "Читать данные" и выбрал созданный объект (видны все колонки)

4) выдается ошибка:



System.InvalidCastException: Specified cast is not valid.

   at Terrasoft.DB.MSSql.MSSqlTypeConverter.DBValueToGuid(Object value)

   at Terrasoft.Core.GuidDataValueType.GetValueForLoad(UserConnection userConnection, Object value)

   at Terrasoft.Core.Entities.EntityColumnValue.LoadValue(Object value)

   at Terrasoft.Core.Entities.EntityColumnValueCollection.ForceLoadColumnValue(String name, Object value)

   at Terrasoft.Core.Entities.Entity.LoadShallow(IDataReader dataReader, Dictionary`2 columnMap)

   at Terrasoft.Core.Entities.EntityCollection.LoadShallow(IDataReader dataReader, Dictionary`2 columnMap, Boolean needClear)

   at Terrasoft.Core.Entities.EntitySchemaQuery.GetEntitySchemaEntityCollection(UserConnection userConnection, IDataReader dataReader)

   at Terrasoft.Core.Entities.EntitySchemaQuery.GetEntityCollection(UserConnection userConnection)

   at Terrasoft.Core.Process.Configuration.ReadDataUserTask.InternalExecute(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessActivity.Execute(ProcessExecutingContext context)



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

Нравится

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

Обычно такое встречается когда в View null попадает в колонку описанную как Guid (уникальный идентификатор), помогает преобразование

CAST(NULL AS UNIQUEIDENTIFIER) AS MIParentId

или

CAST(d.ContactId AS UNIQUEIDENTIFIER) AS MIParentId

 

Добрый день

Тип колонки в объекте View не совпадает с типом колонки представления базы данных.

Проверьте типы, конкретно Guid.

Обычно такое встречается когда в View null попадает в колонку описанную как Guid (уникальный идентификатор), помогает преобразование

CAST(NULL AS UNIQUEIDENTIFIER) AS MIParentId

или

CAST(d.ContactId AS UNIQUEIDENTIFIER) AS MIParentId

 

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

Здравствуйте! Подскажите как можно реализовать обновление карточки мобильного приложения? Кейс следующий делаю апдейт заказа и после обновления полей в success обновлять страницу.

Код примерно следующий:

 

setDiscount: function(config){
		var orderProductRecord = Ext.clone(config.model);
		if(config.discountType==="legal"){
			var discountByContract = config.contract.data.Discount;
			var totalAmount = config.model.data.TotalAmount;
			var discountPrice = this.calculateAmountWithDiscount(totalAmount, discountByContract);
			var totalDiscount = totalAmount-discountPrice;
			orderProductRecord.set("WaDiscountAccount", discountByContract, true);
			orderProductRecord.set("WaTotalDiscount", totalDiscount, true);
			orderProductRecord.save({
				success: function(){
					window.console.log("Update was success");
					Terrasoft.Router.back();
				},
				failure: function(exception) {
					Terrasoft.MessageBox.showMessage(Ext.String.format(Terrasoft.LS.WaErrorExecutionMessage, exception));
				},
				queryConfig: Ext.create('Terrasoft.QueryConfig', {
					modelName: orderProductRecord.self.modelName,
					columns: ["WaDiscountAccount", "WaTotalDiscount"]
				})
			}, this);
		} else if (config.discountType ==="personal") {
			//orderProductRecord.set("WaDiscountContact", config.DiscountContact, true);
		}
	},

 

Нравится

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

См. тут. Возможно, подойдут функции:

markPreviousPagesAsDirty(operationConfig)

Метод отмечает все предыдущие страницы как неактуальные. После возврата к предыдущим страницам для каждой из них вызовется метод refreshDirtyData(), который выполняет повторную загрузку данных или актуализирует данные на основании объекта operationConfig.

refreshPreviousPages(operationConfig, currentPageHistoryItem)

Метод выполняет для всех предыдущих страниц повторную загрузку данных или актуализирует данные на основании operationConfig. Если установлено значение для параметра currentPageHistoryItem, метод выполняет те же действия для предшествующих страниц.

refreshAllPages(operationConfig, excludedPageHistoryItems)

Метод выполняет для всех страниц повторную загрузку данных или актуализирует данные на основании operationConfig. Если установлен параметр excludedPageHistoryItems, метод исключает из актуализации указанные страницы.

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

Добрый день! 

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

 

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

В БД ничего похожего найти не смог 

Есть какие-нибудь идеи по удалению процесса?



Сам процесс перестал открываться, выбрасывает из конфигуратора на стандартную страницу ошибки

Нравится

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

Здравствуйте, если я добавлю к контакту некоторое булево поле, как при выборе его из обращения произвести отбор по этому полю?

 

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

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

Нравится

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

Rinat,

Добрый день!

Данную фильтрацию можно сделать

1. либо через бизнес правила:

1) через код https://academy.terrasoft.ru/documents/technic-sdk/7-13/primer-primenen…

2) через мастер страницы (https://monosnap.com/file/ooYS71HNPA5gozrb204C1N5gCvCNeU)

2. либо в коде через параметр фильтрации атрибута

пример:

attributes: {
			"Contact": {
				lookupListConfig: {
					"filters": [
                        function() {
                            var filterGroup = Ext.create("Terrasoft.FilterGroup");
                            var galochaFilter = Terrasoft.createColumnFilterWithParameter(
                            	Terrasoft.ComparisonType.NOT_EQUAL, "Galocka", true);
                            filterGroup.add("filter1", galochaFilter);
                            return filterGroup;
                        }
                    ]
				}
 
			}
		}

 

Ринат, здравствуйте!

На вашем втором скриншоте есть выпадающий список (там где "ФИО") в этом списке должно будет появиться добавленное поле. 

Так же через, по второму скриншоту, нажав на "Вид" Вы сможете вывести колонку в реестр модального окна

Гриценко Игорь, а как сделать чтобы он по умолчанию этот отбор применял и пользователю не пришлось руками этот отбор вбивать. Делаю что-то на подобии "неактивных" пользователей.

Rinat,

Добрый день!

Данную фильтрацию можно сделать

1. либо через бизнес правила:

1) через код https://academy.terrasoft.ru/documents/technic-sdk/7-13/primer-primenen…

2) через мастер страницы (https://monosnap.com/file/ooYS71HNPA5gozrb204C1N5gCvCNeU)

2. либо в коде через параметр фильтрации атрибута

пример:

attributes: {
			"Contact": {
				lookupListConfig: {
					"filters": [
                        function() {
                            var filterGroup = Ext.create("Terrasoft.FilterGroup");
                            var galochaFilter = Terrasoft.createColumnFilterWithParameter(
                            	Terrasoft.ComparisonType.NOT_EQUAL, "Galocka", true);
                            filterGroup.add("filter1", galochaFilter);
                            return filterGroup;
                        }
                    ]
				}
 
			}
		}

 

Сидоров Александр В., не совсем понял как в мастер страницы попасть. Это не оно? 

Rinat,

Да, оно. Справа сверху есть кнопка перехода к бизнес правилам

Сидоров Александр В.,Спасибо.

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

Всем доброго времени суток!

Подскажите как можно передать в карточку редактирования нового заказа некоторых параметров - http://prntscr.com/n0jpjt ?

Для открытия карточки редактирования использую:

 

var config = {
			isStartRecord: true,
			pageSchemaName: "MobileOrderEditPage"
		};
		Terrasoft.util.openEditPage("Order", config);

 

Нравится

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

См. в MobilePhoneCallLogPage:

 onSaveButtonButtonTap: function() {
  var modelConfig = Terrasoft.ApplicationConfig.getModelConfig("Activity");
  var requiredModels = modelConfig.RequiredModels;
  Terrasoft.StructureLoader.loadModels({
   modelNames: requiredModels,
   success: function() {
    this.createCallActivity(function() {
     var arrangeActivityToggle = this.getArrangeActivityToggle();
     var toArrange = arrangeActivityToggle.getValue();
     var record = this.record;
     this.back();
     if (toArrange) {
      setTimeout(function() {
       var config = {
        defaultRecordData: {}
       };
       if (Ext.isString(this.activityLinkColumnNames)) {
        config.defaultRecordData[this.activityLinkColumnNames] = record;
       } else {
        for (var i = 0, ln = this.activityLinkColumnNames.length; i < ln; i++) {
         var linkColumnNameConfig = this.activityLinkColumnNames[i];
         var columnName = linkColumnNameConfig.activityColumnName;
         var columnValue = record.get(linkColumnNameConfig.parentColumnName);
         config.defaultRecordData[columnName] = columnValue;
        }
       }
       Terrasoft.util.openEditPage("Activity", config);
      }.bind(this), 500);
     }
    }.bind(this));
   },
   scope: this
  });
 },

 

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

Раздел создан сторонним пользователем

ошибка вылетает в методе, когда он пытается обратиться к элементу name контейнера в файле all-combined.js

needFlatten: function(e, t) {
        var a = t || !1;
        return (a = !Ext.isEmpty(e.name)) || (Ext.isArray(e) && e.length > 0 ? a = !Ext.isEmpty(e[0].name) : Ext.isObject(e) && Terrasoft.each(e, function(e) {
            a = this.needFlatten(e, a)
        }, this)),
        a
    },

трэйс начинается условно от ViewModelSchemaValidationMixin.js в методе getSchemaDuplicates 

здесь соотвественно всё останавливается на методе Terrasoft.JsonDiffer.getFlatObject

getSchemaDuplicates: function(schema) {
				const viewConfig = schema.viewConfig;
				const messageConfig = {};
				const result = [];
				const pathDelimiter = Terrasoft.JsonDiffer.pathDelimiter;
				const flatViewConfig = Terrasoft.JsonDiffer.getFlatObject(viewConfig, {identifyItemByPath: true});
				Object.keys(flatViewConfig).forEach(function(path) {
					const name = path.split(pathDelimiter).pop();
					const formattedPath = path.split(pathDelimiter).join(".");
					const diffObject = flatViewConfig[path];
					const caption = diffObject.caption ||
						(diffObject.labelConfig && diffObject.labelConfig.caption) ||
						"";
					messageConfig[name] = messageConfig[name] || [];
					messageConfig[name].push({
						path: formattedPath,
						caption: caption
					});
				});
				Object.keys(messageConfig).forEach(function(name) {
					if (messageConfig[name].length > 1) {
						result.push({
							name: name,
							items: messageConfig[name]
						});
					}
				});
				return result;
			},

В чем может быть причина? И буду рад советами по отладке такого клиентского кода, когда я пытался в all-combined.js ставить брэйкпоинты, у меня словно всё зависало просто

Нравится

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

Посмотрите тут и тут

Григорий Чех,

ни та ни та причина. причина оказалась в свойстве

"contentType": Terrasoft.ContentType.DROPDOWN

после того, как закомментировал его, всё заработало. Только теперь я не могу найти что это за свойство и какие значения оно может принимать помимо DROPDOWN и есть ли вообще у него такое значение?

{
	"operation": "insert",
	"name": "ITExecutor",
	"values": {
		"enabled": false,
		"layout": {
			"contentType": Terrasoft.ContentType.DROPDOWN,
			"colSpan": 12,
			"rowSpan": 1,
			"column": 12,
			"row": 0,
			"layoutName": "Header"
				  },
		"bindTo": "ITExecutor"
				},
	"parentName": "Header",
	"propertyName": "items",
	"index": 1
}

 

Григорий Чех,

разобрался. свойство "contentType" должно находится внутри "values", а не "layout"

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

Всем доброго времени суток!

Есть задача при изменении кол-ва продуктов или же изменении продукта в детали Продукт в заказе просчитывать Amount и TotalAmount. Реализую данную задачу через пользовательское бизнес правило:

 

Terrasoft.sdk.Model.addBusinessRule("OrderProduct", {
	name: "WaOrderProductAmountValidatorRule",
	ruleType: Terrasoft.RuleTypes.Custom,
	triggeredByColumns: ["Quantity", "Product"],
	events: [Terrasoft.BusinessRuleEvents.ValueChanged, Terrasoft.BusinessRuleEvents.Save],
	executeFn: function(model, rule, column, customData, callbackConfig) {
		window.console.info(model);
		debugger;
		var product = model.get("Product");
		if ((!product) || Ext.isEmpty(product)) {
			model.set("Price", 0, true);
			model.set("TotalAmount", 0, true);
			model.set("Amount", 0, true);
		} else {
			var quantity = model.get("Quantity");
			var price = product.get("Price");
			var amount = quantity * price;
			model.set("Amount", amount, true);
			model.set("TotalAmount", amount, true);
		}
		Ext.callback(callbackConfig.success, callbackConfig.scope);
	}
});

Но почему то значение цены продукта возвращает null:

 

{
	"modified":{
		"Id":"fbfb2d62-4439-486b-ae2f-b360f9e899f8"
	},
	"raw":{},
	"stores":[],
	"data":{
		"Id":"1fd85496-4cc0-485c-ad37-bb91857e65df",
		"Name":"Гидрогелевая маска для лица WOW Mask",
		"ProcessListeners":null,
		"Price":null,
		"Active":false,
		"IsArchive":false
	},
	"_data":{
		"Id":"1fd85496-4cc0-485c-ad37-bb91857e65df",
		"Name":"Гидрогелевая маска для лица WOW Mask",
		"ProcessListeners":null,
		"Price":null,
		"Active":false,
		"IsArchive":false
	},
	"id":"fbfb2d62-4439-486b-ae2f-b360f9e899f8",
	"internalId":"fbfb2d62-4439-486b-ae2f-b360f9e899f8",
	"phantom":true,
	"dirty":true
}

Хотя значение цены есть - http://prntscr.com/my9x2o

Нравится

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

Нигрескул Алексей,

Такое происходит из-за того, что в конфиг запроса для справочной колонки никоим образом не была добавлена нужная колонка. Можно в явном виде добавить таким кодом где-нибудь в ModuleConfig:

    var additionalProductColumns = ["Price", /*прочие колонки*/];
    var productQueryConfig = Terrasoft.sdk.LookupGridPage.getQueryConfig("Product");
    Terrasoft.sdk.LookupGridPage.updateQueryConfigColumns(null, {columns: additionalProductColumns}, productQueryConfig);

Либо можно для converFuction первичной или вторичной колонки добавить её в LookupGridPage.

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

var controller = Terrasoft.app.getControllerInstances()["MyController"];
//Можно задебажиться и посмотреть, какие экземпляры контроллеров есть, среди них должен быть нужный
var control = controller.getFieldByName("MyColumn", record);
control.setValue(value);

Или ещё вариант:

var control = Ext.getCmp("{ViewId}_{PageType}_{ColumnName}_Column");
// {ViewId} - id представления, {PageType} - тип страницы Edit или Preview, {ColumnName} - название колонки, например AccountPage_Edit_AlternativeName_Column
control.setValue(value);

 

Бершеда Д. Н.,

 Здравствуйте! Я настроил кастомное правило и все хорошо изменяется, в данном случае сумма в зависимости от цены и кол-ва товаров. Вопрос в другом, не видит значение цены продукта, вот пример:

Есть заказ с продуктами -

http://prntscr.com/mz1088, меняю кол- во продукта срабатывает правило - http://prntscr.com/mz10kr

Мне возвращает цену продукта null - http://prntscr.com/mz10vd

Почему так происходит? В манифест зависимости добавил.

Нигрескул Алексей,

Такое происходит из-за того, что в конфиг запроса для справочной колонки никоим образом не была добавлена нужная колонка. Можно в явном виде добавить таким кодом где-нибудь в ModuleConfig:

    var additionalProductColumns = ["Price", /*прочие колонки*/];
    var productQueryConfig = Terrasoft.sdk.LookupGridPage.getQueryConfig("Product");
    Terrasoft.sdk.LookupGridPage.updateQueryConfigColumns(null, {columns: additionalProductColumns}, productQueryConfig);

Либо можно для converFuction первичной или вторичной колонки добавить её в LookupGridPage.

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

Добрый день!

На главной странице портала по умолчанию есть два модуля в панели итогов, "Мои обращения" и "Популярные статьи".

Написал новый модуль по аналогии с Мои обращения - "Мои проблемы".

Он точно также как и обращения должен отображать номер и тему.

Добавил его на панель итогов. При открытии панели возникает ошибка в браузере, а на месте дашборда пусто:

Message GetSectionFilterModuleId is not defined in UsrProblemListModule (PortalMainPageModule_DashboardModuleModuledc874fc63a3cUsrProblemListModule) module 

 date: Thu Mar 14 2019 15:31:45 GMT+0300 (Москва, стандартное время)

 moduleId: PortalMainPageModule_DashboardModuleModuledc874fc63a3cUsrProblemListModule

 moduleName: UsrProblemListModule

 

Есть какая-то документация по разработке такого решения? Или ваши примеры кода. Спасибо.

 

Нравится

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

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

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