Showing posts with label Scripting. Show all posts
Showing posts with label Scripting. Show all posts

Friday, August 2, 2013

How to display Popup applet in Siebel - Possible ways!!

Siebel provides various different OOB ways to display a Popup applet, no matter if it a list applet or form applet. Here below is the list of all possible ways:

1.     ShowPopup

This is a straight forward OOB way to display a popup applet which is mostly used to display a popup when button is clicked.

a.      Create a button control on the UI with Method Invoked = ShowPopup.
b.      Create following Control User Properties:

Name
Value
Comments
Popup
<Applet Name>
Name of the popup applet
Mode
<Mode>
Base, Edit, Edit List
Popup Dimension
<Height> X <Width>
Eg: 300 X 300

2.     From Server Script using business service : “SLM Save List Service”, Method: LoadPopupApplet

This method can be used as per below example:

var oBSSLM = TheApplication().GetService("SLM Save List Service");
var psInp = TheApplication().NewPropertySet();
var psOut = TheApplication().NewPropertySet();
psInp.SetProperty("Applet Height", "400");
psInp.SetProperty("Applet Mode", "1");                           // 1 - List Applet, 2 - Form Applet
psInp.SetProperty("Applet Name", "<Applet Name>");
psInp.SetProperty("Applet Width", "800");
oBSSLM.InvokeMethod("LoadPopupApplet", psInp , psOut);

3.     From Browser Script

Here below is the sample code to display applet via browser script:

      function Applet_InvokeMethod (name, inputPropSet)
{
if(name == "ButtonClick")
            {
                        inputPropSet.SetProperty("SWEMethod", "ShowPopup");
                        inputPropSet.SetProperty("SWETA", "<Applet Name>");
                        inputPropSet.SetProperty("SWEW", "300");
                        inputPropSet.SetProperty("SWEH", "100");
                        inputPropSet.SetProperty("SWESP", "true");
                        inputPropSet.SetProperty("SWEM", "<Mode>");  // Base, Edit, Edit List
                        this.InvokeMethod("ShowPopup", inputPropSet);
            }
            }

4.     From Command

This can be used if there is a need to display popup applet from toolbar button or some menu item:

Name
<Any name you want to give to Command>
Method
GotoApplet
Method Argument
ShowMode=<Mode>, Applet = <Applet Name>
HTML Popup Dimension
200 X 200                  (Height X Width)
ShowPopup
True
Target
Server


Sunday, December 23, 2012

How to get the Date difference in Days, Hours, Minutes, Seconds


A one liner solution for requirement to find out the date difference between two different dates in eScript:

function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{ 
var Date1 = new Date("12/22/2012");
var Date2 = new Date("12/23/2012");

TheApplication().RaiseErrorText(
"Date1 =" + Date1 + 
"\n Date2 = " + Date2 + 
"\n Date Difference in Days = " + (Date2.getTime() - Date1.getTime())/(1000*60*60*24) + 
"\n Date Difference in Hours = " + (Date2.getTime() - Date1.getTime())/(1000*60*60) + 
"\n Date Difference in Minutes = " + (Date2.getTime() - Date1.getTime())/(1000*60) + 
"\n Date Difference in Seconds = " + (Date2.getTime() - Date1.getTime())/(1000));

            return (CancelOperation);
}

Here below is the output:



Thursday, July 14, 2011

Use GetAssocBusComp () with caution!!

Sometimes we write script and never realize it might result in error due to record set on which it is getting operated and it becomes issue in live environment. Similar kind of scenario I observed while using "GetAssocBusComp()". Siebel geeks who have used this method before must be aware that this is being used to get the Association business component and it's "Associate" method is being used to add a record in the MVG.

So, I got a business service being called inside a workflow asynchronously where below small piece of code was failing for some set of records while it was working fine for other records:

