Wednesday, July 27, 2011

Child Field Read Only depending on Parent Field Value

Sometimes it happens that you get a very simple requirement to implement and in a single glance you say, "Well, this is very easy to implement" and when you actually see the result on the UI after the configuration you have done, you start scratching your head to find out the reason for not getting the result as per the expectation.

Today, I am going to discuss a very simple requirement you might have faced earlier.

Requirement
I have two applet exposed on the UI: 1) Opportunity Form Applet 2) Quote List applet.
Opportunity being the parent applet and quote as the child as per below screen shot.


The simple requirement is to make "Comments" field on Quote List Applet editable, if and only if Sales Stage of Opportunity = Data Entry.

very simple isn't it! Anyone can easily say, go and use "Field Read Only Field" user property at Quote business component and you are done. I reacted to it in the similar manner and followed the below steps:
1. Pull "Sales Stage" value on Quote BC.
2. Create a calc field to set to Y, if Sales Stage = "Data Entry"

3. Create a BC User property, Field Read Only Field based on calc field.



Compile the SRF.

Navigate to Opportuity -> Quote view to verify the results. I created an Opportunity record, set the Sales Stage to "Data Entry" and then created a Quote record. "Comments" field was editable. Then I changed the Sales Stage to "Submitted" and per configuration I was expecting the "Comments" field to be read only, but to my surprise, it was not. Still, I was able to edit the field.


It might happen that change of "Sales Stage" at the Opportunity level is not getting reflected at the quote level. Let me try running a blank query (Alt+Q, then enter) to refresh and now..... yes, "Comments" field get read-only. So, basically the problem is, Quote BC is not aware of the change in Sales Stage at Opportunity level, unless you refresh it.

(Note: this is not the case with "Parent Read Only Field" user property. Change at parent field immediately gets reflected at the child level.
You can refer this post for more details.)

Now, the problem here is to get the Quote list applet refreshed, if some change happens at Opportunity. One might point out that you should have "Immediate Post Changes" as True for "Sales Stage". But, keep in mind that "Immediate Post Changes" will only refresh the fields of the same business component, not of the child BC.

One solution, I can think of is to refresh the Opportunity business component in such a way that it should not loose the record context and consequently, Quote BC will automatically gets refreshed. But, I didn't want to do the scripting on Opportunity WriteRecord event, just to refresh the Quote BC, something like:

function BusComp_WriteRecord ()
{


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

So, I found a better way to achieve to refresh the Opportunity form applet. Just create the following user property on the Opportunity applet:


Compile the SRF and check the result on the UI. Voila, everything is working as desired now.


.

Monday, July 18, 2011

How to send email containing multiple child records data?

I am pretty sure you will find this post very interesting, if you ever get a requirement to send a email in HTML format and email should have the details of the child records(dynamic data) as well.

XSLT (XSL Transformation) can do wonders for this kind of requirement where the basic idea is to get data in XML hierarchy from Siebel (which you can easily do via EAI Siebel Adapter and convert it into XML) and apply the XSL transformations to get the HTML output. And as far as you know how to play with HTML and XSL, you can create any kind of email format that you like to see. All you need is to use EAI XSLT Service business service with method Transform.

Below picture might give you some idea of it:



To understand the concept, let suppose:
1. As soon as an Opportunity gets submitted, you are required to send an email to the Sales person to inform him.
2. Email should have the details of child records created under that Opportunity.
3. Email should have some kind of formatting so that it looks good and eye-catching.

You might be thinking what is a big deal in it and why should I even use the XSLT (new term for lot many people) for it? There is a simple reason behind it, there is NO OOB way available in Siebel (as far as I know) by which you can include the data from Child records (multiple) in the email.

Let me first show you the proof-of-concept and later we will discuss about the technical solution.
1. I have below opportunity created with 2 records of Opportunity Products.

2. It has also 3 Quote records created under it.

3. As soon as Opportunity get submitted, system is required to send the email to the sales person.
4. Here below is the email, I would like to receive:


If you find that interesting, keep reading for the technical details of it.


Pre-requisite
Please note that for this demo, I have used a Integration Object (Opportunity) based on Opportunity BO with having only 3 ICs configured: Opportunity, Opportunity Product and Quote. And include only those fields whose values are required in the final email, for eg: Oppty Name, Product Name, Net Price, Quote Name etc. (Please refer the first picture of this post, XML part)


Technical Solution
1. Call a Workflow (based on Opportunity BO) as soon as Opportunity gets submitted.
(Note: System will automatically pass the row_id of Opportunity to "Object Id" process property of the Workflow Process)
Here below is the WF snapshot.


2. Process Properties

3. Step Details:


Code for XSLTBuffer
<?xml version="1.0" encoding="UTF-16"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><html><body><h2>You have got an Opportunity to act on:</h2><h4>Opportunity Name : <span style="color:#ff0000"><xsl:value-of select="ListOfOpportunity/Opportunity/Name"/></span></h4><h3>Here below are the Product Details:</h3><table border="1"><tr bgcolor="#9acd32"><th>Product</th><th>Quantity</th><th>Net Price</th><th>Revenue</th></tr><xsl:for-each select="ListOfOpportunity/Opportunity/ListOfOpportunityProduct/OpportunityProduct"><tr><td><xsl:value-of select="Product"/></td><td><xsl:value-of select="ProductQuantity"/></td><td><xsl:value-of select="ProductPrice"/></td><td><xsl:value-of select="Revenue"/></td></tr></xsl:for-each></table><h3>Here below are the Quote Details:</h3><table border="1"><tr bgcolor="#9acd32"><th>Quote Name</th><th>Revision</th><th>Status</th> </tr><xsl:for-each select="ListOfOpportunity/Opportunity/ListOfQuote2/Quote2"><tr><td><xsl:value-of select="Name2"/></td><td><xsl:value-of select="Revision"/></td><td><xsl:value-of select="Status"/></td></tr></xsl:for-each></table></body></html></xsl:template></xsl:stylesheet>

If you want to learn about XSLT more, then please refer the below link:
http://www.w3schools.com/xsl/

Friday, July 15, 2011

How to make all Child BCs read-only when Parent BC becomes read-only?

Today I am going to discuss one interesting requirement where you are required to make all the Child Business components read only as soon as the Parent business component becomes read-only.

Actual scenario goes like this:
As per the business requirement, we need to have the Opportunity business component read-only when Sales Stage is Approved. For this simple requirement we configure the BC User Property: "BC Read Only Field" based on a calculated field "OpptyReadOnlyCalc" as defined below:

User Property
Name = BC Read Only Field
Value = OpptyReadOnlyCalc

Field Details
Name = OpptyReadOnlyCalc
Calculated = True
Calculated Value = IIf([Sales Stage] = "Approved", "Y", "N")


This was working pretty fine, but complexity get added to it when we are required to make all Child business components read-only as well. Though the Opportunity record was coming read-only on the UI, but it was allowing us to create the child record as per below screen-shot:



You can see in the above screen shot (marked in Red), all the vanilla buttons i.e. Add, New, Delete are enabled. Requirement was to disable these buttons and user not allowed to do any operation on the child BCs as well as soon as Opportunity become read-only.

Solution:
To achieve this requirement, you are required to create two more BC user properties on Opportunity Business component.

User Properties

Name = Aspect Child BC ReadOnly: ReadOnly
Value = OpptyReadOnlyCalc

Name = Default Aspect
Value = ReadOnly



Thats it, compile the SRF and VoilĂ , now observe the difference on the UI.


If you want to learn about Aspect User Properties, follow the below link:
http://download.oracle.com/docs/cd/B40099_02/books/ToolsDevRef/ToolsDevRef_UserProps43.html
.


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 ;)