Question

How do I configure the frequency of automatic data synchronization in a mobile application?

Answer

The mobile application supports three types of synchronization:



Offline - to perform synchronization, you must click the sync button.

Offline synchronization in the background - starts when the bpm’online mobile application is minimized and only if the “Automatic synchronization” setting corresponds to the current status of the Internet connection.

Online - synchronization occurs during every interaction with a record in the mobile appication.

About filters that apply to displayed activities:

  • Activity must not be closed
  • Non-email activity
  • The user of the mobile application is in the activities.

Also, the filters of the mobile application interface are applied:

Activity date - depending on the filter set by date

"Display in schedule" checkbox

Like 0

Like

Share

0 comments
Show all comments

Question 

I have a problem with uploading images after adding the standard functionality of "Notes". Notes are added to a detail. A separate object is created for the detail. Notes are added to the detail page schema as follows: the text is saved, images are not even uploaded. The insertImagesToNotes  method is not executed. Why?

Answer

The base detail, which all the rest of details are inherited from, does not have the necessary attributes, methods and mixins. Unlike pages that are inherited from BaseModulePageV2.

You can fix this by viewing at what has been implemented in BaseModulePageV2 and reproducing it in your detail. Create the detail object based on Base object with notes (Base) and create a detail based on this object via the detail wizard.

Add the following in the configurator page schema:

1. Dependency of requirejs from NotesUtilities ;

2. The following attribute:

attributes: {
    "NotesImagesCollection": {dataValueType:Terrasoft.DataValueType.COLLECTION}
},

3. The mixin:

mixins: {
    NotesUtilities: "Terrasoft.NotesUtilities"
},

4. The methods:

methods: {
        onNotesImagesUploadComplete: function() {
                this.hideBodyMask();
                this.updateFileDetail();
        },
        onNotesImagesUpload: function() {
                this.showBodyMask();
        },
        init: function(callback, scope) {
                this.callParent(arguments);
               this.mixins.NotesUtilities.initNotesImagesCollection.call(this);
        }
},

5. The notes field in the diff property:

{
        "operation": "insert",
        "parentName": "Header",
        "propertyName": "items",
        "name": "Notes",
        "bindTo": "Notes",
        "values": {
                contentType: Terrasoft.ContentType.RICH_TEXT,
                "layout" : {column: 0, row: 1, colSpan: 24},
                "controlConfig": {
                        "imageLoaded": {
                                "bindTo": "insertImagesToNotes"
                        },
                        "images": {
                                "bindTo": "NotesImagesCollection"
                        }
                }
        },
        "index": 1
}

The test schema code for the detail edit page:

define("UsrUsrMyDetail1Page", ["NotesUtilities"], function() {
	return {
		entitySchemaName: "UsrMyDetail",
		details: {},
		attributes: {
			"NotesImagesCollection": {dataValueType: Terrasoft.DataValueType.COLLECTION}
		},
		mixins: {
			NotesUtilities: "Terrasoft.NotesUtilities"
		},
		diff: [{
			"operation": "insert",
			"name": "UsrIntbcb7788a-2890-4358-bff3-102e82ea7889",
			"values": {
				"layout": {
					"colSpan": 12,
					"rowSpan": 1,
					"column": 0,
					"row": 0,
					"layoutName": "Header"
				},
				"labelConfig": {},
				"enabled": true,
				"bindTo": "UsrInt"
			},
			"parentName": "Header",
			"propertyName": "items",
			"index": 0
		},
		{
			"operation": "insert",
			"parentName": "Header",
			"propertyName": "items",
			"name": "Notes",
			"bindTo": "Notes",
			"values": {
				contentType: Terrasoft.ContentType.RICH_TEXT,
				"layout" : {column: 0, row: 1, colSpan: 24},
				"controlConfig": {
					"imageLoaded": {
						"bindTo": "insertImagesToNotes"
					},
					"images": {
						"bindTo": "NotesImagesCollection"
					}
				}
			},
			"index": 1
		}],
		methods: {
			onNotesImagesUploadComplete: function() {
				this.hideBodyMask();
				this.updateFileDetail();
			},
			onNotesImagesUpload: function() {
				this.showBodyMask();
			},
			init: function(callback, scope) {
				this.callParent(arguments);
				this.mixins.NotesUtilities.initNotesImagesCollection.call(this);
			}
		},
		rules: {}
	};
});

 

Like 0

Like

Share

0 comments
Show all comments

Question

How can I filter a field by the "Exists " filter with a parameter (another field value)?

Answer

Example of implementation the "Exists " filter:

