Hi All,

 

When I import data, system auto thinks me as the record author. Is there a way to give access right to different organisational/ functional role?

For example, 2 groups of organisational roles: A and B. How can I do the import if part of data set should be seen by A but not B, and vice versa.

 

Really appreciate any advise 

Thanks

Like 0

Like

1 comments

Hello,

 

Currently there is no basic functionality to setup access rights for users dynamically within the import process itself. However, you can use the following alternatives to achieve your business task:

 

Set up record permissions for the needed object based on the record author and then import the records under different users in separate batches based on the role.

For example, import a batch of records that only the role A should get access rights for under user1. Setup the record permissions this way:

If record author is user1, then give access rights to role A.

Then import the next batch of records under user2 and setup the record permissions as:

If record author is user2, then give access rights to role B.

 

Another option is to create a business process that would read data (read a collection of records) and then transfer the data from the records to a subprocess. The subprocesses will then process each record separately (1 subprocess will run for 1 record) and change the access rights (with the help of Access rights element) for these records. However, in such case you need to have a field in this object that would signify what role should get the access rights for which record, based on which the process will determine what rights to give to which record.

Show all comments

Hi Community,

We have activated the 'Enable live data update' for the Contacts and its currently not working.

We have a business process that updates fields of the Contact once finished. Only when we click Refresh the fields are updated.

How can we fix/debug this issue?

Sasor

Like 0

Like

4 comments

I assume you're using a Freedom UI section/page? It doesn't work with classic. Also, make sure the feature "LiveEditingForCurrentUser" is on as well.

Ryan

Ryan,

Thank you for the reply.

 

The page is Contacts in freedom UI.

 

From the Business Process I am trying to update the lookup that is responsible for the stages ( Progress Bar). The progress Bar is only updated after I click the Refresh button. 

Should I do some other modifications as well ?

Sasor

We also have this issue, but then tested in 8.1.2 and not found that



Vladimir

You should check with the support. This feature is causing performance issue in 8.1.1.

I recently had an issue after I imported more than 20k cases in a site and the support deactivated the live update for a little while until I creaed a new case on this subject.

Show all comments

I have a 'Contract' object with a start date field, and I want to display that field (start date) in the associated 'Opportunity.' I used an input to retrieve the field in my opportunity. However, the issue is that the date displayed in the opportunity is in the date/time format, whereas the field in the contract is in the date format. How can I display the date in the opportunity with just the date format?

Like 0

Like

1 comments

Hi!

 

Regrettably, this behavior is currently exclusive to the Input Date/Time field. The field currently presents data exactly as it appears in the database, resulting in users consistently receiving Date/Time format data even if the corresponding page originally only contained Time or Date information in these fields.



We wish to inform you that we have imminent plans to address and rectify this behavior in the near future. Anticipated changes are expected to be incorporated in a subsequent release, likely following version 8.1.3.

 

If you have any further questions, please respond to this email we would be happy to help.

Thank you for choosing Creatio!

Show all comments

I'm looking for the code/process that does the denormalisation of Account Address entity records created against an Account on to that Account, as well as the code/process that normalises data put on the Account record for address details that get made into Account Address records (or update the existing one, if that's what it does). I haven't been able to find it in event listeners or business processes yet, but I presume it must be in one of those. We need to add some additional new fields to follow the same process, and it would seem sensible to use the same code to do so. We're on 8.1.1.

Like 0

Like

6 comments
Best reply

If you're referring to the code that adds the primary address values to the account (or contact) columns, that is in C# BaseAddressSynchronizer. This code is triggered from the specific address objects (such as AccountAddress) subprocess (open AccountAddress object then click "open process").  

FYI in classic pages there was also code on the page that did this via sandbox messages iirc.

Ryan

If you're referring to the code that adds the primary address values to the account (or contact) columns, that is in C# BaseAddressSynchronizer. This code is triggered from the specific address objects (such as AccountAddress) subprocess (open AccountAddress object then click "open process").  

FYI in classic pages there was also code on the page that did this via sandbox messages iirc.

Ryan

Thanks Ryan, any idea what the correct way to add an additional field to the synchronization process would be? I'm expecting that it would require adding a new C# module that inherits from the BaseAddressSynchronizer class (or maybe the AcountAddressSynchronizer for Account Addresses specifically?) and adds columns to the GetSynchronizationColumnMappings method in the following way:

protected override ICollection<SynchronizationColumnMapping> GetSynchronizationColumnMappings() {
	SynchronizationColumnComparator stringEqualComparator = EqualComparatorProvider.GetStringEqualComparator();
	var baseColumnMappings = base.GetSynchronizationColumnMappings();
	baseColumnMappings.Add(new SynchronizationColumnMapping {
		SourceColumnName = "SrcColName",
		DestinationColumnName = "TgtColName",
		Comparator = stringEqualComparator
	});
	return baseColumnMappings;
}

With the Account Address entity's column name as the source column name and the Account entity's column name as the target column name. Does the entity's subprocess also need editing to make this logic work, or does the GetAddressSynchronizer method used in the existing subprocess automatically include the extra column mappings defined in the override? Can't see where that method comes from.

Harvey Adcock,

 

Hi!

Yes, you need to create a new source code schema, add a new class that inherits from the BaseAddressSynchronizer, and override the GetSynchronizationColumnMappings method.

You may use the AccountAddressSynchronizer class as an example.

To apply the changes to the entity, it is necessary to create a replacing object and update its process methods (to call the overridden method instead of the default one).

Natalia Kalynovska,

 

Hi Natalia, does that require recreating the Process that's attached to the OOTB Account Address entities? As the replacing object in our package doesn't have that process by default, so in order to change it, it seems like we would have to recreate the previous Process with those changes? And does a Process in a replacing object "overwrite" the Process in the replaced object, or do they both still operate? I'm not sure if there's much documentation on the Entity Processes.

 

Thanks,

Harvey

Harvey Adcock,

Hello Harvey,

Have you find a solution to your needs?

No, unfortunately not yet. I didn't end up spending much more time after this thread on it though, it was deprioritised in our project, so it would still be useful if anyone knows how to correctly override entities' Entity Processes.

Show all comments

Is it possible to restrict the "Owner" filter for Timeline components to only show Contacts which match a specific filter condition? We are currently seeing every Contact as an option, but for us this should be restricted to only Contacts which have a User record associated with them, and ideally we'd want to add some more customisation to the filter options beyond this.

Like 0

Like

9 comments
Best reply

I've discovered that it's possible to add this using code. To do so, you need to override the crt.LoadDataRequest handler and use the following code:

{
	request: "crt.LoadDataRequest",
	handler: async (request, next) => {
		// Filter Timeline's Owner filter to just Contacts with a User record
		if(request.dataSourceName === "ByOwnerQuickFilterInTimeline_xi3lpgm_ComboBox_List_DS") {
			const filter = new sdk.FilterGroup();
			await filter.addExistsFilter("[SysAdminUnit:Contact:Id].Id");
 
			// workaround for filters
			const newFilter = Object.assign({}, filter);
			newFilter.items = filter.items;
 
			request.parameters.push({
				type: "filter",
				value: newFilter
			});
		}
 
		return await next?.handle(request);
	}
},

You have to replace the name of the Timeline component in the above code from Timeline_xi3lpgm to whatever the component is called on your page.

Hello Harvey,



There is no such option for now, however, we've registered it in our R&D team backlog for consideration and implementation in future application releases.

 

Thank you for helping us to improve our product. 

Thanks Bogdan, it's definitely a feature that's needed - having every Contact show up in the Owner filter with no way to change this on a CRM platform isn't ideal.

I've discovered that it's possible to add this using code. To do so, you need to override the crt.LoadDataRequest handler and use the following code:

{
	request: "crt.LoadDataRequest",
	handler: async (request, next) => {
		// Filter Timeline's Owner filter to just Contacts with a User record
		if(request.dataSourceName === "ByOwnerQuickFilterInTimeline_xi3lpgm_ComboBox_List_DS") {
			const filter = new sdk.FilterGroup();
			await filter.addExistsFilter("[SysAdminUnit:Contact:Id].Id");
 
			// workaround for filters
			const newFilter = Object.assign({}, filter);
			newFilter.items = filter.items;
 
			request.parameters.push({
				type: "filter",
				value: newFilter
			});
		}
 
		return await next?.handle(request);
	}
},

You have to replace the name of the Timeline component in the above code from Timeline_xi3lpgm to whatever the component is called on your page.

Harvey Adcock,

good find, thanks!

You should mark your own answer as solution ;)

Harvey Adcock,

Well done! Thanks for sharing this Harvey. 

Also, if you've moved to 8.1.1 you no longer need the filters workaround - it's finally working properly in 8.1.1, just thought I'd mention.

Ryan

Ryan Farley,

Ahh great to hear, thanks for the info Ryan - and thanks for spreading the info about that workaround in the first place!

I'd like to share my solution on lookup filtering.

We wanted to have only contacts from our company and in certain functional role.

