Symptoms

After I have upgraded to version 7.7.0, I get an error when receiving  the number of notifications via execution of the GetUserNotificationCount method (the RemindingsDataService service). The error message is as follows: "Cannot create an instance of Terrasoft.Configuration.BaseNotificationProvider because it is an abstract class."

Cause

The Terrasoft.Configuration.BaseNotificationProvider class name is changed for Terrasoft.Configuration.SystemNotificationProvider in the NotificationProvider table of version 7.7.0. When updating, the modification must be applied via the data setting, but this data is not set in the customer configuration for some reason.

Solution

Perform the following script on the customer base:

UPDATE [NotificationProvider]
SET
[ClassName] = 'Terrasoft.Configuration.SystemNotificationProvider',
[Type] = 2
WHERE [ClassName] = 'Terrasoft.Configuration.BaseNotificationProvider'

Necessary conditions and possible restrictions

If there is no access to the base, perform this script via the configuration.

Like 0

Like

Share

0 comments
Show all comments

This article explains how to bind two different printables together and use one click to print.

Case description:

For example, the first part of the printable should be generated as a word file and the second  printable should be generated as a PDF file. It contains information from the opportunity, which the users are not allowed to change it.

Algorithm of realization:

  1.  We need to bind two printing forms. You should create an object that will contain links to the root printable form, and additional printable.

  2. You should to create and configure two printables or use existing. You should create a lookup for printables binding and bind two printables, which will be printed together.



     
  3. You should create client replacing module for "OpportunityPageV2" and "OpportunitySectionV2" from NUI package 
  4. Insert following code in OportunityPageV2 and OpportunitySectionV2 

    define("OpportunitySectionV2", [], function() {
        return {
            entitySchemaName: "Opportunity",
            methods: {
                generatePrintForm: function(printForm) {
                    this.callParent(arguments);
                    this.generateAdditionalReports(printForm.getTemplateId(), this.getPrintRecordId() || Terrasoft.GUID_EMPTY);
                },
                getAdditionalReportsESQ: function(mainReportId) {
                    var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
                        rootSchemaName: "GlbAdditionalReport"
                    });
                    esq.addColumn("GlbAdditReport.Id", "AdditionalReportId");
                    esq.addColumn("GlbAdditReport.ConvertInPDF", "CToPdf");
                    esq.filters.add("OpportunityFilter", this.Terrasoft.createColumnFilterWithParameter(
                        this.Terrasoft.ComparisonType.EQUAL, "GlbMainReport", mainReportId));
                     
                    return esq;
                },
                generateAdditionalReports: function(rootReportId, recordId) {
                    this.showBodyMask();
                    var esq = this.getAdditionalReportsESQ(rootReportId);
                    esq.getEntityCollection(function(result) {
                        if (result.success && result.collection.getCount() > 0) {
                            result.collection.each(function(item) {
                                var data = {
                                    templateId: item.get("AdditionalReportId"),
                                    convertInPDF: item.get("ConvertInPDF"),
                                    recordId: recordId || Terrasoft.GUID_EMPTY
                                };
                                 
                                var serviceConfig = {
                                    serviceName: "ReportService",
                                    methodName: "CreateReport",
                                    data: data,
                                    timeout: 20 * 60 * 1000
                                };
                                var callback = function(response) {
                                    var key = response.CreateReportResult;
                                    this.downloadReport(item.get("AdditionalReportId"), key);
                                };
                                this.callService(serviceConfig, function(response) {
                                    callback.call(this, response);
                                }, this);
                            }, this);
                        } else {
                            return;
                        }
                    }, this);
                    this.hideBodyMask();
                }
            }
        };
    });



    !!! IMPORTANT. You should allow multiply download files in your browser.

Like 0

Like

Share

4 comments

Does it works?

Dear,

 

The provided code works properly. Please don’t forget to replace the “&&” symbols with “&&” symbols and the “>” symbols with the “>” symbol.

 

Best regards,

Norton

Would it be possible to merge these reports into one big report? instead of multiple downloads?

Gary Singh,

Unfortunately, no. Since the document's structure has to be changed and absolutely new macros created, there is no known way of the printable's auto-creating.

In the described method, we configure two printables, which were manually created with their own connections between macro tags and columns. 

Show all comments
SDK
support
cases

To lock all elements on the page you need to install package GlbPageReadOnlyMode and set up page.

  1. Initialize readOnly mode:

    init: function() {
        this.subscribeReadOnlyEvent({
            excludedDetails: [/*Here add details you want to exclude*/],
            excludedModules: [/*Here add modules you want to exclude*/],
            excludedItems: [/*Here add fields you want to exclude*/]
        });
        this.callParent(arguments);
    }

     

  2. Set up condition to lock a page:

    changeReadOnlyMode: function() {
        if (this.get("Contact")) { // If "Contact" field is filled in, then the page is locked
            this.setPageReadOnlyMode(this, true);
        } else {
            this.setPageReadOnlyMode(this, false);
        }
    }

     

