Вопрос

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

У меня такой же вопрос

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

Это определяется атрибутом CommentsVisible в схеме SocialMessageHistoryItemPageV2:

 * Comments block visibility attribute.
 */
"CommentsVisible": {
	"dataValueType": this.Terrasoft.DataValueType.BOOLEAN,
	"type": this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
	"value": false
},

И его состояние считывает и инвертирует та самая ссылка-переключатель «Комментарии (1)»:

/**
 * Toggle comments block visibility and load first portion of comments if it is visible and empty.
 * @protected
 */
toggleCommentsVisibility: function() {
	if (this.get("CommentCount") < 1) {
		return;
	}
	var newVisibilityState = !this.get("CommentsVisible");
	this.set("CommentsVisible", newVisibilityState);
	if (newVisibilityState && this.get("ShownCommentMessagesCount") === 0) {
		this.onLoadNextComment();
	}
},

Нужно смотреть и экспериментировать, достаточно ли поменять атрибут на true, или нужно будет при открытии ещё принудительно вызывать логику загрузки комментариев.

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

При слияние дублей в разделе Контакты у администратора, выполнявшим слияние, в учетной записи поменялся контакт на лицо из дубля. Контакт админа удалился.
В результате имеем двух пользователей, синхронизированных LDAP, но с единым контактом.
Какой нужно выполнить запрос в поднятый бэкап БД для дедубликации или есть ещё какой либо способ. Откат не желателен.

У меня такой же вопрос

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

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

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

Здравствуйте! Подскажите, а как добавить в фильтры серверного EntitySchemaQuery подзапрос или где в системе можно найти пример? На SQL запрос выглядит следующим образом:

SELECT
   * 
FROM
   [Contract] 
WHERE
   StartDate = (
        SELECT MAX(c.StartDate)
        FROM Premises p
        JOIN PremisesInContract pic ON p.Id = pic.PremisesId
        JOIN Contract c ON spic.ContractId = c.Id
        WHERE p.Id = --@someparameter
   )

 

У меня такой же вопрос

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

Добрый день, похожая ситуация обсуждалась тут https://community.terrasoft.ru/questions/ispolzovanie-kollekcii-v-select

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

Добрый день!

Интересует вопрос:

1) как достать тело письма и "засунуть" его в текстовое поле (как это делает базовые процессы), немного не понимаю процесс (в теле активности текст в html коде)

2) как забирать из письма вложения и добавлять их к вложениям другого объекта?

У меня такой же вопрос

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

Логика создания инцидента по письму реализована в БП IncidentRegistrationFromEmailProcess, его функции RegisterIncidentFromEmail. Там обращаются к вспомогательной схеме IncidentRegistrationFromEmaillHelper. В ней и сделано: функция CreateNewCaseByEmail создаёт запись и наполняет поля, функция ClearHtmlText превращает содержимое тела письма из HTML в текст.

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

А базовой логики переноса файлов не реализовано?

См. UploadAttachmentsData в ExchangeUtility.

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

Стартовым сигналом в  БП IncidentRegistrationFromEmailProcess является FinishedSyncSession и если я меняю его на простую активность(письмо) то все рушится. Как в этом плане лучше реализовать регистрацию обращения по письму, не изобретая велосипед. Ведь есть уже практически готовый код, но не могу понять как его переделать.

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

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

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

Необходимо добавить маску загрузки на страницу редактирования.

Пробовал разными способами.

this.showBodyMask();

также пробовал в зависимости карточки добавлять MaskHelper, и далее в коде вызывать MaskHelper.ShowBodyMask() - не срабатывает
 

так же пробовал следующим образом  - var maskId = this.Terrasoft.controls.Mask.show(this);
 так же не работает.
 страница наследуется от Базовая схема карточки ( NUI ).
Ниже приведен код карточки:

define("AbReportSettingsPageV2", ["AbReportSettingsPageV2Resources", "BaseFiltersGenerateModule", "ServiceHelper"], 
	function(Resources, BaseFiltersGenerateModule, ServiceHelper) {
	return {
		entitySchemaName: "AbCustomReport",
		details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
		modules: /**SCHEMA_MODULES*/{}/**SCHEMA_MODULES*/,
		dataModels: /**SCHEMA_DATA_MODELS*/{}/**SCHEMA_DATA_MODELS*/,
		attributes: {
			"AbDateFrom":{
				"dataValueType": Terrasoft.DataValueType.DATE,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				"isRequired": true
			},
			"AbDateBy":{
				"dataValueType": Terrasoft.DataValueType.DATE,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				"isRequired": true
			},
			"AbCustomReport": {
				"dataValueType": Terrasoft.DataValueType.LOOKUP,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				"isLookup": true,
				"referenceSchemaName":"AbCustomReport",
				"isRequired": true
			},
			"City": {
				"dataValueType": Terrasoft.DataValueType.LOOKUP,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				"isLookup": true,
				"referenceSchemaName":"City",
			},
			"Country": {
				"dataValueType": Terrasoft.DataValueType.LOOKUP,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				"isLookup": true,
				"referenceSchemaName":"Country",
			},
			"Service": {
				"dataValueType": Terrasoft.DataValueType.LOOKUP,
				"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				"isLookup": true,
				"referenceSchemaName":"Product",
			}
		},
		diff: /**SCHEMA_DIFF*/[
			{
				"operation": "merge",
				"name": "SaveButton",
				"values": {
					"caption": "$Resources.Strings.AbLoadReportCaption",
					"visible": true
				}
			},
			{
				"operation": "merge",
				"name": "BackButton",
				"values": {
					"visible": true
				}
			},
			{
				"operation": "remove",
				"name": "actions"
			},
			{
				"operation": "remove",
				"name": "Tabs"
			},
			{
				"operation": "remove",
				"name": "PrintButton"
			},
			{
				"operation": "remove",
				"name": "OptionsButtonButton"
			},
			{
				"operation": "insert",
				"name": "AbReportSettingsContainer",
				"parentName": "CardContentContainer",
				"propertyName": "items",
				"values": {
					"itemType": Terrasoft.ViewItemType.CONTAINER,
					"items": [],
					"markerValue": "AbReportSettingsContainer"
				}
			},
			{
				"operation": "insert",
				"name": "AbReportSettingsGridLayoutContainer",
				"parentName": "AbReportSettingsContainer",
				"propertyName": "items",
				"values": {
					"itemType": Terrasoft.ViewItemType.GRID_LAYOUT,
					"items": []
				}
			},
			{
				"operation": "insert",
				"name": "AbDateFrom",
				"values": {
					"layout": {
						"colSpan": 8,
						"rowSpan": 1,
						"column": 0,
						"row": 0,
						"layoutName": "AbReportSettingsGridLayoutContainer"
					},
					"caption": "$Resources.Strings.AbDateFromCaption",
					"bindTo": "AbDateFrom",
					"enabled": true
				},
				"parentName": "AbReportSettingsGridLayoutContainer",
				"propertyName": "items",
				"index": 0
			},
			{
				"operation": "insert",
				"name": "AbDateBy",
				"values": {
					"layout": {
						"colSpan": 8,
						"rowSpan": 1,
						"column": 0,
						"row": 2,
						"layoutName": "AbReportSettingsGridLayoutContainer"
					},
					"caption": "$Resources.Strings.AbDateByCaption",
					"bindTo": "AbDateBy",
					"enabled": true
				},
				"parentName": "AbReportSettingsGridLayoutContainer",
				"propertyName": "items",
				"index": 1
			},
			{
				"operation": "insert",
				"name": "AbCustomReport",
				"values": {
					"layout": {
						"colSpan": 8,
						"rowSpan": 1,
						"column": 0,
						"row": 4,
						"layoutName": "AbReportSettingsGridLayoutContainer"
					},
					"caption": "$Resources.Strings.AbReportCaption",
					"bindTo": "AbCustomReport",
					"enabled": true,
					"contentType": 3
				},
				"parentName": "AbReportSettingsGridLayoutContainer",
				"propertyName": "items",
				"index": 2
			},
			{
				"operation": "insert",
				"name": "City",
				"values": {
					"layout": {
						"colSpan": 8,
						"rowSpan": 1,
						"column": 8,
						"row": 0,
						"layoutName": "AbReportSettingsGridLayoutContainer"
					},
					"caption": "$Resources.Strings.AbCityCaption",
					"bindTo": "City",
					"enabled": true,
					"contentType": 5
				},
				"parentName": "AbReportSettingsGridLayoutContainer",
				"propertyName": "items",
				"index": 3
			},
			{
				"operation": "insert",
				"name": "Country",
				"values": {
					"layout": {
						"colSpan": 8,
						"rowSpan": 1,
						"column": 8,
						"row": 2,
						"layoutName": "AbReportSettingsGridLayoutContainer"
					},
					"caption": "$Resources.Strings.AbCountryCaption",
					"bindTo": "Country",
					"enabled": true,
					"contentType": 5
				},
				"parentName": "AbReportSettingsGridLayoutContainer",
				"propertyName": "items",
				"index": 4
			},
			{
				"operation": "insert",
				"name": "Service",
				"values": {
					"layout": {
						"colSpan": 8,
						"rowSpan": 1,
						"column": 8,
						"row": 4,
						"layoutName": "AbReportSettingsGridLayoutContainer"
					},
					"caption": "$Resources.Strings.AbServiceCaption",
					"bindTo": "Service",
					"enabled": false,
					"contentType": 5
				},
				"parentName": "AbReportSettingsGridLayoutContainer",
				"propertyName": "items",
				"index": 5
			}
		]/**SCHEMA_DIFF*/,
		methods: {
			onEntityInitialized: function () {
				this.callParent(arguments);
				this.set("Name", this.getHeader());
				this.getCurrentContactCountry();
 
			},
			save: function() {
				this.runReportForming();
			},
			getCurrentContactCountry: function () {
				var currentContactId = Terrasoft.SysValue.CURRENT_USER_CONTACT.value;
				var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
					rootSchemaName: "Contact"
				});
				esq.addColumn("Country", "CountryId");
				esq.getEntity(currentContactId, function(result) {
					if (!result.success) {
						this.showInformationDialog(Resources.localizableStrings.AbCurrentUserCountryError);
						return;
					}
					var country = result.entity.get("CountryId");
					if(country!== null || country!== undefined) {
						this.set("Country", country);
					}
				},this)
			},
			runReportForming: function () {
				var startDate = this.get("AbDateFrom");
				var stopDate = this.get("AbDateBy");
				var report = this.get("AbCustomReport");
				var country = this.get("Country");
				var city = this.get("City");
				var service = this.get("Service");
				if(startDate === null || startDate === undefined) {
					this.showInformationDialog(Resources.localizableStrings.AbFillDateStartCaption);
					return;
				}
				if(stopDate === null || stopDate === undefined) {
					this.showInformationDialog(Resources.localizableStrings.AbFillDateStartCaption);
					return;
				}
				if(startDate > stopDate){
					this.showInformationDialog(Resources.localizableStrings.AbIntervalDateWarningCaption);
					return;
				}
				if(report === null || report === undefined) {
					this.showInformationDialog(Resources.localizableStrings.AbFillReportCaption);
					return;
				}
				if(report.value == "c77af1b5-7118-40c7-8636-870edb85d45f" && (city === null || city === undefined)) {
					this.showInformationDialog(Resources.localizableStrings.AbFiillCityWarningCaption);
					return;
				}
				var reportId = report.value;
				countryId = (country === null || country === undefined) ? null : country.value;
				cityId = (city === null || city === undefined) ? null : city.value;
				serviceId = (service === null || service === undefined) ? null : service.value;
 
				var dateStart = Ext.Date.format(startDate, 'Y-m-d');
				var dateStop = Ext.Date.format(stopDate, 'Y-m-d');
				var dataSend = {
					startDate: dateStart,
					stopDate: dateStop,
					reportId: reportId,
					countryId: countryId,
					cityId: cityId,
					serviceId: serviceId
				};
				this.getReportServices(dataSend);
			},
			getReportServices: function(dataSend) {
				var reportId = dataSend.reportId;
				var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
					rootSchemaName: "AbCustomReport"
				});
				esq.addColumn("Name", "ReportName");
				esq.addColumn("AbSourceCodeServiceName", "SourceCodeServiceName");
				esq.getEntity(reportId, function(result) {
					if (!result.success) {
						this.showInformationDialog("Ошибка запроса данных");
						return;
					}
					var reportName =  result.entity.get("ReportName");
					var sourceCodeName =  result.entity.get("SourceCodeServiceName");
					this.downloadReport(sourceCodeName, reportName, dataSend);
				}, this);
			},
			downloadReport: function(sourceCodeName, reportName, dataSend) {
				debugger;
				this.showBodyMask();
				Terrasoft.AjaxProvider.request({
					url: "../rest/" + sourceCodeName + "/GetReportUrl",
					headers: {
						"Accept": "application/json",
						"Content-Type": "application/json"
					},
					method: "POST",
					jsonData: dataSend,
					callback: function (request, success, response) {
						var responseObject = {};
						if (success) {
							responseObject = Terrasoft.decode(response.responseText);
							var key = "/" + responseObject.GetReportUrlResult;
							var reportCaption = reportName + ".xlsx";
							var report = document.createElement("a");
							report.href = "../rest/" + sourceCodeName + "/GenerateSalaryReport" + key;
							report.download = reportCaption;
							document.body.appendChild(report);
							report.click();
							document.body.removeChild(report);
						}
						this.hideBodyMask();
					}, scope: this
				});
			},
			getHeader: function() {
				return Resources.localizableStrings.AbPageSettingsCaption;
			}
		},
		rules: {},
		businessRules: /**SCHEMA_BUSINESS_RULES*/{}/**SCHEMA_BUSINESS_RULES*/
	};
});

 

