Showing posts with label Impossible. Show all posts
Showing posts with label Impossible. Show all posts

Server Confirm dialog (Scriptless)

[Background]

Every Siebel professional knows that its impossible to get input from the user using Server script. The rationale is that server script runs on the server, and theres no way that it can pop something up on the client. Whats more ludicrous is to do it without any script.

Google for "Siebel Confirm" and you'll get a bunch of results stating that this is only possible using Browser Script.

Search in support web and you'll probably end up with these documents

1. How Should You Implement Message and Input Boxes in Siebel 7 and Siebel 8? [ID 476612.1]

2. How Can You Display a Message from a Server Script on the Browser? [ID 477323.1]

The conclusion is the same:

"Interactive dialog boxes are features that belong to the JavaScript language and can only be launched from browser script"

That sounds like solid advice, so would you believe me, if i told you that its possible to invoke a Confirm dialog from the server, using out of the box functionality?

Did i hear someone say "NO"!? Okay, that might have been my sub conscious.

If you are not convinced, let me introduce you to an undocumented business service that does just this.

[Confirm Dialog Business Service]

Business Service: LS Pharma Signature UI Service
Method Name:
ShowConfirmDialog

Open up Siebel and goto your business service simulator, and load up the following values

Inputs:
Cancel Method Name:
MyCustomMethod1
Confirm Text:
Winona, will you marry me?
OK Method Name:MyCustomMethod2

Your view should look like this.



Click run, and VOILA.



This produces an Ok,Cancel dialog that can be used across the application, but best of all, it is scriptless.

Now click either button, and you should get an error.


This happens because we havnt configured the application to handle these custom events, but lets try to invoke methods that we do know exist, and we'll perform some real configuration instead of basing our results off the simulator.

[Configuration]


Find your favourite BC and add the following user property, this will enable a custom method, and call the business service to display our Confirm Dialog.

Named Method

"InvokeAction", "INVOKESVC", "WS Transaction Settings", "LS Pharma Signature UI Service", "ShowConfirmDialog", "'Cancel Method Name'", "'NewRecord'", "'Confirm Text'", "'Hello'", "'OK Method Name'", "'DeleteRecord'"

Next find your favourite applet, and add a new button and set the following property:

Method Invoked: InvokeAction

The Ok and Cancel method definitions, will fire the respective events from the Applet to the BC, and from Browser to the Server, just like normal events, which you can subsequently trap and perform the intended action, based on the user response.

[Results]

NewRecord
This creates a new record in the applet

NewQuery This toggles the applet into Query mode

DeleteRecord
Interestingly, this brings up another confirm dialog. Infact, it looks damn similiar my own confirm dialog, except for the question text.

[Conclusion]


If you look hard enough, you'll find examples of this all over the application, heres another business service that does the same thing, except the message, and return codes are hard coded

Business Service: LS SubjectVisits Service
Method Name: ShowConfirmationDlg

This raises a few questions in my mind

1. Why isnt this documented?
2. Can we have control over how the dialogs are presented?
3. Can we display a message or prompt dialog in the same manner?

Maybe someone from Oracle engineering can answer this, but suffice to say, this is a great little nugget for Impossible Siebel readers.

On a closing note, if you would like more pizazz in your popups, change the buttons or add an icon, have a read of Alex's UMF Series, on Siebel Essentials. It should cover my requirements above.

Siebel Unified Messaging Framework - Part 1

Siebel Unified Messaging Framework - Part 2

Solution - Show creator full name on 'About Record Applet'

Impossible reader Sajan, has responded to the 'About Record Applet' Challenge.

The solution Sajan shares, higlights the use of ShowControl.

The WebApplet_ShowControl event is only supported in Standard interactivity, and allows us to modify a control as it is being rendered to the user.

By trapping this event, Sajan can intercept the rendering of the Created By and Last Updated By fields, send the login Id off to a server script function to resolve it to a persons name, then inject the value back into the HTML stream on the fly.

Sajan's solution