Example: lock page "ContactPageV2" when "Account" field is filled in:

ContactPageV2

define("ContactPageV2", [], function() {
    return {
        entitySchemaName: "Contact",
        methods: {
            init: function() {
                this.subscribeReadOnlyEvent();
                this.callParent(arguments);
            },
            changeReadOnlyMode: function() {
                if (this.get("Account")) {
                    this.setPageReadOnlyMode(this, true);
                } else {
                    this.setPageReadOnlyMode(this, false);
                }
            }
        }
    };
});

 

Like 0

Like

Share

0 comments
Show all comments

Symptoms

In some cases, not all activities, in which the current or selected user is the owner, are displayed in the [Activities] section. Similar situation can be observed on the [Dashboards]  tab of the section.

Cause

The situation occurs, when the owner does not get into the list of participants automatically after the activity is created (manually or according to the process). In the [Activities] section, filtering is performed by this detail: only records whose [Participants] detail contains a user specified as the section "Owner" in the filter are displayed.

Solution

Correct the custom process or the activity creation logic so that the owner is added to the [Participants] detail once created. After this, add the corresponding missing participants by a script. An example of a script:

INSERT INTO [ActivityParticipant]
([Id], [ActivityId], [ParticipantId], [RoleId])
SELECT NewId(), a.[Id], a.[OwnerId], '53fc4a92-b0ea-e111-96c4-00165d094c12'
FROM [Activity] a
WHERE NOT EXISTS (
SELECT ap.[Id] FROM [ActivityParticipant] ap
WHERE ap.[ActivityId] = a.[Id]
AND ap.[ParticipantId] = a.[OwnerId]
)

 

Like 0

Like

Share

0 comments
Show all comments

Symptoms 

Type: Terrasoft.SyncException%0D%0AСообщение: В процессе синхронизации произошла ошибка%0D%0A%0D%0AТип: Terrasoft.ServerException%0D%0AMessage: Request for server returned an erro%0D%0AAdditional information: %0D%0A%09{"request":{"id":6,"headers":{"X-Terrasoft-Mobile":"true","Accept":"application/json","Content-Type":"application/json","Authorization":"Cookie","X-Requested-With":"XMLHttpRequest"},"options":{"url":"http://xxx.xxx.xxx.xxx/0/Services/ProfileService.asmx/Logout","method":"POST","jsonData":{"customData":"","doLogout":"true"},"headers":{"X-Terrasoft-Mobile":"true","Accept":"application/json","Content-Type":"application/json","Authorization":"Cookie"},"disableCaching":false,"scope":{"initialConfig":{"url":"http://xxx.xxx.xxx.xxx/0/Services/ProfileService.asmx/Logout","method":"POST","jsonData":{"customData":"","doLogout":"true"},"headers":{"X-Terrasoft-Mobile":"true","Accept":"application/json","Content-Type":"application/json","Authorization":"Cookie"},"disableCaching":false},"performanceCounter":{"startDate":"2015-06-08T12:11:51.319Z"}}},"async":true},"requestId":6,"status":500,"statusText":"Internal Server Error","responseText":"System.InvalidOperationException: Request format is invalid: application/json.\r\n   at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()\r\n   at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()\r\n","responseXML":null,"responseBytes":null}%0D%0A%0D%0A

Cause

A problem in IIS settings.

Solution

Go to the IIS settings - Handler Mappings module

Find the rules for files with * .asmx extension with the following names:

"WebServiceHandlerFactory-Integrated"

"WebServiceHandlerFactory-ISAPI-2.0_32bit"

"WebServiceHandlerFactory-ISAPI-2.0_64bit"

and delete all of them.

Like 0

Like

Share

0 comments
Show all comments
knowledge base
SDK
Q&A
support

Question

How can I add/change color in the "Color customization" section?

Answer

You can add/change the existing color in the "Color customization" section via the source at all-combined.js (…\Terrasoft.WebApp\Resources\ui\combined\all-combined.js). Use the "colors" property in "ColorMenuItem".

Please note that in this case you can only use the color code, since the application specifies that only "background-color" can be used for this property. You will not be able to insert links to images.

Like 0

Like

Share

0 comments
Show all comments

Question

How to remove the action in the mobile application and how you can sort the actions?

Answer

Approximate algorithm.



1. You need to create your own module (for example,"TestOrderRemoveMobileAccountModuleConfig")

2. To delete an action, use the following method - Terrasoft.sdk.Actions.remove: function (model, actionName)