У меня такой же вопрос

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

Добрый день.

Для вызова маски из this необходимо проверить, не потерялся ли контекст где-то по стэку вызова.  При правильном this метод showBodyMask(); должен работать.

Для вызова из MaskHelper необходимо модуль подключить в define.

define("AbReportSettingsPageV2", ["AbReportSettingsPageV2Resources", "BaseFiltersGenerateModule", "ServiceHelper", "MaskHelper"], 
	function(Resources, BaseFiltersGenerateModule, ServiceHelper, MaskHelper) 

В консоли ошибки есть?

Пащенко Александр Сергеевич,

В зависимости MaskHelper добавлял. Во всех трех случаях которые я описал ошибок в консоли нет.

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

попробуйте так:

 

var maskId = Terrasoft.MaskHelper.showBodyMask();

Terrasoft.MaskHelper.hideBodyMask(maskId);

 

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

Страница настроек случайно не в SystemDesigner вставлена?

Варфоломеев Данила,

Да, туда.

Есть какие то особенности в данной реализации?

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

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

Принял, благодарю. А ТП ничего не говорит по данному поводу?

Cм. пример использования showBodyMask и hideBodyMask. 

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

Все перепробовал - не работает.

Может, на самом деле маска показывается, но сразу скрывается другим процессом.

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

Добрый день!

 

Версия 7.12.3.

Столкнулся с проблемой, одному из пользователей (upd: на самом деле не одному, проблемы точно нет у cупервизора) система не позволяет менять/удалять инфу на детали Средства связи в Контакте (добавлять разрешает). Происходит это не у всех контактов, только на некоторых, системы еще не обнаружил (upd: обнаружил - сбой на контактах, заведенных после 16 августа сего года включительно).

BatchQuery возвращает сообщение об ошибке из темы, сама CRM показывает:

Права на объект вроде по умолчанию.

Что это за глюк?

У меня такой же вопрос

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

Попробуйте перераздать права на через решение Access rights setup wizard for bpm'online

А объект "Контакт" администрируется?

Судя по настройкам, нет.

Хотя на вкладке "Доступ к записям по умолчанию:" есть записи.

Тогда странно. Я бы попробовал встать дебаггером в функцию getValidationMessage. Сообщение похоже на то, что данная функция должна возвращать.

Не, сообщение приходит в ответ на 0/DataService/json/SyncReply/BatchQuery.
"Трасформируется" (неправильно) для вывода на экран в методе onSaved от BaseCommunicationDetail.

 

Борис Леонов,

Добрый день! В объекте детали ContactCommunication в свойстве "Доступ" у вас стоят где нибудь выбранные пункты?("По операциям, по колонкам и др."). Для полного доступа галочки напротив данных полей должны отсутствовать.

 

engineer7,

нет, галочки не установлены

Борис Леонов,

возможно данная статья сможет Вам помочь: https://academy.terrasoft.ru/documents/sales-enterprise/7-10/detal-dostup-k-obektu-razdela-dostup-k-obektam

engineer7,

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

Опыты показали, проблема не у одного пользователя, и затрагивает контакты, заведенные в систему после 16 августа сего года включительно...

А нет другой логики на сигналы с детали (в том числе на уровне объектных бп)?

Если есть доступ в базу, можно посмотреть скрытые в интерфейсе таблицы прав SysContactRight и SysContactCommunicationRight, если они есть. Отфильтровать по Id контактов и записей на детали средств связи, взяв примеры, созданные до и после 16. Может, права почему-то всё же выдались. Например, если тогда кто-то менял настройки прав для объекта и вернул как было.

Также можно попробовать включить по объектам Contact и/или ContactCommunication права по записям, а потом обратно выключить. Возможно, при прошлом выключении был сбой и не выключилось полностью. Лучше перед этим сделать бекап или проверять на копии базы.

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

 

 

Попробуйте перераздать права на через решение Access rights setup wizard for bpm'online

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

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

Реализовал деталь с редактируемым реестром и карточкой редактирования записи код ниже:

define("AbAccountProductDetail",
	["ConfigurationEnums", "ConfigurationGrid", "ConfigurationGridGenerator", "ConfigurationGridUtilities"],
	function (enums) {
		return {
			entitySchemaName: "AbAccountProduct",
			attributes: {
				"IsEditable": {
					dataValueType: Terrasoft.DataValueType.BOOLEAN,
					type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
					value: true
				}
			},
			mixins: {
				ConfigurationGridUtilities: "Terrasoft.ConfigurationGridUtilities"
			},
			methods:{
				init: function() {
					this.callParent(arguments);
					this.sandbox.subscribe("[AbAccountProductEntityEventListner]:[RequestToPlatform]:[Exception]", this.accountProductEntityListnerMsgHandler, this);
				},
 
				/*Overrided "BaseGridDetailV2"*/
				editRecord: function(record) {
					var activeRow = record || this.getActiveRow();
					if (!activeRow) {
						return;
					}
					if (!this.getIsCardValid()) {
						return;
					}
					var isCardChanged = this.getIsCardChanged();
					var primaryColumnValue = typeof activeRow === "object" ? activeRow.get(activeRow.primaryColumnName) : activeRow;
					var typeColumnValue = this.getTypeColumnValue(activeRow);
					this.setLastActiveRow(primaryColumnValue);
					if (isCardChanged) {
						this.set("CardState", enums.CardStateV2.EDIT);
						this.set("EditPageUId", typeColumnValue);
						this.set("PrimaryValueUId", primaryColumnValue);
						var args = {
							isSilent: true,
							messageTags: [this.sandbox.id]
						};
						this.sandbox.publish("SaveRecord", args, [this.sandbox.id]);
					} else {
						this.openCard(enums.CardStateV2.EDIT, typeColumnValue, primaryColumnValue);
					}
				},
 
				accountProductEntityListnerMsgHandler: function() {
					Terrasoft.ServerChannel.on(Terrasoft.EventName.ON_MESSAGE,
					function(scope, message){
							if (!message || message.Header.Sender !== "[AbAccountProductEntityEventListner]:[RequestToPlatform]:[Exception]") {
							return;
						}
						var message2 = message.Body;
						if (!this.Ext.isEmpty(message2)) {
							window.console.info(message2);
							this.Terrasoft.showInformation(message2);
						}
					}, this);
				}
			},
			diff: [
				{
					"operation": "merge",
					"name": "DataGrid",
					"values": {
						"className": "Terrasoft.ConfigurationGrid",
						"generator": "ConfigurationGridGenerator.generatePartial",
						"generateControlsConfig": { "bindTo": "generateActiveRowControlsConfig" },
						"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": "card",
								"markerValue": "card",
								"imageConfig": { "bindTo": "Resources.Images.CardIcon" }
							},
							{
								"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
					}
				}
			]
		};
	});

Пришлось переопределить editRecord():
 

var primaryColumnValue = typeof activeRow === "object" ? activeRow.get(activeRow.primaryColumnName) : activeRow;

т.к. дальше не срабатывало.
сейчас работает - http://prntscr.com/lfe61n
но при переходе на страницу редактирования поле для связи не заполняется - http://prntscr.com/lfe6k4
Подскажите в чем может быть дело?
Заранее благодарен.

У меня такой же вопрос

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

Попробуйте например вызывать openCardInChain и передавать туда значения по умолчанию
 

addChildRecord: function(typeColumnValue, date) {
var selectedItem = this.get("ActiveRow");
var defaultValues = [];
defaultValues.push({
	name: "ParentId",
	value: typeColumnValue
});
defaultValues.push({
	name: "UsrDate",
	value: date
});
var config = {
	sandbox: this.sandbox,
	schemaName: this.getEditPageSchemaName(typeColumnValue),
	operation: ConfigurationEnums.CardStateV2.ADD,
	moduleId: this.getChainCardModuleSandboxId(typeColumnValue),
	defaultValues: defaultValues
};
this.openCardInChain(config);
},

 

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

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

Попробуйте например вызывать openCardInChain и передавать туда значения по умолчанию
 

addChildRecord: function(typeColumnValue, date) {
var selectedItem = this.get("ActiveRow");
var defaultValues = [];
defaultValues.push({
	name: "ParentId",
	value: typeColumnValue
});
defaultValues.push({
	name: "UsrDate",
	value: date
});
var config = {
	sandbox: this.sandbox,
	schemaName: this.getEditPageSchemaName(typeColumnValue),
	operation: ConfigurationEnums.CardStateV2.ADD,
	moduleId: this.getChainCardModuleSandboxId(typeColumnValue),
	defaultValues: defaultValues
};
this.openCardInChain(config);
},

 

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

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

Коллеги нужна Ваша помощь. Необходимо в С# коде получить идентификатор SystemUser.
http://prntscr.com/lczocy
Хардкодом как то не очень хочется забивать.
Данный идентификатор необходим для работы в событийном слое Entity.
Заранее благодарен.

У меня такой же вопрос

3 комментария
Лучший ответ
//получить значение системной настройки
var mySystemUser=Terrasoft.Core.Configuration.SysSettings.GetValue(UserConnection, "SystemUser");
//получить значение системной настройки
var mySystemUser=Terrasoft.Core.Configuration.SysSettings.GetValue(UserConnection, "SystemUser");

Ну или, учитывая что система по-умолчанию работает от Supervisor-a:

UserConnection.AppConnection.SystemUserConnection.CurrentUser.Id

Не уверен, что сработает, но вроде должно)