var SRId = Inputs.GetProperty("SRId");
var SRBOBusObject = TheApplication().GetBusObject("Service Request");
var SRBC:BusComp = boinactive.GetBusComp("Service Request");
var SerialMVGBC:BusComp;
var SerialAssocBC:BusComp;
with(SRBC)
{

ClearToQuery();
SetViewMode(AllView);
SetSearchSpec("Id", SRId);
ExecuteQuery();
if(FirstRecord())
{

SerialMVGBC = SRBC.GetMVGBusComp("Serial Number");
SerialAssocBC = SerialMBVGBC.GetAssocBusComp();
// While debugging I found that code was failing
// for some records at above step
................
................
}

}

When I debug the issue and checked for the logs, the error I saw was:

No association list is available in this applet.(SBL-DAT-00276)

Strange part was, for some of the records this code was working fine and failing for some records.

While debugging I realize that the record on which this code was failing, was Read-Only. This is the due to the fact that when Service Request status change to "Closed" it gets read-only and the error was quite confusing in the way when it said "No association list is available".

Might be helpful for you in future if you face this error, please check record should not be read-only for any reason, not even due to "BC Read Only Field" user property on the business component.

Note: this is the reason you don't see the "Associate Applet" inside the MVG Shuttle applet configured on any MVF on the UI, if the record is Read-only.

Workaround

1. If you are operating on Service Request business component, then you can make use of "Always Enabled: <_MVL Dest BusCompName>" user property and then GetAssocBusComp() method would work even on read-only records. Drawback of this workaround would be, on the UI user can open the MVG applet and can associate a record in it even if the Service Request record has status = Closed.

2. Another better way is to operate on business component based on the inter-table. And just do a NewRecord().


.

Friday, July 1, 2011

How to send Email in HTML Format?...... contd

In continuation of the previous post, I found another good way to achieve the requirement of sending email in HTML format and moreover you are required to replace the field values dynamically from business component. So the extra information you need to provide to Outbound Communication Manager is the ROW_ID of the record in context.

Suppose, here below is the Email Template need to send in HTML format:


Here below is the code to achieve it:

var inp = TheApplication().NewPropertySet();
var out = TheApplication().NewPropertySet();
var svc = TheApplication().GetService("Outbound Communications Manager");
inp.SetProperty("CommProfileOverride", "SiebelMantra Profile");
inp.SetProperty("SourceBusObj", "Service Request");
inp.SetProperty("RecipientBusComp", "Service Request");
inp.SetProperty("SourceIdList", "1-B9PGUA");
inp.SetProperty("TestAddress", "siebelmantra@gmail.com");
inp.SetProperty("PackageNameList", "Test");
svc.InvokeMethod("CreateRequest", inp, out);



Here below is the email with necessary SR Number and status:


Siebel makes life "dynamically" colorful, isn't it ;)

Thursday, June 30, 2011

How to send Email in HTML Format?

If you get a requirement to send an email from Siebel, the very simple way is to make use of OOB business service, i.e "Outbound Communications Manager" with the method "SendMessage". Following input parameters would be enough for this purpose:

a) MsgToList
b) MsgSubject
c) MsgBody
d) CommProfile

Here below is the working example for the same:

var inp = TheApplication().NewPropertySet();
var out = TheApplication().NewPropertySet();
var svc = TheApplication().GetService("Outbound Communications Manager");
inp.SetProperty("CommProfile", "SiebelMantra Profile");
inp.SetProperty("MsgToList", siebelmantra@gmail.com);
inp.SetProperty("MsgSubject", "Test Email");
inp.SetProperty("MsgBody", "This is a test email");
svc.InvokeMethod("SendMessage", inp, out);

Here below is the email I received:

So, everything is working as desired, but what if you are required to send a HTML email which contains text with different colors and formatting? Well, one can quickly answer that you can use "MsgHTMLBody" argument in the above code instead of using "MsgBody". Yes, that is correct but the only it got is that you need to pass the complete HTML code as the value to this argument, but wait a minute why to take all this pain when Siebel provides a mechanism to keep the email template in HTML format for you and just need to create it from the UI. Yes, you guessed it right, I am talking about Administration - Communications -> All Templates view.