For example:

Terrasoft.sdk.Actions.remove("Account", "addAccountAnniversary");

3. Use the following code to sort:

Terrasoft.sdk.Actions.setOrder("model ", {
    "actionName1": 0,
    "actionName2": 1,
    …,
    "actionName5": 4
});

For example:

Terrasoft.sdk.Actions.setOrder("Account", {
    "Phone": 0,
    "Email": 1,
    "Meeting": 2,
    "Terrasoft.ActionCopy": 3,
    "Terrasoft.ActionDelete": 4
});
 

4. Then connect it in the user manifest of the mobile application (available on our SDK) in the “Models” section for the “Account” object (if they are accounts) in the “PagesExtensions” section. For example:

 

"Models": {
    "Account": {
        "RequiredModels": [],
        "ModelExtensions": [],
        "PagesExtensions": [
            "TestOrderRemoveMobileAccountModuleConfig"
        ]
    },
 

Where TestOrderRemoveMobileAccountModuleConfig is an arbitrary schema name.

 

You can see the implementation of the add address logic in the MobileAccountModuleConfig schema (the action is called addAccountAddress).

Like 0

Like

Share

0 comments
Show all comments

Question

The styles for twitter and facebook icons are not applied on the [Communication options] detail after I upgrade to a new version

Answer

CommonCSSV2 replacing client module ccontaining custom styles has been found in the configuration. The point is that the base styles have slightly changed and have been added in version 7.6.0, but replacing in the custom package does not let apply these changes.

To eliminate the problem, transfer the styles from the CommonCSSV2 base module to the replacing module and add the custom styles in the end. You can also delete the text from the "Source code" module tab - the styles contained thereon will not be applied.

Like 0

Like

Share

0 comments
Show all comments

Error message

Terrasoft.Common.ReflectionUtilities FindTypeByShortName - Could not load file or assembly 'SharpSvn.dll' or one of its dependencies. The specified module could not be found.

System.IO.FileNotFoundException: Could not load file or assembly 'SharpSvn.dll' or one of its dependencies. The specified module could not be found.

File name: 'SharpSvn.dll'

at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)

at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)

at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)

at System.Reflection.Assembly.LoadFrom(String assemblyFile)

at Terrasoft.Web.Common.AssemblyResolver.FindAssemblyByProcessRunMode(String requestingAssemblyName, String searchSubDirectory)

at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)

 

Solution

Install Microsoft Visual C++ 2010 Redistributable

Like 1

Like

Share

0 comments
Show all comments

Case description:

We want to show different printables for different opportunity stages.