Вставлю свои 5 копеек

в Terrasoft.Configuration определена константа id супервизора 

BaseConsts.SystemUserId 

 

 

 

 

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

Коллеги всем доброго времени суток. Подскажите, кто нибудь работал с событийным слоем Entity.
Написал класс обработчик в качестве примера для обучения скомпилировал приложение упал сайт.
Вот пример класса обработчика:
 

using System;
using System.Web;
using Terrasoft.Core;
using Terrasoft.Core.Entities;
using Terrasoft.Core.Entities.Events;
 
 
namespace Terrasoft.Configuration
{
    [EntityEventListener(SchemaName = "Order")]
    public class OrderEntityEventListener : BaseEntityEventListener
    {
 
        private UserConnection _userConnection;
 
        private LogService _logService;
        public UserConnection UserConnection
        {
            get
            {
                if (_userConnection != null)
                {
                    return _userConnection;
                }
                _userConnection = HttpContext.Current.Session["UserConnection"] as UserConnection;
                if (_userConnection != null)
                {
                    return _userConnection;
                }
                return _userConnection;
            }
 
            set { _userConnection = value; }
        }        
 
        public LogService LogService { get => _logService; set => _logService = value; }
 
        public OrderEntityEventListener()
        {
            LogService = new LogService(UserConnection);
        }
 