Just create a new Email Template with :
a) Status = Active
b) HTML Template = True

Now, here below is the small code to make this work:

var inp = TheApplication().NewPropertySet();
var out = TheApplication().NewPropertySet();
var svc = TheApplication().GetService("Inbound E-mail Database Operations");
inp.SetProperty("BusObj", "Comm Package");
inp.SetProperty("BusComp", "Comm Package");
inp.SetProperty("Name", "Test");
inp.SetProperty("QueryFields", "Name");
inp.SetProperty("ValueFields", "Template Text");
svc.InvokeMethod("FindRecord", inp, out);

var inp1 = TheApplication().NewPropertySet();
var out1 = TheApplication().NewPropertySet();
var svc1 = TheApplication().GetService("Outbound Communications Manager");
inp1.SetProperty("CommProfile", "SiebelMantra Profile");
inp1.SetProperty("MsgToList", siebelmantra@gmail.com);
inp1.SetProperty("MsgSubject", "Test Email");
inp1.SetProperty("MsgHTMLBody", out.GetProperty("Template Text"));
svc1.InvokeMethod("SendMessage", inp1, out1);

and when I executed the above code, here below is the email in HTML format I received in my Inbox:

Siebel makes life so colorful, isn't it ;)

Tuesday, August 25, 2009

Refreshing a record in Siebel applet - Possible ways !!

Sometimes it happens you clicks on a button on an applet which is supposed to do some modification on the current record but you get an error saying : The selected record has been modified by another user. This happens when the same record has been updated into the database (by another user or some other process like Workflow, EAI etc) and system is trying to update the old context of record on the UI. So the better way to get the updated copy of the record by refreshing it and then do any modifications. But the bottom line is you should not loose the context of the current record, so if you are thinking of using ClearToQuery() and ExecuteQuery(), it will not solve the purpose here.

There are few possible ways by which you can refresh a record on the UI, without loosing the context of the current record, depending upon the requirement you can take the decision which one to use.

1. RefreshRecord : Business Component Method

This is a method available on Business Component which are derived from CSSBCBase class. Here is how you can use it, if writing code in PreInvokeMethod of applet :
if (MethodName == "MyMethod")
{
this.BusComp().InvokeMethod("RefreshRecord");
...............................................
}

This method will just refresh the highlighed record on the UI.

2. RefreshBusComp : Business Component Method

This is similar to RefreshRecord method available on Business Component which are derived from CSSBCBase class. The only difference is that it will refresh all the records in the current query context :

if (MethodName == "MyMethod")
{

this.BusComp().InvokeMethod("RefreshBusComp");
...............................................
}

3. FINS Teller UI Navigation : Business Service

Unlike RefreshRecord and RefreshBusComp, this business service can be used for refreshing any applet/buscomp, no matter which class it has been derived from. The method need to use is "RefreshCurrentApplet".
if(MethodName == "MyMethod")
{

TheApplication().GetService("FINS Teller UI Navigation").InvokeMethod("RefreshCurrentApplet", TheApplication().NewPropertySet(), TheApplication().NewPropertySet());

}


.


Wednesday, August 12, 2009

How to do a SetFieldValue on a ReadOnly field on an Applet?

yaa... I know this sounds something interesting so please now stop scratching your head, today I will tell a unique trick by which you can do a SetFieldValue on a field on an applet which is actually displayed as ReadOnly on the UI. Let me reiterate : We want to change the value of a field which is ReadOnly on the Applet, NOT on Business Component. Special Thanks to Amol, my colleague, for bringing this up.

First of all : "Why we need this trick?". Sometimes it happen that for testing purpose Developers/QA people need to set a value in Field but if that is ReadOnly on the applet, what we generally do is just fire a SQL query in the database to set its value and do whatever we want OR you can write a small piece of code in Business Service and simulate it to just solve the purpose temporarily. Here below is a trick by which you can do this without much of effort.

Here below is the screenshot which displayes we have field : "Description" readonly on the UI. And the requirement is set its value to "SiebelMantra".