//Object: Applet
//Object Name: About Record Applet
//Event: WebApplet_ShowControl
//Script: Server Side

function WebApplet_ShowControl (ControlName, Property, Mode, &HTML)
{
if ((ControlName == "CreatedBy") && (Property == "FormattedHtml"))
{

var temp =HTML;

//Capture the LOGIN only
var temp1=temp.substring(temp.indexOf(">"));
loginid= temp1.substring(1,temp1.indexOf("<"));

//Method to pull Full Name based on the Login
HTML = fetchfullname(loginid);
}
}

This technique is useful for tricky client automation problems, and can be used to perform more complex logic, by injecting javascript into the HTML, which executes when it loads in the users browser.

Why would we want to do this?

  • Auto-completing fields
  • Auto submitting a form
  • Scrolling to a desired position in the view
  • Changing the look and feel of an applet dynamically


What if the business insisted that we change the background image of the 'About Record Applet', and have a different picture displayed every time it is opened?

We never say no around here =).






387uh4ap2x

Reader Challenge - Show creator full name on 'About Record Applet'

This is our second reader challenge, and i've come up with something more achievable, but still impossible (our definition of impossible is when Siebel says it can't be done).

As usual, this will take under 5 < minutes to prototype, and will be fun to try.

Requirement
When the user clicks on About Record, display the actual First Name + Last Name, instead of the Login Id next to the 'Created By' and 'Updated By' labels.

Before


After


Why its impossible
1. It runs from class code and the available fields are hard coded
2. There is no underlying BC

Some people will find the above challenge too simple, so have a go at the first reader challenge which is a lot tougher.

Selectively enable/disable multiple buttons based on ShowPopup

Second place in our Impossible Siebel Poll results was a requirement to have two buttons on an applet, that call two different popup applets.

The challenge was to selectively enable/disable these buttons, this is not possible using orthordox config methods, because the buttons are based on the same method.

In this article i'll go through 3 solutions that enables us to control these buttons individually.

Solution 1 - Browser Script hack

The basis around this solution is really a DOM hack, and is implemented as follows.

We take a handle on the control, and change the class from minibuttonOn to minibuttonOf, this causes the button to be styled as an disabled button.

This allows us to control multiple showpopup buttons based on the control name.

The disadvantage of this trick, is that you cannot do complex PreCanInvoke logic, outside of the current UI active fields, without doing a round server trip.

function Applet_Load ()
{
if (theApplication().GetProfileAttr("InvButton1") == "Y" )
{
var btn1 = this.FindActiveXControl("Button1");
btn1.innerHTML = "Button1";
}

if (theApplication().GetProfileAttr("InvButton2") == "Y" )
{
var btn2 = this.FindActiveXControl("Button2");
btn2.innerHTML = "Button2";
}
}


Solution 2 - Server Script + Browser Script

