Question

My question concerns changing the button availabillity without updating the list – kindly advise where I can learn about the sandbox message implementation feature?

Answer

There are a lot of examples of sandbox message implementation in bpm'online. The BasePageV2  and BaseSectionV2 modules are some of them. In these modules, when performing initialization, we call the subscribeSandboxEvents() method that implements subscription to the sandbox messages.

For example, the [CardChanged] message subscription is implemented in the BaseSectionV2  module. When the module receives this message, it sets the modified value to the corresponding attribute. The message, on the other hand, sends (publishes) the BasePageV2 module when calling the publishPropertyValueToSection() method. The publishPropertyValueToSection() method, in its turn, is called when certain attributes of the edit page model are modified.

You can act in a similar way. For example, subscribe to the modification of the [ServiceCategory] field in the init() method of your edit page (CasePage):

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

Thus, when the [ServiceCategory] page field is modified, the new value will be populated in the [CurrentServiceCategory] attribute of the CaseSection section.

After this, you will be able to receive the current category value by addressing the [CurrentServiceCategory] attribute:

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

 

Like 0

Like

Share

0 comments
Show all comments

1. Create Source Code:

Ext.define("Terrasoft.configuration.service.UsrYourService", {
    alternateClassName: "Terrasoft.UsrYourService",
    statics: {
 
        serviceUrl: "rest/UsrYourService/",  // Name of your Service
 
        yourAction: function(config) {
            var data = {
                recordId: config.id // Input parameter(s) of service
            };
            Terrasoft.RequestManager.issueRequest({
                supressRequestEvents: false,
                requestFn: Terrasoft.Ajax.request,
                requestFnConfig: {
                    url: Terrasoft.util.encodeServiceUrl(this.serviceUrl) + config.action,
                    method: "POST",
                    jsonData: data,
                    success: function(response) {
                        var decodedResponse = Ext.JSON.decode(response.responseText, true);
                        Ext.callback(config.success, config.scope, [decodedResponse]);
                    },
                    failure: function(response) {
                        var parser = Ext.create("Terrasoft.ServiceResponseParser", response);
                        var exception = parser.getServiceFailureException();
                        Ext.callback(config.failure, config.scope, [exception]);
                    },
                    scope: this
                },
                responseToStatusCodeFn: function(response) {
                    return response.status;
                },
                scope: Terrasoft.Ajax
            });
        }
    }
});

2. Add in MobileApplicationManifest your service into CustomSchemas block:

"CustomSchemas": [
    "UsrYourService"
]

3. Call service from your code:

yourFunction: function() {
    Terrasoft.UsrYourService.yourAction({
        id: this.record.getId(), // RecordId
        action: "Start", // Method of service
        success: this.serviceSuccess, // Success callback
        failure: this.serviceFailure, // Error callback
        scope: this
    });
},
serviceSuccess: function(response) {
    if (response.isSuccess) {
        ///TODO: do something
    } else {
        Terrasoft.MessageBox.showMessage(Terrasoft.LocalizableStrings.StartErrorMessage); // Error message
    }
},
serviceFailure: function(error) {
    var response = error.getResponse();
    Terrasoft.MessageBox.showMessage(response.statusText);
}

 

Like 0

Like

Share

0 comments
Show all comments

In order to run process GlbProcess1 from server side use code below:

IProcessExecutor processExecutor = UserConnection.ProcessEngine.ProcessExecutor;
var nameValues = new Dictionary<string, string>();
// Add your parameters
nameValues["RecordId"] = entityId.ToString();
processExecutor.Execute("GlbProcess1", nameValues);

If you want to run GlbProcess1 for all records in Case:

var esq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Case");
esq.PrimaryQueryColumn.IsAlwaysSelect = true;
var entities = esq.GetEntityCollection(UserConnection);
foreach(var entity in entities) {
    var entityId = entity.PrimaryColumnValue;
    IProcessExecutor processExecutor = UserConnection.ProcessEngine.ProcessExecutor;
    var nameValues = new Dictionary<string, string>();
    // Add your parameters
    nameValues["RecordId"] = entityId.ToString();
    processExecutor.Execute("GlbProcess1", nameValues);
}

 

Like 0

Like

Share

3 comments

This code gives an error now. "ProcessExecutor is not usable because of it's protection level" or something like that.

Hi Jonas,

I just checked from my end and I was able to use above article to start a process.



Which version are you using? Could you please provide error screenshot?



Regards,

Dmytro

Hi Dmytro Smishchenko & Tatiana,

Have a follow up question regarding executing a BP from the server side. The article covers how to execute it by passing certain parameters. How does one get back certain out output parameters after the BP executes??



I went through the IProcessExecutor documentation here and it permits to retrieve one result parameter. What if I need to read more than 1 parameter at the end of the business process execution?? Is there any other way to execute a BP from server side code and get the output parameter?



Anastasia's comment in this question - https://community.creatio.com/questions/call-business-process recommends the use of FlowEngine to run the business process. I also went through the class documentation of FlowEngine here. Could not find a way to get BP parameters after execution.



Appreciate your assistance. 

Show all comments