Here is the solution :
Just copy paste the below text into Address bar :
javascript: alert(theApplication().ActiveBusObject().GetBusComp("Action").SetFieldValue("Description", "SiebelMantra"))

I don't think to explain what we have typed in Address bar, if you already aware how to write browser scripts in Siebel. You can use it further as per your need. Try it !!

.

Thursday, July 30, 2009

Limitation in "PRM ANI Utility Service" business service

I was working on one requirement which I was trying to implement using Workflow, where I need to perform the following :
a) Query on Account using EAI Siebel Adapter
b) Get the contact name for the very first child under the accounts.

requirement sounds very simple, same the case with me and I thought of using PRM ANI Utility Service to achieve the purpose with the help of just two steps in the workflow. So here is how these two steps looks like :

Process Properties:
Step1 : Query AccountBusiness Service : EAI Siebel Adapter
Business Service Method : Query
Step2 : Get Contact IdBusiness Service : PRM ANI Utility Service
Business Service Method : GetProperty

As per my expectation, I didn't get the "First Name" into process property "Name", but instead I was getting the error :

Error invoking service 'PRM ANI Utility Service', method 'GetProperty' at step 'Get Contact Id'.(SBL-BPR-00162)--Error Running Method 'Execute'.(SBL-PRM-00104)

I was getting crazy as not able to figure it out what exactly the root cause of it, but after some hit and trials it worked fine for me when there was only one single child record (Contact) under the Account for which I was querying. So let me tell you the reason why I was getting the error :



This is the snapshot from the watch window, where you can see there were actually 3 records under the accounts for which I was querying and due to this PRM ANI Utility Service was not able to figure it out for which record I need the First Name. So this is the limitation of this business service and you need to make sure while using "GetProperty" and "SetProperty" of this business service that there should not be more than one child in the propertyset.

I tried with querying for the Account having single Contact associated and it worked fine. So the only workaround is to write a customize business service if you want to get/set a property value of any child record.
Give it a try !!
.

How to call "Asynchronous Server Requests" business Service?

Sometimes there is a requirement we need to run few processes that should not stop the user on the screen to go further and do next steps when Siebel is processing something in the background. That is the place when Asychronous processes come into the picture and the solution that Siebel provides for these kind of scenarios is to give a call to "Asynchronous Server Requests" business service.

There are only two ways (that I know my past experience, please add if anyone know more) by which you can call "Asychronous Server Requests" Business Service :

a) Via e-Script : easy way to do that and most people know this.
b) Via Workflow : this is bit tricky
Lets see each one of them in detail. Taken an assumption that you need to invoke a workflow (asynchronously). Assume the workflow name is "Send Email Opportunity Sales Rep", which just sends an email to the Sales Person on the Opportunity and the Input Agrument to the workflow is : "OpptyId" (1-XR45)

Via e-Script :
Here is the piece of code that you can to achieve the above requirement :
var svc = TheApplication().GetService("Asynchronous Server Requests")
var input = TheApplication().NewPropertySet();
var child = TheApplication().NewPropertySet();
var output = TheApplication().NewPropertySet();
input.SetProperty("Component", "WfProcMgr");
child.SetProperty("ProcessName", "Send Email Opportunity Sales Rep");
child.SetProperty("OpptyId", "1-XR45");
input.AddChild(child);
svc.InvokeMethod("SubmitRequest", input, output);
very simple, isn't it. We just need to make sure that the Input Argument of the calling Workflow (Send Email Opportunity Sales Rep) should be the properties of the Child Property Set.

Via Workflow :
Here is the example below in which I have used this and you can accomodate the below two steps in any of the workflow you are using :

Process Properties :
Name : Inputs
Type : Hierarchy

Step1: Set Input Arguments
Business Service : Workflow Utilities
Business Service Method : echo


Step2: Call Asynchronous Service
Business Service : Asynchronous Server Requests
Business Service Method : SubmitRequest


