Question

Regarding the error when working with the mobile version of the application:

HTTP Error 405.0 - Method Not Allowed. The page you are looking for cannot be displayed because an invalid method is used (HTTP command).

Full bug report:

Type: Terrasoft.ServerException

Message: Request for server returned error

<legend> Most likely reasons: </ legend> \ n <ul> \ t <li> The request sent to the web server used the HTTP command that was not allowed by the module configured to process the request. </ li> \ t < li> A request was sent to the server containing an invalid HTTP command. </ li> \ t <li> This request for static content contains an HTTP command other than GET and HEAD. </ li> \ t <li> The request was sent to the virtual directory using the HTTP POST command; meanwhile, the default document is a static file that is not compatible with HTTP commands other than the GET and HEAD. </ li> </ ul> \ n </ fieldset> \ n </ div> \ n <div class = \ "content-container \"> \ n <fieldset> <legend> What can be done: </ legend> \ n <ul> \ t <li> Check the list of commands activated for the module handler with this request and ensure that this command can easily reach the website. </ li> \ t <li> View the IIS log file and determine which command cannot be used in the request. </ li> \ t <li> Create a trace rule to track failed requests for this HTTP status code. For more information about creating a trace rule for failed requests, click Most likely causes: The request sent to the web server used the HTTP command that was not allowed by the module configured to process the request. A request was sent to the server containing an invalid HTTP command. This static content request contains an HTTP command other than GET and HEAD. A request was sent to the virtual directory using an HTTP POST command; meanwhile, the default document is a static file that is not compatible with HTTP commands other than the GET and HEAD. Possible solutions: Check the list of commands activated for the module handler where this request was sent, and make sure that this command can reach the website. Review the IIS log file and determine which command cannot be used in the request. Create a trace rule to track back requests for this HTTP status code. For more information on creating a trace rule for failed requests, click here.

Solution

This error may occur due to incorrect IIS settings on the server.

To fix this, add the following code to the web.config file:

<system.webServer>
    <modules>
        <remove name="WebDAVModule" />
    </modules>
    <handlers>
        <remove name="WebDAV" />
    </handlers>
</system.webServer>

 

Like 0

Like

Share

0 comments
Show all comments

Symptoms

When I export big data volumes, in 30 seconds I get an error.

Cause

The cause of the timeout error, when exporting big volumes of data or big number of nested queries, is the Ext.Ajax component, whose standard timeout is 30 seconds.

The server request waits for this exact time, and if the file is not generated, the client declines waiting.

Solution

The possible solution might be extending the timeout period in the bpm'online "core" (...\Terrasoft.WebApp\Resources\ui\Terrasoft\core\). The ajax-provider.js file in the "request: function(config) { …" function, add the following code strings:

Ext.Ajax.timeout = 90000;
Ext.override(Ext.data.proxy.Server, { timeout: Ext.Ajax.timeout });
Ext.override(Ext.data.Connection, { timeout: Ext.Ajax.timeout });

If a permission error occurs, increase the number of list records in the web config:

 

Like 0

Like

Share

0 comments
Show all comments
  1. Add your *.dll file to configuration on "External assemblies" tab (for example barcode.dll):

  2. Get Namespace of your *.dll file.

    a) You can find it in documentation to library;

    b) If you don't have documentation you can use ildasm.exe (IL Disassembler). This tool is automatically installed with Visual Studio. To run the tool, use the Developer Command Prompt (or the Visual Studio Command Prompt in Windows 7). For more information, see Command Prompts.



     

  3. Add using to your schema

    a) For source code:





    b) For Business process:







     
  4. Now you can use methods from library in your code. 

     

    Example for barcode.dll

    string temp = BarcodeConverter128.StringToBarcode("Test string");

     

Like 0

Like

Share

6 comments

Hi,

I tried to do so with a library I uploaded and I'm getting the following compilation errors on the script

 

The type or namespace name 'PdfApi' could not be found (are you missing a using directive or an assembly reference?)

 

Thanks,

Raz

Raz Guille Rosman,

Hello,

 

Please share the process schema and with the library you've uploaded.

 

Thank you in advance!

 

Best regards,

Oscar

Oscar Dylan,

Hi Oscar,

 

I attached  a screen shot of the process and a link to the libraryhttps://www.dropbox.com/s/2lplgni2wsi5piy/Aspose.PDF.dll?dl=0

 

This is the code inside the script task:

PdfApi api = new PdfApi("11d276990520041f6cda09531e25aabb", "9568f0a0-cf77-4836-97d2-fd1389338080");

return true;

Raz Guille Rosman,

 

Hello Raz,

 

Thank you for providing the dll file!

 

The namespace of the file is no Aspose.PDF, but Aspose.Pdf:

And even after applying a correct namespace name this error comes up:

And indeed I couldn't locate the type or namespace with such a name in the dll. Please contact the developer of this library and ask him\her how to correctly call the method you need.

 

Best regards.

Oscar

Thank you, I'll check it out.

It's a library I downloaded from Aspose website

Show all comments

Let's suppose you have created a new web-service UsrCustomService.svc and you need to disable cookie authentication. Here is the

list of changes to be done:

Make changes to the site folder

  • In folder \Terrasoft.WebApp\ServiceModel\ create file UsrCustomService.svc with text:
<%@ ServiceHost Language="C#" Debug="true" Service="Terrasoft.Configuration.UsrCustomService" %>

Important! Specify full service name including the namespace

  • In file \Terrasoft.WebApp\ServiceModel\http\services.config and \Terrasoft.WebApp\ServiceModel\https\services.config add section:
<service name="Terrasoft.Configuration.UsrCustomService">
    <endpoint name="UsrCustomServiceEndPoint"
        address=""
        binding="webHttpBinding"
        behaviorConfiguration="RestServiceBehavior"
        bindingNamespace="http://Terrasoft.WebApp.ServiceModel"
        contract="Terrasoft.Configuration.UsrCustomService" />
</service>
  • In file \Terrasoft.WebApp\Web.config in the  section  to the value of the key AllowedLocations append ;ServiceModel/UsrCustomService.svc and add next section into configuration section:
<location path="ServiceModel/UsrCustomService.svc">
  <system.web>
    <authorization>
      <allow users="*" />
    </authorization>
    <httpRuntime requestValidationMode="2.0" executionTimeout="28800" /><!--For incoming message in 'Raw' format-->
    <pages validateRequest="false" />
  </system.web>
</location>

Example different requests

UsrCustomService.cs

namespace Terrasoft.Configuration
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Web;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.ServiceModel.Activation;
    using Terrasoft.Common;
    using Terrasoft.Core;
 
    #region Class: UsrCustomService
 
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class UsrCustomService {
 
        #region Constructors
 
        public UsrCustomService() {
        }
 
        public UsrCustomService(HttpContextBase httpContext, UserConnection userConnection) {
            _httpContext = httpContext;
            _userConnection = userConnection;
        }
 
        #endregion
 
        #region Properties: Protected
 
        private const int StreamReaderBufferSize = 65536;
 
        private HttpContextBase _httpContext;
        protected virtual HttpContextBase CurrentHttpContext {
            get { return _httpContext ?? (_httpContext = new HttpContextWrapper(HttpContext.Current)); }
        }
 
        private UserConnection _userConnection;
        protected UserConnection UserConnection {
            get {
                if (_userConnection != null) {
                    return _userConnection;
                }
                _userConnection = CurrentHttpContext.Session["UserConnection"] as UserConnection;
                if (_userConnection != null) {
                    return _userConnection;
                }
                var appConnection = (AppConnection)CurrentHttpContext.Application["AppConnection"];
                _userConnection = appConnection.SystemUserConnection;
                return _userConnection;
            }
        }
        #endregion
 
        #region Methods: Private
 
        private void SetOptionsCORS() {
            CurrentHttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
            CurrentHttpContext.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
            CurrentHttpContext.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        }
 
        private void SetHeaderCORS() {
            CurrentHttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
        }
 
        private NameValueCollection ParseQueryParameters(Stream stream) {
            var rawPostData = new StringBuilder();
            char[] buffer = new char[StreamReaderBufferSize];
            int readLength = 0;
            using (StreamReader streamReader = new StreamReader(stream)) {
                while ((readLength = streamReader.ReadBlock(buffer, 0, StreamReaderBufferSize)) > 0) {
                    if (readLength < StreamReaderBufferSize) {
                        char[] bufferLast = buffer.Take(readLength).ToArray();
                        rawPostData.Append(bufferLast);
                        bufferLast = null;
                    } else {
                        rawPostData.Append(buffer);
                    }
                }
            }
            buffer = null;
            NameValueCollection queryParameters = HttpUtility.ParseQueryString(rawPostData.ToString(), Encoding.UTF8);
            rawPostData.Clear();
            return queryParameters;
        }
 
        #endregion
 
        #region Methods: Public
 
        [OperationContract]
        [WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
        public void GetWebRequestOptions() {
            SetOptionsCORS();
        }
 
        #region POST: Content-Type: "application/x-www-form-urlencoded"
 
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "UsrFormRequest", ResponseFormat = WebMessageFormat.Json)]
        public ConfigurationServiceResponse UsrFormRequest(Stream stream) {
            SetHeaderCORS();
            ConfigurationServiceResponse response = new ConfigurationServiceResponse();
            if (UserConnection == null || stream == null) {
                response.Success = false;
                return response;
            }
            try {
                NameValueCollection queryParameters = ParseQueryParameters(stream);
                ///TODO: your code here
            } catch (Exception e) {
                response.Exception = e;
            }
            return response;
        }
 
        #endregion
 
        #region POST: Content-Type: "application/json"
 
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "UsrJsonRequest",
            RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public ConfigurationServiceResponse UsrJsonRequest(JsonDataRequest request) {
            SetHeaderCORS();
            ConfigurationServiceResponse response = new ConfigurationServiceResponse();
            if (UserConnection == null || request == null) {
                response.Success = false;
                return response;
            }
            try {
                ///TODO: your code here
            } catch (Exception e) {
                response.Exception = e;
            }
            return response;
        }
 
        #endregion
 
        #region GET
 
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "UsrGetRequest/{request}/", ResponseFormat = WebMessageFormat.Json)]
        public ConfigurationServiceResponse UsrGetRequest(string request) {
            SetHeaderCORS();
            ConfigurationServiceResponse response = new ConfigurationServiceResponse();
            if (UserConnection == null || string.IsNullOrEmpty(request)) {
                response.Success = false;
                return response;
            }
            try {
                ///TODO: your code here
            } catch (Exception e) {
                response.Exception = e;
            }
            return response;
        }
 
        #endregion
 
        #endregion
 
    }
 
    #endregion
 
    #region Class: JsonDataRequest (Example)
 
    [DataContract]
    public class JsonDataRequest {
 
        [DataMember(Name = "first_name")]
        public string FirstName { get; set; }
 
        [DataMember(Name = "last_name")]
        public string LastName { get; set; }
 
    }
 
    #endregion
 
}

 