This solution puts our PreCanInvoke logic in server script which offers more flexibility, and should be used over the DOM hack when possible.


  1. Configure your button as follows



    You will notice that instead of using the method ShowPopup, we are using custom methods for our buttons.



    But we still configure the user properties as normal, remember to replace the applet and desired mode with your own.



  2. Put the following code in the Applet_PreInvokeMethod section under browser scripts

    function Applet_PreInvokeMethod (name, inputPropSet)
    {
    var iOperation = "ContinueOperation";
    try
    {
    switch(name)
    {
    case "EventMethodButton1":
    case "EventMethodButton2":
    iOperation = "CancelOperation";
    inputPropSet.SetProperty("SWEMethod","ShowPopup");
    this.InvokeMethod("ShowPopup",inputPropSet);
    break;
    }
    }
    catch(e)
    {
    theApplication().SWEAlert(e.toString());
    }
    finally
    {
    }
    return (iOperation);
    }

    What this does is redirect our custom methods to a generic ShowPoup method, that is interpreted by the class code to display our popup applets, that we configured in the control user properties.

  3. Because we have configured our buttons to invoke different custom methods, we can use normal PreCanInvokeMethod logic to selectively enable/disable our controls.

    function WebApplet_PreCanInvokeMethod (MethodName, &CanInvoke)
    {
    var iOperation = ContinueOperation;

    try
    {
    switch (MethodName)
    {
    case "EventMethodButton1":
    case "EventMethodButton2":
    if (TheApplication().GetProfileAttr("InvButton1") == "Y" )
    {
    CanInvoke = "FALSE";
    iOperation = CancelOperation;
    }
    else
    {
    CanInvoke = "TRUE";
    iOperation = CancelOperation;
    }
    break;

    }
    }
    catch(e)
    {
    //error handling goes here
    }
    finally
    {
    return (iOperation);
    }
    }

  4. If you have already attempted the above instructions and have found that it doesnt work, there is a very obscure trick that enables the entire solution to work.

    You need to enable the ShowPopup property for the control

    How this works is not clear, because if you look at the help files, this is the description of this property

    • This property should not be set to TRUE on a button if there is underlying script that uses the application object method, GotoView.

      If this property is set to TRUE and TheApplication.GotoView is used, this causes the view to be opened in a new browser window. The Siebel client UI does not support a Multiple Document Interface (MDI) architecture, so this combination is not supported


    This has vague if any reference to what we are doing, but it serves our very exact purpose. Thanks to DMc for this trick.


Solution 3 - Server Script + Browser script + Accelerators

This solution was provided by one of our readers Dos and he/she donst use any tricks, just really creative thinking.

This solution is based of a SR "How to launch a popup applet via an applet menu? (Doc ID 762230.1)", which shows us how to use commands to display popup applets.

We are going to take advantage of this behaviour and use some browser script to call our commands.


  1. Configure some commands to display our popup applets



  2. Define the keyboard accelerator to invoke these commands.



  3. Configure hidden applet menus that invoke our commands



  4. Configure some buttons on our applets to trigger a virtual click on our invisible applet menus



  5. Put the follow browser script in your applet, to send keys to the UI, corresponding to our keyboard accelerators


    function Applet_PreInvokeMethod (name, inputPropSet)
    {
    var iOperation = "ContinueOperation";
    try
    {
    switch(name)
    {
    case "EventMethodButton1":
    var WshShell = new ActiveXObject("WScript.Shell") ;
    WshShell.SendKeys("^1");
    WshShell = null;
    iOperation = "CancelOperation";
    break;

    case "EventMethodButton2":
    var WshShell = new ActiveXObject("WScript.Shell") ;
    WshShell.SendKeys("^2");
    WshShell = null;
    iOperation = "CancelOperation";
    break;
    }

    }
    catch(e)
    {
    theApplication().SWEAlert(e.toString());
    }
    finally
    {
    }
    return (iOperation);
    }


  6. Use Serverscript PreCanInvoke to control whether these buttons should be enabled or disabled.

Its encouraging to see so many different solutions for something that is supposedly impossible to achieve. I can imagine all the BAs who are reading this, getting funky ideas on how to use the application.

Because i once told a BA, that doing the above was not possible, i hope that person isnt reading this blog.

Display different Popup applets from a single button click

The frequency of articles on Impossible Siebel has slowed down due to current project responsibilities, but i'd thought i say a quick hello by responding to a reader question.

This article has been requested by our good friend Neel, over at Siebel Unleashed.

Requirement

Display a different popup applet on the same button click depending on certain conditions.

Solution Overview

  1. Create two buttons that will invoke ShowPopup to display our different Popup applets.
  2. The above buttons will be made hidden
  3. Create a master button that will programically click the desired hidden button to display our desired applet


Implementation

Configure two buttons as follows









Control Name: Button1Method Invoked: ShowPopup
User Property NameValue
ModeQuery
PopupPopup Applet 1
Control Name: Button2Method Invoked: ShowPopup
User Property NameValue
ModeQuery
PopupPopup Applet 2


Configure a master button that invokes a custom method and click the above buttons based on a profile attribute.