Thats it, you are done. Just to add it here, I tried doing the same stuff with the help of runtime events but it is limitation there and we cannot do that.

.

Tuesday, April 28, 2009

FirstRecord() in PreCanInvoke Event : Refresh Issue

Today I am going to tell you about an interesting issue that we faced in our Production Env and really worked hard to figure it out the root cause for it.


The issue was :

On Activity Form applet, we have "Comments" field, which is 2000 characters long and user to write a detail description in this field related to that activity record. Now few of the users faced the issue that "while typing some text in Comments field, suddenly the whole text written get deleted and Comments field become blank". User get frustrated as he need to type in the whole text again and also the next time not sure whether he will able to complete putting text in Comments field or not. For a temporary workaround they used to first type in all the text in a NotePad file and then copy paste the complete text at once in Comments field and save the record.

What we tried :

When we tried replicating this issue in our dedicated env, we were unable to replicate it. After lot much of effort our QA Team was able to replicate it sometimes on our thin client. But the problem was this is not always happening with them as well. On some of the machines we were not able to replicate it at all. Totally a random behaviour.

Now the problem was to find out the steps so that we can replicate it. We have one option to try i.e. by disabling all the Server Script and check if we can replicate the issue in thin client (since in dedicated client everything was working fine).

We changed the "EnableScripting" = False and restart the Siebel server, and found that the issue is not coming anymore. So we narrowed down for the root cause of the problem to Scripting.


And, here is what we finally found :

On PreCanInvoke method of the applet we had a script written, something like :


if (MethodName == "Test")
{
if(this.BusComp().FirstRecord())
CanInvoke = "True";
return (CancelOperation);
}


So, what was happening when user was typing some text in Comments field, it seems like IE web page get refreshed and due to this the code written on "PreCanInvoke" method was getting invoked and due to the "FirstRecord()" method used inside the code, the current record get refreshed and resulting in no text in Comments field.

Finally, we were able to find the root cause of the problem, now its the time to look for some workaround. So we decided not to enable/disable button using PreCavInvoke script, rather put a check message in PreInvoke method when there is no record displayed. So here below is final version of script we used :

PreCanInvoke Method

if (MethodName == "Test")
{

CanInvoke = "True";
return (CancelOperation);

}


PreInvoke Method :

if(MethodName == "Test")
{
if(this.BusComp().FirstRecord())
{
TheApplication().RaiseErrorText("This operation is not valid, when record is not displayed");

}
return (CancelOperation);
}


Recommendation:
Avoid writing scripting on PreCanInvoke Method of Applet, as this is the event which fires on each and every action we do on the applet + at the time of automatic refresh of web page.

Thursday, January 22, 2009

Early Instantiation of Business Component

In this article, I want to showcase a nice way that we should use while scripting in Siebel. This also comes under the Siebel scripting best practices.

I need to write a Script for a simple requirement : "I want to get a "Opportunity Name" and "Product Name" from "Opportunity" & "Opportunity Product" business component respectively. Opportunity Product is a child business component of Opportunity. Lets suppose, The Opportunity Id in the requirement is : "1-6JKM".

Here are few ways by which we can code :

First Method
var BO = TheApplication().GetBusObject("Opportunity");
var OBC = BO.GetBusComp("Opportunity");
with (OBC)
{
ClearToQuery();
SetViewMode(3);
SetSearchSpec("Id","1-6JKM");
ExecuteQuery();

if(FirstRecord())
{
var OPBC = BO.GetBusComp("Opportunity Product");
with (OPBC)
{
ClearToQuery();
SetSearchSpec("Oppty Id","1-6JKM");
ExecuteQuery();
if(FirstRecord())
{
TheApplication().RaiseErrorText("Opportunity Name = " + OBC.GetFieldValue("Name") + ", Product = " + OPBC.GetFieldValue("Product"));
}
}
OPBC = null;
}
}
OBC = null;
BO = null;


