27 February 2011

SugarCRM: Seamless Mail Sync

The disclaimer first - my knowledge with SugarCRM has been limited and I only try to dig into things when I find something interesting enough. I have been playing around the latest version (6.12) of SugarCRM lately, and was fairly delighted to see a good email integration feature.

How it works is pretty straight-forward.
1. The user can setup his own account to connect to an email account - gmail, yahoo, MS Exchange enabled by default


2. Connect to email box and check things in Sugar



3. Import the received/sent email within Sugar, and build other entities like account, opportunity etc. around it


I was also impressed by the level of integration a calendar entry has. For example, a divisional manager sends a meeting request to his boss and the rep working on a proposal. This is what the rep gets in the email.


Ofcourse, the point to note is that this was sent from the SugarCRM calendar. There is greater flexibility if it was google calendar (yes, there is a mod to connect with Google calendar).

The reason I was so delighted should probably be attributed to the way PIM Sync works. Until that is re-written, we probably would not miss out on 'complex' projects to implement email integration.

05 February 2011

Siebel: Prototype in eScript - Part 3

In earlier posts, we have seen using prototypes to extend OOB objects. In other posts we have also dealt with user defined objects and scripts libraries. Time for seeing all three in action you say? And I hear you, we shall see how user defined object can be prototyped, and used across the application.
Problem: I need a function to lookup the description of a LOV provided its type and value
Solution: We address the problem in two steps:
  1. Define a user object and make sure it is available for the session. One of the common ways of doing this is in Application object
  2. Use the custom object to define a prototype for useful function(s) - in our case 'LookupDesc'
 Now, the how..
  • Define a variable in the application script, for example: Siebel Life Sciences
[Application: Siebel Life Sciences, (declarations)]
var MyApp;
And, call a business service where MyApp is initialized. This is just to keep the application object, it works just fine within the application itself.
[Application: Siebel Life Sciences, Method: Application_Start]
function Application_Start (CommandLine)
{
 var bsStarter = TheApplication().GetService("COG Test Proto");
 bsStarter.Init();
}

  • Write the custom business service 'COG Test Proto'
[Service: COG Test Proto, Method: Init]
 function Init ()
 {
    TheApplication().MyApp = new MyAppFun;
    MyAppFun.prototype.LookupDesc = LookupDescFun;
 }

[Service: COG Test Proto, Method: MyAppFun]

       function MyAppFun()
       {
 // this is a dummy, but funny function.
       }


  [Service: COG Test Proto, Method: MyAppFun]
function LookupDescFun (Type, Value)
 {
 try {
  var sDesc = "";
  var boLOV = TheApplication().GetBusObject("List Of Values");
  var bcLOV = boLOV.GetBusComp("List Of Values");
  with (bcLOV) {
     ClearToQuery();
     SetViewMode(AllView);
     ActivateField("Description");
     SetSearchExpr("[Type]='" + Type + "' AND [Value] = '" + Value + "'");
     ExecuteQuery(ForwardOnly);
     if (FirstRecord()) sDesc = GetFieldValue("Description");
  } //with
  return(sDesc);
 }
 catch(e) {
  throw(e);
 }
 finally {
  bcLOV = null;
  boLOV = null;
 }
 }


 That's about it, now MyApp is ready to have some fun. Again, a quick service to test how things work.

[Service: COG Test Proto Call, Method: Service_PreInvokeMethod]
 function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
 {
    Outputs.SetProperty("out", TheApplication().MyApp.LookupDesc("blah", "blah"));
 }

A bit of theory on how it works:
  1. MyApp is defined as a variable in Application, the same is initialized in a business service. It does not matter what the function [MyAppFun] contains, we will not be using that anyway
  2. The prototype LookupDesc is defined as an extension of MyAppFun. Any object based on MyAppFun will have access to the LookupDesc functionality
  3. We invoke LookupDesc as an extension of the variable in the application object. There are other blogs out there who just use TheApplication = MyApp, but that practice is not encouraged as I understand
  4. When TheApplication().MyApp.LookupDesc is invoked, Siebel will look for the LookupDesc function for MyApp object. Since the functionality does not exist OOB, the prototype is consulted and in turn LookupDescFun function is executed.

If you are thinking this is an overkill, you may be right if this is all you want to do. Keep in mind that this coding practice will be more scalable, and ensures reusability.

02 February 2011

Siebel: Prototype in eScript - Part 2

The last example in prototypes dealt with extending a OOB data type, but that extension was done within the business service itself. Although the prototype can be defined only once and used multiple times, it is not really demonstrated well since the entire thing is handled within the same code. Here, let me take an opportunity to show how the prototype definition itself can be handled elsewhere.

Problem
Check whether the given string is a valid email address

Solution
Define the prototype to extend the OOB string object, and use it as many times as needed. To achieve this we define the prototype in the Application object.

Go to "Server Scripts" of 'Siebel Life Sciences' or similar, and define prototype.

(declarations)

String.prototype.IsEmail = CheckValidEmail;

Add a function 'CheckValidEmail' to the same application object.

function CheckValidEmail()

{

var rEmailPat = /^\w+[\w-\.]*\@\w+((-\w+)(\w*))\.[a-z]{2,3}$/;

return rEmailPat.test(this);

}

That's about it! Any string can now be tested for a valid email. We will quickly build a test function to demonstrate how this is used:

Service: COG Test Email

Method: Service_PreInvokeMethod

function Service_PreInvokeMethod (MethodName, Inputs, Outputs)

{

var sEmail = Inputs.GetProperty("Email");

Outputs.SetProperty("Valid", sEmail.IsEmail());

return (CancelOperation);

}

When you run this in the simulator, this should either return a 'true' or 'false' value depending on whether the supplied string is a valid email address. Now, a bit about how it works.

  1. First we define the prototype for the data type string with the statement String.prototype.IsEmail = CheckValidEmail'. This statement is executed when the application starts up.
  2. The above prototype points to a custom function 'CheckValidEmail'. This function uses a simple regular expression to test the validity of the entered string. It returns a 'true' when the string has the specified regex pattern, false otherwise
  3. None of the above has any effect until we actually invoke the 'IsEmail' function. When this function is used against the string object, Siebel checks the prototype since no such function exists OOB
  4. Return value from the function denotes whether the string 'sEmail' is a valid email address

Watch this space for one more example!