Like 0

Like

Share

2 comments

I have a problem with CORS with cookies value "samesite". How I can fix it?

Daer Nataliia, 

Please see the article below on how to deal with CORS: 

https://community.creatio.com/articles/web-service-available-without-authorization-cors

Show all comments

Question

How can I get information form an account page via the [Addresses] detail? For example, I need to call a function or retrieve information from a field (e.g., name) or learn the field status (e.g., enabled).

Answer

To connect a detail with a page, use the message mechanism. You can use base messages or create custom ones (you will have to create a replacing module in this case).

For example, you can execute a ReloadDetail message subscription in the implementation of the init() method of the detail code as follows:

this.methods.init = function() {
 ...
 this.sandbox.subscribe("ReloadDetail", function(customArgs) {
 // executing actions with function arguments
 }, [this.sandbox.id]);
}

Further, you can publish the message in the parent page code by an action:

this.methods.myAction = function() {
 Terrasoft.each(this.entitySchemaInfo.details, function(detailInfo) {
 if (detailInfo.name === "addresses") {
 sandbox.publish("ReloadDetail", this, [detailInfo.moduleId]);
 }
 }, this);
}

Passing this as a parameter when publishing enables accessing the page object in a detail as well as accessing all its attributes and methods, etc. – this object will be passed in the customArgs parameter. You can pass a set of only the needed data instead of this.

You do not need to create ReloadDetail, it is already contained in the base modules of pages and details.

We recommend receiving the values of needed conditions before this moment, since after you perform getCustomItemView(), the control will be passed over to the base detail module (DetailModule), where the model is linked to the view and detail rendering is performed.

Like 0

Like

Share

0 comments
Show all comments

Symptoms

Type: Terrasoft.SourceCodeException

Message: SyntaxError: Unexpected identifier 'Invoices'. Expected '}' to end a object literal.

Additional information:

Script: file:///var/mobile/Containers/Data/Application/5971FB51-E199-46E3-8004-22E3199C246B/Documents/BPMonline700/AppStructure/rev_1/src/UsrInvoicesType.js?hash=c033cb8c-ace4-4766-b865-88fc6882274f%0D%0A%09Line:8 

Cause

The title of the Activity includes double quotation marks, but at the present moment, the system does not know how to process them.

Solution

The ability to work with double quotation marks will be implemented in the next versions of bpm'online. At the moment, a workaround is the following:

1. Go to the configuration

2. Open the UsrInvoicesType schema

3. Change its caption so that it does not have double quotation marks

For example, Section object type 'Invoices'

Necessary conditions

Admin rights.

Like 0

Like

Share

0 comments
Show all comments

Question

In version 7.8, details do not work correctly in a detail.

Answer

The parent Id is not passed over from detail to a detail, if useRelationship is not specified. If you declare another detail in a detail, specify: "useRelationship": true

"UsrDetail2": {
    "schemaName": "UsrSchema2Detail",
    "entitySchemaName": "UsrDetail2",
    "filter": {
        "detailColumn": "UsrDetail1",
        "masterColumn": "Id"
    },
    "useRelationship": true
}

Another detail's connection column specified in detailColumn, will be populatd with the value from the parent detail (the first detail) page, from the collumn, specified in masterColumn. The column types should match.