The following code should be put behind PreInvokeMethod on the applet in browser script


var retOperation = "ContinueOperation";
switch(name)
{
case "EventMethodTest":
retOperation = "CancelOperation";
var oAppl = theApplication().FindApplet("My Applet");

if(theApplication().GetProfileAttr("WhichButton") == "Button1") {
var oCon = oAppl.FindActiveXControl("Button1");
}else{
var oCon = oAppl.FindActiveXControl("Button2");
}
oCon.all[0].all[0].click();
break;
}
return (retOperation);


Once you are happy with the above config, you can make the two ShowPopup buttons hidden.

There are various ways of doing this, you can make the buttons hidden using browser script on applet load.

var ctrl = this.FindActiveXControl("Button1");
ctrl.style.visibility="hidden";
var ctrl = this.FindActiveXControl("Button2");
ctrl.style.visibility="hidden";


Another way is to provide ON and OFF states for the button, and assign it a blank image. Maybe our readers know of better ways to do this, i'll leave this open for comments.

How to create a VBC without Script - XML Gateway


This article is a continuation of the Impossible Solutions Poll Results post.

If you have been following this blog, it probably dosnt need any further introduction.

This solution has been contributed by Michael Feng, a respected colleague, who dosnt know the meaning of impossible and is an all round nice guy.