var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
    "rootSchemaName": "Account"
});
// add the request columns
esq.addColumn("Id");
...
// filtering condition for using inside of "exists"
// searchValue - value for comparing with the SearchNumber column
var subFilters = Terrasoft.createFilterGroup();
subFilters.addItem(Terrasoft.createColumnFilterWithParameter(
    Terrasoft.ComparisonType.EQUAL, "SearchNumber", searchValue));
// add the exists-filter with a condition to the esq filter collection
var filters = esq.filters;
filters.add(Terrasoft.createExistsFilter("[AccountCommunication:Account:Id].Id", subFilters));
//receive the request value
esq.getEntityCollection(function(result) {
...
}, this);

As a result, the following request will be sent to the server:

SELECT Id, ... FROM Account
WHERE EXISTS 
(SELECT
[SubAccountCommunication].[Id] [Id]
FROM
[dbo].[AccountCommunication] [SubAccountCommunication] WITH(NOLOCK)
WHERE
[SubAccountCommunication].[AccountId] = [Account].[Id]
AND [SubAccountCommunication].[SearchNumber] = @P1
)

The @P1 parameter will store the searchValue value passed over to the filtering condition.

Like 1

Like

Share

0 comments
Show all comments

Question

How can I execute an SQL-query (reading, adding, deleting) in the database On-demand?

It can be useful if a user does not have access to database but needs to read or add some data in the table.

Answer

Import the schema from the attached file. Publish and run it.

File attachments
Like 0

Like

Share

0 comments
Show all comments

Case

Enable approval functionality for a new section

Solution

1. Create a new object for the [Approvals] custom section. The detail object name is generated from the section object name + Visa. For example, for the UsrInnerRequest  section, the object name will be UsrInnerRequestVisa. When creating the object, ensure inheriting from the [BaseVisa] object, add a field for connecting to the section, other parameters should be configured similar to the [OrderVisa] object. 

The UsrInnerRequest object should be managed by records.

2. Enable approval functionality for the custom section page. Namely, migrate all elements from the [OrderPageV2] order page schema to the custom section page by the Visa keyword.

3. Enable approving in the custom section list. Namely, migrate all elements from the [OrderSectionV2] order section list schema to the custom section list schema by the Visa key word.

4. Copy the "Receiving order approval" subprocess and change the Order and Read data parameters, as well as filtering of elements from the [Order] section to the custom section object. The subprocess title should look as follows: section name + VisaBaseSubprocess.

5.Copy the "Order approval" process and change the Order and Read data parameters, element filtering and the link to subprocess for the relevant values. The process title should look as follows: section name + VisaProcess. The elements of sending notifications should be changed for the new sending element.

6. Add a new "[custom section name] Approval process"  system setting with a link to the process specified in item 5. See the setup parameters in the "Order approval process" system setting.

To display approvals on the communication panel:

1. Copy the [OrderVisaNotificationProvider] schema and rename it for the Section name + VisaNotificationProvider. By the Order keyword, replace it in the schema for the name of the custom section object. The titles of the [Orders] section fields should be replaced by the corresponding fields of the custom section.

2. Register the previously added schema with the 0 type by a script in the [Notification Provider] table (the [Lookup] does not enable saving a record with a 0 type):

insert into NotificationProvider (ClassName, Type)
values ('Terrasoft.Configuration.UsrInnerRequestVisaNotificationProvider','0')

 

Like 2

Like

Share

0 comments
Show all comments

1) Create client module

define("GlbHtmlEditModule", ["ext-base", "terrasoft", "HtmlEditModule"], function(Ext, Terrasoft) {
    Ext.define("Terrasoft.controls.GlbHtmlEdit", {
        extend: "Terrasoft.HtmlEdit",
        alternateClassName: "Terrasoft.GlbHtmlEdit",
 
        tplSignature: "<br><div><span style=\"color:#7f2910;\"><i>{0}: {1}</i></span><hr></div>",
 
        signature: false,
 
        setSignature: function(value) {
            if (this.signature === value) {
                return;
            }
            this.signature = value;
        },
 
        onContentDom: function() {
            this.callParent(arguments);
            this.setSignature(false);
            var editor = this.editor;
            if (editor) {
                var editorDocument = this.editor.document;
                if (editorDocument) {
                    var el = editorDocument.$;
                    Ext.EventManager.on(el, "keypress", this.onKeyPress, this);
                }
            }
        },
 
        destroy: function() {
            var editor = this.editor;
            if (editor) {
                var editorDocument = this.editor.document;
                if (editorDocument) {
                    var el = editorDocument.$;
                    Ext.EventManager.removeListener(el, "keypress", this.onKeyPress, this);
                }
            }
            this.callParent(arguments);
        },
 
        onKeyPress: function(e) {
            if (!this.enabled || this.readonly) {
                return;
            }
            if (!this.signature && !e.isNavKeyPress() && !e.isSpecialKey()) {
                this.setSignature(true);
                var editor = this.editor;
                var selection = editor.getSelection();
                var ranges = selection.getRanges();
                var range = ranges[0];
                var currentContact = Terrasoft.SysValue.CURRENT_USER_CONTACT.displayValue;
                var date = new Date();
                var culture = Terrasoft.SysValue.CURRENT_USER_CULTURE ?
                    Terrasoft.SysValue.CURRENT_USER_CULTURE.displayValue : "";
                var signatureHtml = Ext.String.format(this.tplSignature, currentContact,
                    date.toLocaleString(culture));
                var signatureNode = CKEDITOR.dom.element.createFromHtml(signatureHtml);
                range.deleteContents();
                range.select();
                range.insertNode(signatureNode);
                var cursorNode = range.getNextNode();
                range.selectNodeContents(cursorNode);
                selection.selectRanges(ranges);
            }
        }
    });
});

 