Do not forget to set up columns in the second detail. By default, a detail of a detail does not contain any columns.

Like 0

Like

Share

0 comments
Show all comments

Question

In the mobile app, I only see a single opportunity created by the Supervisor user. Why I do not see the rest?

Answer

In bpmonline sales omnichannel (the "Opportunities" section), we use the following base logic:

1) While synchronizing, the mobile app only downloads opportunity records for the current user.

This is done to save memory and reduce synchronization time.

2) The data is filtered by the "Opportunity stage.Final = FALSE" condition in the “Opportunities” section of the mobile app.

This is done for convenience - the user only sees all his incomplete tasks.

Note: If the "Stage" field is empty, the opportunity will not be displayed at all. 

At the same time, such opportunities are stored in the mobile application and can be accessed from other sections (for example, from the “Activities” section to view the related opportunity record).

Like 0

Like

Share

0 comments
Show all comments

Question

The profile completion in accounts displays incorrectly (thousands instead of %). As a solution, we were recommended resaving each record (which indeed helps), but we have more than 5000 accounts – resaving is not a good option for us.

Answer

The record is updated upon opening the page as a result of calling the GetRecordCompleteness() method of the CompletenessService service.

You can get all records for the further processing from the browser console. For this, execute:

var esq = Ext.create("Terrasoft.EntitySchemaQuery", {rootSchemaName: "Account"});
esq.addColumn("Id");
esq.getEntityCollection(function(result) {
   var items = null;
   if (result.success) {
      items = result.collection;
      document.testResult = items;
      console.log("testResult added");
   }
}, this);

After this, call the service method for every record (it will take some time).

document.iter = 0;
document.myLoop = function() {
    var item = document.testResult.collection.items[document.iter];
    setTimeout(function () {  
      // ---------
      console.log(item.values.Id);
      var config = {
       recordId: item.values.Id,
       schemaName: "Account"
      };
      require(["ServiceHelper"], function(ServiceHelper) {
       ServiceHelper.callService("CompletenessService",
        "GetRecordCompleteness",
         function(response) {
         },
         config,
       this);
      });
      // ---------  
      document.iter++;                  
      if (document.iter < document.testResult.collection.items.length) {         
         document.myLoop();            
      }                       
   }, 1000)
};
document.myLoop();

 

Like 0

Like

Share

0 comments
Show all comments

Question

How can I create a ComboBox and populate it with values by developer means?

Answer

Example of a code:

define("CasePage", ["CasePageResources", "terrasoft"],
    function(resources, Terrasoft) {
    return {
        entitySchemaName: "Case",
        details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
        attributes: {
            "myEnum": {
                "dataValueType": Terrasoft.DataValueType.ENUM,
                "type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                "caption": "myEnum"
            },
            "myList": {
                "dataValueType": Terrasoft.DataValueType.ENUM,
                "type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                "isCollection": true
            }
        },
        diff: /**SCHEMA_DIFF*/[
            {
                "operation": "insert",
                "name": "myEnum",
                "values": {
                    "caption": "myEnum",
                    "dataValueType": this.Terrasoft.DataValueType.ENUM,
                    "bindTo": "myEnum",
                    "layout": { "colSpan": 24, "rowSpan": 1, "column": 0, "row": 4 },
                    "controlConfig": {
                        "className": "Terrasoft.ComboBoxEdit",
                        "list": {
                            "bindTo": "myList"
                        },
                        "change": {
                            "bindTo": "onMyValueChange"
                        },
                        "prepareList": {
                            "bindTo": "prepareMyList"
                        }
                    }
                },
                "parentName": "SolutionTab_gridLayout",
                "propertyName": "items",
                "index": 1
            }
        ]/**SCHEMA_DIFF*/,
        methods: {
            onPageInitialized: function(callback, scope) {
                if (!this.get("myList")) {
                    this.set("myList", this.Ext.create("Terrasoft.Collection"));
                }
 
                if (callback) {
                    callback.call(scope || this);
                }
            },
            onEntityInitialized: function() {
                this.callParent(arguments);
 
                // and just for debug:
                document.scope = this;
            },
            prepareMyList: function(filter, list) {
                if (list === null) {
                    return;
                }
                list.clear();
                var columns = {};
 
                var value1 = {
                    displayValue: "a123",
                    value: "1"
                };
                var value2 = {
                    displayValue: "b234",
                    value: "2"
                };
                var value3 = {
                    displayValue: "c345",
                    value: "3"
                };
 
                columns[1] = value1;
                columns[2] = value2;
                columns[3] = value3;
 
                list.loadAll(columns);
            },
            onMyValueChange: function(val) {
                if (val && val.displayValue) {
                    console.log("you pick: ", val.displayValue);
                }
            }
        },
        rules: {}
    };
});

 

Like 0

Like

Share

0 comments
Show all comments