        public override void OnInserting(object sender, EntityBeforeEventArgs e)
        {
            try
            {
                base.OnInserting(sender, e);
 
                var systemUserName = UserConnection.CurrentUser.ContactName;
                var systemUserId = UserConnection.CurrentUser.ContactId;
                LogService.RecInfo($"LOG:[OnInserting]:systemUserId: {systemUserId}; systemUserName:{systemUserName}");
            }
            catch (Exception exception)
            {
                LogService.RecInfo($"LOG:[OnInserting]:Exception: {exception.Message}; {exception.InnerException}");
            }
 
        }
    }
}

Подскажите, что тут не так? Если кто работал, скинте пожалуйста примеры.
Заранее благодарен

У меня такой же вопрос

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

Добрый день, Алексей!

UserConnection необходимо получать из sender

Пример:

public override void OnSaved(object sender, EntityAfterEventArgs e) {
            base.OnSaved(sender, e);
            var entity = (Entity) sender;
            var userConnection = entity.UserConnection;
        }

Ошибка заключается в том, что слушатели изменений сущностей, работают не только при изменении значений через карточку (в данном случае есть HttpContext) но и в фоновом режиме (процессы, планировщик - без HttpContext).

Добрый день, Алексей!

UserConnection необходимо получать из sender

Пример:

public override void OnSaved(object sender, EntityAfterEventArgs e) {
            base.OnSaved(sender, e);
            var entity = (Entity) sender;
            var userConnection = entity.UserConnection;
        }

Ошибка заключается в том, что слушатели изменений сущностей, работают не только при изменении значений через карточку (в данном случае есть HttpContext) но и в фоновом режиме (процессы, планировщик - без HttpContext).

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

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

После прочтения документации вижу так:

  1. настроить необходимое в разделе [Лиды] в CRM
  2. сформировать ссылку в письме с нужными параметрами
  3. на сайте проверять параметры в ссылке

  4. при необходимости ставить куку - флаг первого посещения
  5. если посещение первое, то динамически создавать и программно сабмитить форму

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

У меня такой же вопрос

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

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

http://адрес_сайта.com/0/ServiceModel/GeneratedObjectWebFormService.svc/SaveWebFormObjectData

Клиентская логика — в общедоступных скриптах:

https://webtracking-v01.bpmonline.com/JS/track-cookies.js
https://webtracking-v01.bpmonline.com/JS/create-object.js

Серверная — в схеме GeneratedObjectWebFormService.

Другой вариант — писать полностью свой сервис с нужной функциональностью, доступный извне без авторизации.

Спрашивали - отвечаем.