[ Michael's solution ]

Key Points:

  • Using XML Gateway Business Service to serve the VBC
  • Using Business Integration Manager (Server Request) as Transport Protocol
  • Create your own workflow to deal with the logic


Architecture:

  • VBC trigger XML Gateway: Init(), Query(), etc
    XML Gateway generates xml files corresponding to the command. Eg. It generates xml file

    <siebel-xmlext-fields-req>
    <buscomp id="1">Contact</buscomp>
    </siebel-xmlext-fields-req>


  • Matching Init() command
  • XML Gateway triggers Business Integration Manager to invoke SendReceive() method

  • Business Integration Manager sends the xml files generated by XML Gateway to Workflow

  • Workflow gets the xml file and passes it to external application like MQ Series, MSMQ, HTTP Web Application or processes it inside the Siebel

  • Workflow gets the result xml file from external application or Siebel Application and passes it back to Business Integration Manager (BIM)

  • BIM receives the result xml file and passes back to XML Gateway to populate the VBC



Points of configuration:

  • Create a BC of Class CSSBCVExtern

  • Configure the above BC with following user properties
    Service Name: XML Gateway
    Service Parameters: Transport=EAI Business Integration Manager (Server
    Request);ProcessName=<Name of WF>;

  • Create a process property as type of binary/string. Set the default to <Value>. It will hold the xml file generated by XML Gateway

  • Create a process property as type of binary and named <Value>. It will pass back to BIM and XML Gateway to populate the VBC

  • Analyse the xml file generated by XML Gateway to determine what action to be taken. (Query, Insert…)

  • Use XSLT to transform the result xml file to the format XML Gateway needs to populate the VBC



Sample Workflow Design


Workflow Process Properties



StepTypeMethodBusiness Service
SaveIncomingXMLBusiness ServiceSendEAI File Transport
Input ArgumentTypeValueProperty name
<Value>Process PropertyIncomingXML
FileNameLiteralC:\XMLGateway.txt
AppendToFileLiteralTrue






StepTypeMethodBusiness Service
Analyse Incoming XMLBusiness ServiceEchoWorkflow Utilities
Output ArgumentTypeValueProperty name
CheckPointExpressionInStr([&IncomingXML],"fields-req")







StepTypeMethodBusiness Service
Is Init Request?Decision Point
BranchConditionExpression
Is InitCondition(CheckPoint Greater Than('0'))
Not InitDefault




StepTypeMethodBusiness Service
Get Init XML ResponseBusiness ServiceReceiveEAI File Transport
Input ArgumentTypeValueProperty name
FileNameLiteralC:\TEMP\TestVBCInit.xml
Output ArgumentTypeValueArgument name
<Value>Output Argument<Value>






StepTypeMethodBusiness Service
Analyse Incoming Query XMLBusiness ServiceEchoWorkflow Utilities
Output ArgumentTypeValueProperty name
CheckPointExpressionInStr([&IncomingXML], "query-req")







StepTypeMethodBusiness Service
Is Query Request?Decision Point
BranchConditionExpression
Is QueryCondition(CheckPoint Greater Than('0'))
Not QueryDefault




StepTypeMethodBusiness Service
Get Query XML ResponseBusiness ServiceReceiveEAI File Transport
Input ArgumentTypeValueProperty name
FileNameLiteralC:\TEMP\TestVBCQuery.xml
Output ArgumentTypeValueArgument name
<Value>Output Argument<Value>


TestVBCQuery.xml

<?xml version="1.0" encoding="UTF-8" ?>
<siebel-xmlext-query-ret>
<row>
<value field="Title">Mr.</value>
<value field="First Name">Sara</value>
<value field="Last Name">Chan</value>
</row>
</siebel-xmlext-query-ret>

TestVBCInit.xml

<?xml version="1.0" encoding="UTF-8"?>
<siebel-xmlext-fields-ret>
<support field="Last Name"/>
<support field="First Name"/>
<support field="Title"/>
</siebel-xmlext-fields-ret>


This solution provides a proof of concept for you to build upon, and therefore dosnt include the steps needed to send/recieve or transform your XMLs and there are more elegant ways of querying your XML for a string, but that is left for the reader to play with.

Working with Transports, XML and VBCs are probably one of the most difficult areas of Siebel to work with, but Michael has provided us with a nice foundation for any of us to take this further, and all without writing a line of code.

How to make an invisible Screen

Requirement

Restrict users from navigating and browsing through Client information, this information could be classified and access is provided on a need to know basis. The only way Client information can be accessed is through a drilldown from another part of the application.

Problem

Siebel does not provide any obvious mechanism to hide a Screen completely from the Application. When adding Views to Screens, we are given two options

1. Display in Page
2. Display in Sitemap

The first option, determines wether a view should be displayed when navigating to a Screen, while the later determines wether this view will be show under the Screen link under SiteMap.

But there is no similiar options for a Screen, the best you can do is make the Screen hidden from the page tabs, but this will still show up in the SiteMap.

Solution

Under Application/Screen Menu Item, just blank out the screen name text for the Screen you want to hide. Siebel has some internal logic to prevent screens with empty names to be displayed in SiteMap. Obscure? Absolutely!

Format DTYPE_PHONE EAI phone challenge - Part 2




This will be the conclusion to our series on the DTYPE_PHONE phone challenge.

This solution will pick up where the last article left of from and I am assuming that you already have a WF and have queried your IO to get your message.

For added fun, this is our new beefed up XML message.

<phone>
<home>+610296480999
(00) 0000 0000</home>
<work>+610296480888
(00) 0000 0000</work>
<mobile>+610401123456
0000 000 000</mobile>
<voip>+610296480222
00 0000 0000</voip>
<mum>+610296480111
(00) 00 00 00 00</mum>
<dad>+610296480333
0000 0000</dad>
<brother>+610296480444
00 0000 0000</brother>
<sister>+610296480555
000000000</sister>
</phone>

We will use the technique in the first article to split the phone and pattern using XSLT, and also apply the phone formatting in the same transaction!

Heres the new XSLT that will do the magic for us.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:variable name="CRLF"><xsl:text>&#10;</xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/home"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/work"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mobile"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/voip"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mum"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/dad"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/brother"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/sister"/></xsl:call-template>
</xsl:template>
<xsl:template name="applyPhoneFormat">
<xsl:param name="dtypephone"/>
<xsl:param name="output"/>
<xsl:param name="num" select="substring-before($dtypephone, $CRLF)" />
<xsl:param name="pattern" select="substring-after($dtypephone, $CRLF)" />
<xsl:param name="ploop" select="string-length($pattern)" />
<xsl:param name="nloop" select="string-length($num)" />
<xsl:variable name="patterncursor" select="substring($pattern, $ploop , 1 )" />
<xsl:variable name="numbercursor" select="substring($num, $nloop , 1 )" />
<xsl:choose>
<xsl:when test="$ploop > 0">
<xsl:choose>
<xsl:when test="$patterncursor = 0">
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop - 1"/>
<xsl:with-param name="output" select="concat($numbercursor,$output)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop"/>
<xsl:with-param name="output" select="concat($patterncursor,$output)" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($output,$CRLF)" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

To make this solution work, we needed to have cursors that loops through the phone pattern and build the phone string, but since there is no concept of looping in XSLT (we have the for-each, but that just iterates over the XML nodes, it dosnt do a custom for loop for us), i have used the next best thing, which is build a recursive template to give us the same effect.

I originally designed this solution 3 years ago, but sadly never kept a copy of it when i moved on. So the XSLT you see here is a re-write of the original.

Whenever we use a new technology in our environment, and especially when it uses loops, its prudent to do performance testing to ensure it runs as expected. When i did my testing on the original XSLT against the Xalan (Siebel's XSLT translator which uses the Xerces 1.1 parser) engine in version 7.5, i used a dummy XML with 100 phone numbers, and each phone number had between 8-10 characters for the phone number. When i analysed the logs, the transaction completed within a split millisecond.

This is only a proof of concept, and dosnt handle cases where the user enters the correct phone format, and the system needs to lookup the correct number format, and in the above solution i've chopped of the country code.

The XSLT above hasnt been performance tested, so before you use it in your environment take sometime to analyse the XSLT logic to ensure it meets your needs, and test its performance in your environment, you should be quite surprised by the Xalan engines efficiency.

In the example above, i've included the special formatting characters, but Alex from Siebel Essentials has requested that i show how to send only the numeric phone number.

This was achieved in the first article in the series, by using XSLT to split the phone and pattern portions.

To apply the correct format with spacing, but not non numeric characters such as (,),/,- etc. In other words, we are stripping off all the special characters and just applying the correct spacing.

To do this we just need to modify our XSLT a little.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:variable name="CRLF"><xsl:text>&#10;</xsl:text></xsl:variable>
<xsl:variable name="SP"><xsl:text>&#32;</xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/home"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/work"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mobile"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/voip"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mum"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/dad"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/brother"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/sister"/></xsl:call-template>
</xsl:template>

<xsl:template name="applyPhoneFormat">
<xsl:param name="dtypephone"/>
<xsl:param name="output"/>
<xsl:param name="num" select="substring-before($dtypephone, $CRLF)" />
<xsl:param name="pattern" select="substring-after($dtypephone, $CRLF)" />
<xsl:param name="ploop" select="string-length($pattern)" />
<xsl:param name="nloop" select="string-length($num)" />

<xsl:variable name="patterncursor" select="substring($pattern, $ploop , 1 )" />
<xsl:variable name="numbercursor" select="substring($num, $nloop , 1 )" />

<xsl:choose>
<xsl:when test="$ploop > 0">
<xsl:choose>
<xsl:when test="$patterncursor = 0">
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop - 1"/>
<xsl:with-param name="output" select="concat($numbercursor,$output)" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$patterncursor = $SP">
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop"/>
<xsl:with-param name="output" select="concat($patterncursor,$output)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop"/>
<xsl:with-param name="output" select="$output" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($output,$CRLF)" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Before we leave this topic, i want to touch on the original challenge, which was to retrieve the phone number portion from the DTYPE_PHONE field without using any scripting, and although we've achieved that, plus a whole lot more. Some could argue that the XSLT solution is a form of scripting, but without all the negative associations.

Its not quite black or white, so i'll leave that for you to think about.

Stay tuned for more Impossible solutions!


Format DTYPE_PHONE EAI phone challenge - Part 1




This is the followup article to Strip off Number format in DTYPE_PHONE field (No Script) and also Scriptless Siebel Challenge: Phone Numbers in EAI from Siebel Essentials.

I first came across this problem 3 years ago in a production environment. There was a complaint, that the phone numbers that we were sending across to the external system had inconsistent number formatting.

In Siebel, the phone formatting is controlled by the PHONE_FORMAT LOV. If the user enters in the correct number format, the system will store the number in a compressed format, and use the PHONE_FORMAT lookup to apply to the UI.

However if the user enters in a phone number different to the LOV, the system stores the phone number + the new format string.

The root cause of our problem 3 years ago, was that we had an EIM process that created new and updated existing records. Any phone numbers that were updated by EIM, took the literal value, and not the compressed value that the UI stored.

Example
02 1234 4567 // value from EIM
+611234567 // value from UI using default LOV format
+61021234567|(00) 0000 0000 //value with custom format

All these values could exist simultaneously in the same database column, because the physical type is a varchar(40).

We raised the problem with our TAM, and were told that no declarative means exists and needed to use a custom business service.

The solution that i'm about to share, involves no scripting, and can be applied to all sorts of string challenges.

It nicely meets all of Alex's pre-requisites for a non-scripting solution, ie. It dosnt introduce any custom code to the Applets, Application, BCs, BSs or even use obscure user properties.

Here's my thoughts on this challenge

The DTYPE_PHONE field is a proprietry Siebel format, so there are no standard string functions that will single handedly apply the formatting, there are no documented Siebel user properties that will apply the formatting for us, and to add more complexity the challenge, the user may not want the country codes to be sent across.

Heres how we solve it
Conceptully we need to implement a custom string function that does the following

  1. Split the TYPE_PHONE into a number and a pattern string
  2. Have a cursor that iterates through the pattern string

    • If character = 0 then and place the corresponding position on the number string into an Output property
    • Otherwise place the non numeric character from the pattern string into an Output property

  3. Loop through pattern string and concatenate the Output string until it has finished

I've highlighted key design concepts to solve this problem, now since we cannot use any scripting, the above concept seems impossible, but thats what we are all about.

In the next post i will provide the actual technical solution.


Strip off Number format in DTYPE_PHONE field (No Script)




There is an interesting post Scriptless Siebel - A Challenge over at Alex's Siebel Essentials blog.

One of his readers posts this challenge.

  • Scenario
    "We were sending a Contact Record to external system via HTTP.That contact Record had a field called Work Phone of Dtype_Phone.I guess you might be aware that Dtype_Phones are stored along with Format string which consists of zeroes, if user enterd some space in Phone number like - If User Enters +44123 456 789 then it will be stored in database as -
    +44123456789CRLF000 000 000.

    Now I was using a WF which use EAI Siebel adapter to get Siebel Message. Then I would convert that into xml and send to external system.External system said to remove those zeroes and send.Though there is a delimitter in form of new line between zeroes and actual number, I was unable to do this task in config."
If i am understanding the requirement correctly, it should be quite simple to transform the message in WF, before sending it to the external system.

Assuming our XML looks like this.

<phone>+44123456789
000 000 000</phone>
//Note: there this a real CRLF character between the phone and the phone format

We can use the following XSLT to split the field to return us just the phone number without the format.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="CRLF">&#10;
<xsl:variable name="num" select="substring-before(phone, $CRLF)" />
<xsl:variable name="pattern" select="substring-after(phone, $CRLF)" />
phone: <xsl:value-of select="$num" /> <xsl:value-of select="$CRLF"/>
pattern: <xsl:value-of select="$pattern" /> <xsl:value-of select="$CRLF"/>
</xsl:template>
</xsl:stylesheet>


However, i think we can make it better, so i would like to propose a new challenge.

Following the above scenario, get the DTYPE_PHONE value, extrapolate the pattern and apply it to the phone number on the fly before sending out to the external system (this of course must be done without any sort of custom script).

eg. The system must take this format "000 000 000" and apply it to "+44123456789" to output "+44 123 456 789"

Stay tuned to see the solution to the problem.