Question

Can we configure calculating the response/resolution time from the moment of assigning a case assignee (it is now calculated from the moment of registering a case)?

Answer

The date of calculation is performed at the moment of changing the Service in the onServiceItemChanged() method when a case is created. You can create a method that would process chaning of the Assignee and calculate the date, but make sure all the necessary fields are populated before that (in particular, the [Service] field).

Like 0

Like

Share

0 comments
Show all comments

Question

How do I display another column in the "Accounts" list in the mobile app? For example, the "Address" coulmn?

Answer

Since the MobileAccountModuleConfig base schema cannot be changed, you need to create a custom UsrMobileAccountModuleConfig schema (in a custom package, create the page extension schema of the corresponding section). To do this, in the [Configuration] section, select Add > Source code. Fill in the schema properties ([Title], [Name], [Package]). Select JavaScript as a language for the schema, and connect it to the manifest.

 

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

Paste the following code in the schema:

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

Register the necessary columns in the manifest:

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

Once done, we recommend regenerating the source code and compiling the configuration 

Like 0

Like

Share

0 comments
Show all comments

Question

I cannot delete a participant from an activity. The error message informs that I canot delete the Owner, but the participant in fact IS NOT the owner.

Answer

-- downgrading to a participant
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
)
-- upgrading to an owner
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'
)

 

Like 0

Like

Share

0 comments
Show all comments

Case description:

We want to change color of activity on ActivitySection.

Algorithm of realization:

  1. You should create client replacing module for "ActivitySectionV2" from NUI package.
  2. Add to this module three methods:
    1.  getGridDataColumns - this method configures which fields we will get from DB for each activity;

      getGridDataColumns: function() {
          var baseGridDataColumns = this.callParent(arguments);
          var gridDataColumns = {
              "Account": {path: "Account"},
              "StartDate": {path: "StartDate"},
              "DueDate": {path: "DueDate"},
              "ShowInScheduler": {path: "ShowInScheduler"},
              "Status": {path: "Status"},
              //Added by me, because in base implementation this method doesn't get this field
              "Result": {path: "Result"},
              "Status.Finish": {path: "Status.Finish"},
              "ProcessElementId": {
                  path: "ProcessElementId",
                  dataValueType: 0
              }
          };
          return Ext.apply(baseGridDataColumns, gridDataColumns);
      },

       

    2. prepareResponseCollection and setColor - this methods set background color for activities;

      prepareResponseCollection: function(collection) {
          var notStartedId = ConfigurationConstants.Activity.Status.NotStarted;
          var inProgressId = ConfigurationConstants.Activity.Status.InProgress;
          var finishedId   = ConfigurationConstants.Activity.Status.Done;
          var canceledId   = ConfigurationConstants.Activity.Status.Cancel;
       
          this.callParent(arguments);
       
          collection.each(function(item) {
              var status = item.get("Status").value;
              if (status === notStartedId.toLowerCase()) {
                  this.setColor(item, "#42f4dc");
              } else if (status === inProgressId.toLowerCase()) {
                  this.setColor(item, "#4168f4");
              } else if (status === finishedId.toLowerCase()) {
                  this.setColor(item, "#88f441");
              } else if (status === canceledId.toLowerCase()) {
                  this.setColor(item, "#f441af");
              }
          }, this);
      },
      setColor: function(item, color) {
          //Items in register
          item.customStyle = {
              background: color,
          };
          //Items on calendar view
          item.set("Background", color);
      }

       

  3. In this case we change color depend on activity status, but you can use another field. For example - Result. You can get Result id of item by call item.get("Result").value. IMPORTANT! You must add this field to getGridDataColumns method. Identificators of default activity results you can get by next query

    SELECT Name, Id FROM ActivityResult

    to your bpm'online DB.

  4. This code can work for ActivityDetail too. Algorithm of realization is same.
  5. If you want you can store your color settings in Lookup.
    1. Create lookup which will looks like this:

      Figure 0.

    2. Add method which will get them from DB

      init: function() {
          this.callParent(arguments);
          this.getColorsFromLookup();
      },
      getColorsFromLookup: function() {
          var colors = {};
          var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
              rootSchemaName: "GlbActivityColor"
          });
          esq.addColumn("Name");
          esq.addColumn("GlbCode");
          esq.getEntityCollection(function (result) {
              if (!result.success) {
                  return;
              }
              result.collection.each(function (item) {
                  colors[item.get("Name")] = item.get("GlbCode");
              });
              this.set("Colors", colors);
              debugger;
          }, this);
      }

       

    3. Add attribute which will store colors at front-end

      attributes: {
          Colors: {
              dataValueType: this.Terrasoft.DataValueType.CUSTOM_OBJECT
          },
      },

       

    4. Fix prepareResponseCollection method for using colors from our attribute

      prepareResponseCollection: function(collection) {
          var notStartedId = ConfigurationConstants.Activity.Status.NotStarted;
          var inProgressId = ConfigurationConstants.Activity.Status.InProgress;
          var finishedId   = ConfigurationConstants.Activity.Status.Done;
          var canceledId   = ConfigurationConstants.Activity.Status.Cancel;
       
          this.callParent(arguments);
       
          collection.each(function(item) {
              var status = item.get("Status").value;
              if (status === notStartedId.toLowerCase()) {
                  this.setColor(item, this.get("Colors")["notStarted"]);
              } else if (status === inProgressId.toLowerCase()) {
                  this.setColor(item, this.get("Colors")["inProgress"]);
              } else if (status === finishedId.toLowerCase()) {
                  this.setColor(item, this.get("Colors")["finished"]);
              } else if (status === canceledId.toLowerCase()) {
                  this.setColor(item, this.get("Colors")["canceled"]);
              }
          }, this);
      },

       