{
	request: "crt.LoadDataRequest",
	handler: async (request, next) => {
		if (request.dataSourceName !== "FbContact_List_DS") {
			return await next?.handle(request);
		}
 
		const ourCompanyFilter = new sdk.CompareFilter(
			sdk.ComparisonType.Equal, 
			new sdk.ColumnExpression({
				columnPath: "Account.Type"
			}), 
			new sdk.ParameterExpression({
				value: Constants.AccountType.OurCompany
			})
		);
 
		const funcRoleFilter = new sdk.CompareFilter(
			sdk.ComparisonType.Equal, 
			new sdk.ColumnExpression({
				columnPath: "[SysAdminUnit:Contact:Id].[SysUserInRole:SysUser:Id].SysRole.Id"
			}), 
			new sdk.ParameterExpression({
				value: Constants.FunctionalRole.MyCustomFunctionalRole
			})
		);
 
		request.parameters.push({
			type: sdk.ModelParameterType.Filter,
			value: ourCompanyFilter
		});
 
		request.parameters.push({
			type: sdk.ModelParameterType.Filter,
			value: funcRoleFilter
		});
 
		return await next?.handle(request);
	}
}

 

Alex Zaslavsky,

Interesting, it hadn't occurred to me to push multiple filters to the parameters. I've always added the multiple filters to a FilterGroup and then added the group to the parameters. I guess it's an array for a reason :) Nice to know it works that way as well.

Ryan

Hello , 

Can we set a current user as a default in timeline quickfilter ? 

Show all comments

I have added a button on every record in detail for a particular column. I am trying to have one more button on the same detail, But the button is not visible on the UI.

The code that i used for this is:

{
"operation": "merge",
"name": "DataGrid",
"parentName": "DataGridContainer",
"propertyName": "items",
"values": {
"className": "Terrasoft.ControlGrid",
"controlColumnName": "UsrPlanningManagerRelevance",
"applyControlConfig": {"bindTo": "applyControlConfig"}
}
},

METHOD