Если в ссылке будет передан параметр bpmContactEmail="email@email.email", этот код зарегистрирует лида и привяжет к контакту с почтовым ящиком email@email.email. Ловушка для лида должна быть настроена в разделе [Лендинги].

/*Форма авторегистрации по ссылке из Email*/
					var configAutoReg = {
						fields: {
							"Email": ".bpm-contact-email" // Email посетителя
						},
					    landingId: "00000000-0000-0000-0000-000000000000", // ID лендинга, смотреть в шаге 2 настройки лендинга
					    serviceUrl: "http://CRM_SITE_DNS_NAME/0/ServiceModel/GeneratedWebFormService.svc/SaveWebFormLeadData",
						redirectUrl: ""
					};
					function createLeadFromAutoReg() {
						landing.createObjectFromLanding(configAutoReg)
					};
 
					//функция позволяет выполнять действие (регистрацию лида) один раз
					//взята тут https://developer.mozilla.org/ru/docs/Web/API/Document/cookie#Example_5_Do_something_only_once_%E2%80%93_a_general_library
					function executeOnce () {
						var argc = arguments.length, bImplGlob = typeof arguments[argc - 1] === "string";
						if (bImplGlob) { argc++; }
						if (argc < 3) { throw new TypeError("executeOnce - not enough arguments"); }
						var fExec = arguments[0], sKey = arguments[argc - 2];
						if (typeof fExec !== "function") { throw new TypeError("executeOnce - first argument must be a function"); }
						if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { throw new TypeError("executeOnce - invalid identifier"); }
						if (decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) === "1") { return false; }
						fExec.apply(argc > 3 ? arguments[1] : null, argc > 4 ? Array.prototype.slice.call(arguments, 2, argc - 2) : []);
						document.cookie = encodeURIComponent(sKey) + "=1; expires=Fri, 31 Dec 9999 23:59:59 GMT" + (bImplGlob || !arguments[argc - 1] ? "; path=/" : "");
						return true;
					};
 
					// функция возвращает значение указанного парметра из ссылки
					function getSearchParams(k){
						var p={};
						location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){p[k]=v})
						return k?p[k]:p;
					};
 
					jQuery(document).ready(function() {
						var bpmContactEmail = getSearchParams("bpmContactEmail");
						if (bpmContactEmail && bpmContactEmail !== "[") {
 
							executeOnce(function() {
								landing.initLanding(configAutoReg);								
								var $form = $("<form />", { style: "display: none;", onSubmit: "createLeadFromAutoReg(); return false" });
								$form.append($("<input />", { class: "bpm-contact-email" , name: "bpmContactEmail", value: bpmContactEmail}));
								$form.appendTo("body").submit().remove();
							},
							"bpmLeadFromEmail");
 
						}
					});

 

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

да не, все проще оказалось, в bpm все настройки только стандартные, а на сайте легкая доработка :)

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

Войдите или зарегистрируйтесь, чтобы комментировать