Like 0

Like

Share

1 comments

Color is not getting updated once activity edit page is saved and closed when activity edit page is opened from onScheduleItemDoubleClick method

Show all comments

Case:

How to send email from script task from portal? I am using 

Script task code

var emailClientFactory = ClassFactory.Get<EmailClientFactory>(new ConstructorArgument("userConnection", UserConnection));
var activityEmailSender = new ActivityEmailSender(emailClientFactory, UserConnection);
activityEmailSender.Send(AddDataUserTask1.RecordId);

And i get errors on sending. I've already added Terrasoft.Core.Factories, Terrasoft.Mail.Sender, Terrasoft.Mail namespaces to my process.

Solutuion:

1. Create a shared mailbox and allow access to it for portal users

2. Open access to following objects for portal users:

  • Activity
  • ActivityStatus
  • ActivityParticipant
  • ActivityType
  • ActivityCategory
  • ActivityParticipantRole
  • MailboxSyncSettings
  • MailServerType
  • MailServer
  • EmailTemplate
  • EmailMessageData
  • EmailSendStatus
  • EmailType

3. Allow access for portal users for SysSetting with code IgnoreExchangeSSLWarnings and make sure it is NOT cached

Like 0

Like

Share

0 comments
Show all comments

Symptoms

A customer has the "Payment status", "Delivery status" fields together with currency dashboards displayed on all tabs of the order page. These fields cannot be edited via the section wizard, since they are displayed the same way there.

Cause

The OrderPageV2 page was developed by a partner and contained the following code for the specified elements:

{
    "operation": "merge",
    "name": "PaymentStatus",
    "values": {
        "layout": {
            "column": 0,
            "row": 1,
            "colSpan": 12,
            "rowSpan": 1
        },
        "caption": {
            "bindTo": "Resources.Strings.PaymentStatusCaption"
        },
        "enabled": true
    }
},
{
    "operation": "remove",
    "name": "PaymentStatus",
    "properties": [
        "contentType",
        "parentName",
        "propertyName"
    ]
},
{
    "operation": "move",
    "name": "PaymentStatus",
    "index": 1
}

Solution

Change the page code for the specified elements by eliminating partner logic, for example, for:

{
    "operation": "insert",
    "name": "PaymentStatus",
    "values": {
        "bindTo": "PaymentStatus",
        "layout": {
            "column": 0,
            "row": 6,
            "colSpan": 12,
            "rowSpan": 1
 },
        "contentType": Terrasoft.ContentType.ENUM,
        "caption": {
            "bindTo": "Resources.Strings.PaymentStatusCaption"
 },
        "enabled": true
 },
    "parentName": "Header",
    "propertyName": "items",
    "index": 9
}

Necessary conditions and possible restrictions:

Particular case, individual solution

Like 0

Like

Share

0 comments
Show all comments

Question

Terrasoft.Geolocation.getCurrentCoordinates is used to determine GPS coordinates on an Android mobile device, which for some reason does not launch the GPS module (the GPS start indicator does not appear in the UI of the device). 

Is it possible to collect the coordinate information without enabling this module (maybe a coordinate cache?)

Answer

Yes, the GPS service can be disabled. The data can be collected based on mobile device settings (from Wi-Fi points), or it can be cached. 

In fact, the way bpm'online collects the coordinates can be controlled. Below is an example of the current implementation of the mentioned method:

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

At the moment, if there is no Internet connection or if the device is not connected to Wi-Fi (for example, you're using EDGE or 3G), then the “accurate” positioning will be used (GPS), but otherwise the data will be obtained using Wi-Fi, caching, etc., providing less accurate location information, but sufficient for given business tasks.

Nevertheless, if you need to receive data using GPS in all cases, you can create your own implementation of the action, similar to how it is implemented in bpm'online:

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

This method has a number of problems:

- despite the fact that the GPS method is more accurate, the time for receiving such data can be quite long (up to 10-15 minutes).

- the waiting time for receiving the response should be increased, i.e. the timeout parameter in the code above will need to be set to more than 1 minute (60,000 ms).

- this method may decrease your Android device's battery life.

Like 0

Like

Share

1 comments

hi Kirill Potapkin,



Could you please assist with where to add this schema?

1. When does this schema gets triggered?

2. what is geo.updatelocation method performs?

3. How to capture the GPS co-ordinates and store it in a field in custom section.

 

 

BR,

Bhoobalan Palanivelu.

Show all comments