applyControlConfig: function(control, activeRow) {
control.config = {
"className": "Terrasoft.Button",
"style": Terrasoft.controls.ButtonEnums.style.BLUE,
"caption": "מסמכי רקע",//this.get("Resources.Strings.FileButtonCaption"),
"imageConfig": {"bindTo": "Resources.Images.ExportToExcelBtnImage"},
"handler": this.BackgroundDocumentsClick.bind(this, activeRow.id)
};

Can anyone help me on this?

Like 1

Like

1 comments
Best reply

Hi,



I think, you can do this by appending buttons in the targeted column.

 

var baseEle = "#Identifier div[id*=\"item-" + rowId + "\"]  div:nth-last-child(2)";
$(baseEle).append(Ext.String.format("<span></span>"));
 
var ele = baseSelector + ">span";
$(ele).click(function() {});

 

Loop collection in prepareResponseCollection method or onGridDataLoaded

Hi,



I think, you can do this by appending buttons in the targeted column.

 

var baseEle = "#Identifier div[id*=\"item-" + rowId + "\"]  div:nth-last-child(2)";
$(baseEle).append(Ext.String.format("<span></span>"));
 
var ele = baseSelector + ">span";
$(ele).click(function() {});

 

Loop collection in prepareResponseCollection method or onGridDataLoaded

Show all comments

We were trying to expose the automatically-created Change Log entities created by Creatio when change tracking is turned on for entities, which generally take the form of SysLog but don't actually get navigable entities created in the package. Is there any way to expose these, for example in a detail on a page in Freedom UI? We wanted to be able to specify our own sorting and filtering logic on the OOTB section, as it's quite frustrating to use - for example, every time you drill into a record, it resets the date range for that record to the current day. You also can't search for specific record IDs that you want to see modifications to unless the record never had a Name filled in which makes trying to see what happened to deleted records you know must have existed very difficult!

 

I tried manually creating an entity over the table name (specifying it as a database view so Creatio didn't try to create or update the actual table) but then adding the change log entity's columns wasn't possible due to them having to have the prefix before the names, which the automatically-created columns of the change log table didn't have (e.g. Id, ChangeTypeId etc). Any way of working around this or a way of adding a change log entity as List in the UI somehow?

Like 1

Like

5 comments
Best reply

You can avoid needing the prefix by clearing the prefix system setting. Then no prefix will be needed.

However, I'm not sure creating the object would be a good idea, perhaps? Seems risky. What I would do is create a database view wrapping the data and then expose that as an object instead. That seems like the best route to me.

Ryan

Any ideas on how this might be possible?

You can avoid needing the prefix by clearing the prefix system setting. Then no prefix will be needed.

However, I'm not sure creating the object would be a good idea, perhaps? Seems risky. What I would do is create a database view wrapping the data and then expose that as an object instead. That seems like the best route to me.

Ryan

Thanks Ryan, sounds like a great idea - then the view over the top of the change log table can have its columns renamed where the prefix isn't present to start with the prefix, which will avoid the need to turn prefix off and on when adding new columns to the change log view entity.

Harvey,

 

Can I ask, what tables the change log is saved to if you know?  Or if there is a view to read the change log?  There is an API I note but I have a scenario where a SQL query is the better option.

Hi Gareth, the name of the tables created for the change log is Sys[object name]Log, so for example for the Account entity, it would be SysAccountLog. Hope this helps!

Show all comments

In the academy documentation, there is limited information about using the ESQ/ORM server-side methods to delete data, with only 2 or 3 toy examples. We need to efficiently delete large volumes of data using server-side ESQ in one of our processes, but we can't see anything about bulk deleting while still firing off any event-based triggers on the entity or generating change log records for it. Obviously the direct Terrasoft.Core.DB delete statement would be very efficient, but would skip the Creatio logic where needed.

 

We've been able to delete records by iterating over a collection of entities matching the required filtering condition retrieved by using GetEntityCollection and then for each entity in the collection, running a FetchFromDB on its Id before deleting it, but this seems like quite a few steps more than should be required and doesn't do it in a batched way.

 

Any help would be greatly appreciated.

Like 0

Like

2 comments

Hello Harvey,

 

You can use out-of-the-box examples of bulk deletion logic. For example we can take the BulkEmailTargetArchiver class and the DeleteArchiveLevel method in it:

private void DeleteArchiveLevel(string sourceSchemaName, string targetSchemaName) {
			int processedRecords;
			do {
				var deleteQuery = new Delete(_userConnection).From(sourceSchemaName)
					.Where("Id").In(new Select(_userConnection)
						.Top(_batchSize)
						.Column("s", "Id")
						.From(sourceSchemaName).As("s")
						.Where().Exists(new Select(_userConnection)
							.Column(Column.Parameter(1))
							.From(targetSchemaName)
							.Where(targetSchemaName, "Id")
							.IsEqual("s", "Id")));
				processedRecords = deleteQuery.Execute(_dbExecutor);
			} while (processedRecords != 0);
		}

This is just one example of the logic. You can use:

 

select * from SysSchemaSource

where Source like '%DeleteQuery%'

 

to get other schemas in the application configuration with delete queries examples and build your own one using all examples you may find in the system.

Hi Oleg,

 

using these Delete classes bypasses Creatio’s internal logic though, right? So change logs will be inaccurate and any BPs that should be triggered on delete would not be triggered etc. This seems risky to me as important processes could hang off this, and I don’t know what other internal aspects of Creatio might be relying on logic that Creatio manages at an application level.

 

Is there any way to bulk delete while respecting that?

Show all comments

Hi Community,

How can we filter the Cities based on the Zip Code (string field) in Freedom UI?

Apparently dynamic filtration on Object Level works only for Lookup fields.

Sasori

Like 0

Like

4 comments

Hello Sasori,



Since a text field and there is no lookup values you can not filter it based on conditions. 

Hi Bogdan,

Your answer is something that we already now (I have already stated that in my post) . And it is very astonishing that such functionality which was oob in the Classic UI is not present in the Freedom UI.

Please give us a code example of implementing such functionality in freedom UI.

Sasori

Sasori,

 

We don't have a ready example of such implementation. 

 

However, we have already registered the idea for our R&D team to implement this functionality in further releases. I will assign your case to this project to increase its priority.  

Sasori Oshigaki,



You need to create other lookups, remove and replace the current postal code text field, so that you can add postal code to the list of cities to do the links. It is indeed weird that this is a seperate text field as an OOTB feature.



Also, accounts is in Freedom UI, with customer 360, but not account adresses , how weird is that ??

Show all comments

I tried returning false and not calling next?.handle(request), but the record still seems to get saved. In Classic UI it was possible to prevent saving by not calling the this.callParent method, which I believe is somewhat analogous to the next?.handle(request), but I guess not perfectly? Maybe I'm missing something.

Like 1

Like

1 comments
Best reply

Hello Harvey,

It is possible, and you do it in the right way as I can see from the description. To prevent saving you have to declare this handler in the scheme and simply do not call next?.handle(request). 

Hello Harvey,

It is possible, and you do it in the right way as I can see from the description. To prevent saving you have to declare this handler in the scheme and simply do not call next?.handle(request). 

Show all comments