2) On the poge add dependency GlbHtmlEditModule and in diff section change className for your field (Example: Field Notes on Contact page):

{
    "operation": "merge",
    "parentName": "NotesControlGroup",
    "propertyName": "items",
    "name": "Notes",
    "values": {
        "className": "Terrasoft.GlbHtmlEdit"
    }
}

 

3) Result

Like 1

Like

Share

0 comments
Show all comments
package cherniak.bpmonline.com;
import java.io.OutputStream;
import java.net.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Attr;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
/**
* OData insert request for bpmonline
*
*/
public class App
{
    private static final String SERVICE_URL = "http://int-                web/Amdocs_T/0/ServiceModel/EntityDataService.svc/";
    private static final String AUTH_URL = "http://int-web/Amdocs_T/ServiceModel/AuthService.svc/Login";
    private static final String DS = "http://schemas.microsoft.com/ado/2007/08/dataservices";
    private static final String DSMD = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
    private static final String ATOM = "http://www.w3.org/2005/Atom";
    public static void main( String[] args ) throws Exception
    {
        CookieManager msCookieManager = new CookieManager();
        CookieHandler.setDefault(msCookieManager);
        if(GetAuthCookie("Supervisor", "Supervisor")) {
            CreateBpmEntityByOdataHttpExample(msCookieManager);
        }
    }
    public static boolean GetAuthCookie(String login, String password) {
        try{
            URL urlAuth = new URL(AUTH_URL);
            HttpURLConnection connection1Auth = (HttpURLConnection) urlAuth.openConnection();
            connection1Auth.setDoOutput(true);
            connection1Auth.setRequestMethod("POST");
            connection1Auth.setRequestProperty("Content-Type","application/json");
            String authJson = String.format("{\"UserName\": \"%s\", \"UserPassword\":\"%s\"}", login, password);
            byte[] outputBytes = authJson.getBytes("UTF-8");
            OutputStream os = connection1Auth.getOutputStream();
            os.write(outputBytes);
            os.close();
            int responseCode = connection1Auth.getResponseCode();
            return responseCode == 200;
        } catch (Exception e) {
            return false;
        }
    }
    public static void CreateBpmEntityByOdataHttpExample(CookieManager manager) {
        try{
            //Create xml document
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.newDocument();
            Element entry = doc.createElement("entry");
            Attr attrAtom = doc.createAttribute("xmlns");
            attrAtom.setValue(ATOM);
            entry.setAttributeNode(attrAtom);
            doc.appendChild(entry);
 
            Element content = doc.createElement("content");
            Attr attrType = doc.createAttribute("type");
            attrType.setValue("application/xml");
            content.setAttributeNode(attrType);
            entry.appendChild(content);
 
            Element properties = doc.createElement("properties");
            Attr attrMetadata = doc.createAttribute("xmlns");
            attrMetadata.setValue(DSMD);
            properties.setAttributeNode(attrMetadata);
            content.appendChild(properties);
 
            //Set Name of Contact
            Element name = doc.createElement("Name");
            Attr attrProp = doc.createAttribute("xmlns");
            attrProp.setValue(DS);
            name.setAttributeNode(attrProp);
            name.appendChild(doc.createTextNode("Test Person"));
            properties.appendChild(name);
 
            //Set Dear of Contact
            Element dear = doc.createElement("Dear");
            Attr attrOppo = doc.createAttribute("xmlns");
            attrOppo.setValue(DS);
            dear.setAttributeNode(attrOppo);
            dear.appendChild(doc.createTextNode("Mister"));
            properties.appendChild(dear);
 
            doc.setXmlStandalone(true);
 
            //Send insert request
            URL url = new URL(SERVICE_URL + "ContactCollection/");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept", "application/atom+xml");
            connection.setRequestProperty("Content-Type","application/atom+xml;type=entry");
 
            //Add BPMCSRF
            for(HttpCookie cookie : manager.getCookieStore().getCookies()) {
                if(cookie.getName().equals("BPMCSRF")) {
                    connection.setRequestProperty("BPMCSRF", cookie.getValue());
                }
            }
            OutputStream os = connection.getOutputStream();
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(new DOMSource(doc), new StreamResult(os));
            os.close();
            int responseCode = connection.getResponseCode();
            System.out.println(responseCode);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

 

Like 0

Like

Share

0 comments
Show all comments

Question

How to implement a search for multiple columns in a section?

For example, in the Contacts section, search by full name and zip code (the column in the Contact object).

Answer

- Launch the mobile app wizard

- Open default workplace (“Main workplace”)

- Go to section settings

- Click "Save"

- Create ClientUnit schema

- Add the following code to it:

Terrasoft.sdk.GridPage.setSearchColumns("Contact", [“Name”, “Zip”]);

- Open MobileApplicationManifestDefaultWorkplace in the Custom package

- Register your schema for the “Contacts” section:

{
    “Models”: {
        “Contact”: {
            "PagesExtensions": [
                "Name_of_the_schema"
            ]
        }
    }
}

 

Like 0

Like

Share

0 comments
Show all comments

Question

Can we set up displaying of a post date in the Feed without specifying "today, yesterday, the day before yesterday"?

Answer

Override the getCreatedOnText() method of the SocialFeedUtilities module. Since you cannot extend modules in bpm'online (you can only replace them completely), create a replacing client module in the custom package and specify SocialFeedUtilities as the parent modue. Copy the text from a similar module in the ESN package (the "Source code and "LESS" tabs) and change the text of the getCreatedOnText method to:

getCreatedOnText: function() {
    var cultureSetting = Terrasoft.Resources.CultureSettings;
    var value = this.get("CreatedOn");
    if (value) {
        var datePart = Ext.Date.dateFormat(value, cultureSetting.dateFormat);
        var timePart = Ext.Date.dateFormat(value, cultureSetting.timeFormat);
        return Ext.String.format("{0} {2} {1}", datePart, timePart,
            FormatUtilsResources.localizableStrings.In);
        }
    return "";
}

At the very beginning of the text, add the dependency of the module from FormatUtilsResources to have access to the FormatUtilsResources.localizableStrings.In localized string of the FormatUtils module:

define("SocialFeedUtilities", ["FormatUtilsResources", "ESNFeedUtils", "ESNFeedModuleResources", 
    "FormatUtils", "ESNConstants", "NetworkUtilities", "ModalBox", "ServiceHelper", "MaskHelper", 
    "performancecountermanager", "css!SocialFeedUtilities"],
    function(FormatUtilsResources, ESNFeedUtils, resources, FormatUtils, ESNConstants, 
        NetworkUtilities, ModalBox, ServiceHelper, MaskHelper, performanceManager) {...

 

Like 0

Like

Share

0 comments
Show all comments

Question

How to add a standard detail to a mobile application and display a specific column in it?

Answer

1. Go to the "Mobile application wizard" (/0/Nui/ViewModule.aspx#SectionModuleV2/SysMobileWorkplaceSection)

2.  Open the required workplace ("DefaultWorkplace" by default) and click the "Set up sections" button.

3. Select the desired section, for example, "Contacts", and press the "Details setup" button

4. Add a detail:

5. Go to the "Configuration" section (/0/WorkspaceExplorerModule.aspx)

6. Add a new "Module" schema type with the name "UsrContactCareerModuleConfig"

7. Write a similar code:

Terrasoft.sdk.GridPage.setPrimaryColumn("ContactCareer", "JobTitle");
Terrasoft.sdk.RecordPage.addColumn("ContactCareer", {
        name: "JobTitle",
        position: 1
    }, "primaryColumnSet");
Terrasoft.sdk.RecordPage.removeColumn("ContactCareer", "Contact", "primaryColumnSet");

Where ContactCareer is the name of the table that corresponds to our detail;

JobTitle - the name of the column you want to display

8. Connect this schema in the "MobileApplicationManifestDefaultWorkplace" mobile application manifest: Find the block of the ContactCareer model and add our UsrContactCareerModuleConfig module to PagesExtensions.

Like that:

 

 

Like 0

Like

Share

0 comments
Show all comments