Second Method
var BO = TheApplication().GetBusObject("Opportunity");
var OBC = BO.GetBusComp("Opportunity");
with (OBC)
{
ClearToQuery();
SetViewMode(3);
SetSearchSpec("Id","1-6JKM");
ExecuteQuery();

if(FirstRecord())
{
var OPBC = BO.GetBusComp("Opportunity Product");
with (OPBC)
{
ExecuteQuery();
if(FirstRecord())
{
TheApplication().RaiseErrorText("Opportunity Name = " + OBC.GetFieldValue("Name") + ", Product = " + OPBC.GetFieldValue("Product"));
}
}
OPBC = null;
}
}
OBC = null;
BO = null;

Third Method
var BO = TheApplication().GetBusObject("Opportunity");
var OBC = BO.GetBusComp("Opportunity");
var OPBC = BO.GetBusComp("Opportunity Product");
with (OBC)
{
ClearToQuery();
SetViewMode(3);
SetSearchSpec("Id","1-6JKM");
ExecuteQuery();

if(FirstRecord())
{

if (OPBC.FirstRecord())
{
TheApplication().RaiseErrorText("Opportunity Name = " + OBC.GetFieldValue("Name") + ", Product = " + OPBC.GetFieldValue("Product"));
}
}
}
OPBC = null;
OBC = null;
BO = null;



If you had a glance on three different ways mentioned above, you will realize the third method is the most efficient method. Let me try to explain what exactly we have tried to achieve here.

First method is the simplest one, where to get any field value we query for Business Component with the row_id and do a GetFieldValue on the resultant record.
Second method is bit tricky, as you can see no need to query on Opportunity Product. "ExecuteQuery" is sufficient to fetch the records. This is the power of Link mentioned for the "Opportunity Product" in "Opportunity" business Object. Siebel is smart enough to initialize the link along with business component, whenever instantiated.
And best one is the third method, as you can see the Opportunity Product is instantiated right in the beginning. So when we query on Opportunity business component, the Siebel will automatically returns the associated Opportunity Product records as well. No need to put any extra "ExecuteQuery". This is what we call "Early Instantiation" of Business Component.

Saturday, November 29, 2008

Call Business Service from Browser : A Trick

Siebel is really a miser if talk of browser script.... but, here is the way that can be used to take full advantage out of it :)

At times we have the requirement to call a Business Service from “Browser Script” then it is necessary to make the entry of that “Business Service” everytime in .CFG file with the following syntax under [SWE] section of the CFG file:

ClientBusinessService X = “”Where X = 1,2,3,4……

So, to get rid of this here is a trick. You can implement a new "Generic Business Service" which will internally call the Business Service that we want to call from Browser Script.

Name of Business Service = CallBusSerFromBrowScript
Method Name = Service_PreInvokeMethod

Generic business Service Code :
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
if(MethodName == “GenericCall”)
{
var svc = TheApplication().GetService(Inputs.GetProperty(”BSName”));
svc.InvokeMethod(Inputs.GetProperty(”MethodName”), Inputs, Outputs);
svc = null;
}
return (ContinueOperation);
}

Procedure for Calling :
Please follow the below code for calling your Business Service from browser script. Lets say you want to call “MyBusinessService” with Method Name = “MyMethod”, then use the following code :
var input = theApplication().NewPropertySet();
var output = theApplication().NewPropertySet();
input.SetProperty(”BSName”,”MyBusinessService”);
input.SetProperty(”MethodName”,”MyMethodsvc = theApplication().GetService(”CallBusSerFromBrowScript”);
svc.InvokeMethod(”GenericCall”, input, output);
svc = null;output = null;input = null;
ToDo List ( Admin Team + Development Team + QA Team)
1. Please update the following code in .CFG file of your web client under [SWE] section with the name of Generic Business Service. This is to be done one time only.

ClientBusinessServiceX = “CallBusSerFromBrowScript”where X = 1,2,3………..
TA DA…… once you are done with this, life become easy. Try it out !!!!!!!!!
This way you make the life of your Siebel-Admin people easier as they don’t require making changes in CFG file in every release. :)