Algorithm of realization:

  1.  Create replacing client modules for OpportunityPageV2 and OpportunitySectionV2.
  2. Add message that will refresh print button when we work in CombinedMode and add event handler which run when opportunity stage was changed.
    1. OpportunityPageV2

      
      define("OpportunityPageV2", ["SysModuleReport"], function (SysModuleReport) {
          return {
              entitySchemaName: "Opportunity",
              details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
              attributes: {
                  "Stage": {
                      "onChange": "onStageChanged"
                  }
              },
              messages: {
                  "PrintButtonFilterMessage": {
                      mode: Terrasoft.MessageMode.PTP,
                      direction: Terrasoft.MessageDirectionType.PUBLISH
                  }
              },
              methods: {
                  printButtonFilterPublishMessage: function () {
                      return this.sandbox.publish("PrintButtonFilterMessage", this.get("Stage").value, ["key"]);
                  },
                  onStageChanged: function () {
                      this.printButtonFilterPublishMessage();
                  }
              },
              diff: /**SCHEMA_DIFF*/[]/**SCHEMA_DIFF*/,
              rules: {},
              businessRules: /**SCHEMA_BUSINESS_RULES*/{}/**SCHEMA_BUSINESS_RULES*/
          };
      });

       

    2. OpportunitySectionV2

      define("OpportunitySectionV2", [], function () {
          return {
              messages: {
                  "PrintButtonFilterMessage": {
                      mode: Terrasoft.MessageMode.PTP,
                      direction: Terrasoft.MessageDirectionType.SUBSCRIBE
                  }
              },
              methods: {
                  init: function () {
                      this.callParent(arguments);
                      this.sandbox.subscribe("PrintButtonFilterMessage", this.onPrintButtonFilterMessage, this, ["key"]);
                  },
                  onPrintButtonFilterMessage: function (args) {
                      this.set("StageId", args);
                  }
              },
              diff: []
          };
      });

       

  3. Override preparePrintFormsMenuCollection method in both pages and add calling of initCardPrintForms() and initSectionPrintForms() on stage changing and PrintButtonFilterMessage handling.
    1. OpportunityPageV2 

      define("OpportunityPageV2", ["SysModuleReport"], function (SysModuleReport) {
          return {
              entitySchemaName: "Opportunity",
              details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
              attributes: {
                  "Stage": {
                      "onChange": "onStageChanged"
                  }
              },
              messages: {
                  "PrintButtonFilterMessage": {
                      mode: Terrasoft.MessageMode.PTP,
                      direction: Terrasoft.MessageDirectionType.PUBLISH
                  }
              },
              methods: {
                  preparePrintFormsMenuCollection: function (printForms) {
                      var stage = this.get("Stage");
                      printForms.eachKey(function (key, item) {
                          if (!item.get("Caption")) {
                              item.set("Caption", item.get("NonLocalizedCaption"));
                          }
                          item.set("Tag", key);
                          if (item.get("TypeColumnValue")) {
                              item.set("Visible", { bindTo: "getPrintMenuItemVisible" });
                          }
                          //Here is your logic for filtering of printables
                          /*************************************************************************/
                          if (stage !== undefined) {
                              if (stage.value === "423774cb-5ae6-df11-971b-001d60e938c6") {
                                  if (key === "0d8c28ce-9794-42be-8427-3d5d60e60c1f") {
                                      item.set("Visible", false);
                                  }
                                  else {
                                      item.set("Visible", true);
                                  }
                              } else if (stage.value === "fb563df2-5ae6-df11-971b-001d60e938c6") {
                                  if (key === "c80094c5-2513-4857-b5da-4b355aed8c10") {
                                      item.set("Visible", false);
                                  }
                                  else {
                                      item.set("Visible", true);
                                  }
                              } else {
                                  item.set("Visible", true);
                              }
                          }
                          /*************************************************************************/
                      }, this);
                  },
                  printButtonFilterPublishMessage: function () {
                      return this.sandbox.publish("PrintButtonFilterMessage", this.get("Stage").value, ["key"]);
                  },
                  onStageChanged: function () {
                      this.initCardPrintForms();
                      this.printButtonFilterPublishMessage();
                  }
              },
              diff: /**SCHEMA_DIFF*/[]/**SCHEMA_DIFF*/,
              rules: {},
              businessRules: /**SCHEMA_BUSINESS_RULES*/{}/**SCHEMA_BUSINESS_RULES*/
          };
      });

       

    2. OpportunitySectionV2

      define("OpportunitySectionV2", [], function() {
          return {
              messages: {
                  "PrintButtonFilterMessage": {
                      mode: Terrasoft.MessageMode.PTP,
                      direction: Terrasoft.MessageDirectionType.SUBSCRIBE
                  }
              },
              methods: {
                  preparePrintFormsMenuCollection: function(printForms) {
                      printForms.eachKey(function(key, item) {
                          if (!item.get("Caption")) {
                              item.set("Caption", item.get("NonLocalizedCaption"));
                          }
                          item.set("Tag", key);
                          if (item.get("TypeColumnValue")) {
                              item.set("Visible", {bindTo: "getPrintMenuItemVisible"});
                          }
                          //Here is your logic for filtering of printables
                          /*************************************************************************/
                          if (this.get("StageId") !== undefined) {
                              if (this.get("StageId") === "423774cb-5ae6-df11-971b-001d60e938c6") {
                                  if (key === "0d8c28ce-9794-42be-8427-3d5d60e60c1f") {
                                      item.set("Visible", false);
                                  }
                                  else {
                                      item.set("Visible", true);
                                  }
                              } else if (this.get("StageId") === "fb563df2-5ae6-df11-971b-001d60e938c6") {
                                  if (key === "c80094c5-2513-4857-b5da-4b355aed8c10") {
                                      item.set("Visible", false);
                                  }
                                  else {
                                      item.set("Visible", true);
                                  }
                              } else {
                                  item.set("Visible", true);
                              }
                          }
                          /*************************************************************************/
                      }, this);
                  },
                  init: function() {
                      this.callParent(arguments);
                      this.sandbox.subscribe("PrintButtonFilterMessage", this.onPrintButtonFilterMessage, this, ["key"]);
                  },
                  onPrintButtonFilterMessage: function(args) {
                      this.set("StageId", args);
                      this.initSectionPrintForms();
                      this.initCardPrintForms();
                  }
              },
              diff: []
          };
      });

      !!!IMPORTANT!!! - in preparePrintFormsMenuCollection() you can change code only between comments

      Identificators of printables you can get from SysModuleReport table in you DB

Like 0

Like

Share

1 comments

Hi Tatiana Rogova,

       This solution doesn't work in section, because the function preparePrintFormsMenuCollection can't get stage value to check. Please double check and update your solution.

Thanks

Toàn Mai

Show all comments