Siebel Code Challenge – #3

UPDATED: My old friend Terrence was the first to spot the ‘deliberate’ mistake. Property sets can be your friend – they offer a persistent and flexible mechanism to move pairs of name, value strings across entities. However, the Siebel compiler is unable to spot situations where not all control paths set an expected value on the output property set. In this case, we were seeing occasional errors in our logs with the text “Argument ‘x’ in step ‘y’ is not correctly initialized or does not return valid data”. This is because the code was failing to set an expected output value which caused the Workflow to throw an exception and prevent a critical business process from executing correctly.

Another anomaly for you to decipher – an easy one again today! Once more, I must emphasise that these are examples of code and configuration that I’ve found in live, Production Siebel environments. I’m not posting these to shame anybody (well, maybe a little) but to show how the simplest mistake or ommission can comprimise the functionality and data quality within Siebel.

Virtual prize for the first to point out the obvious mistake!

Note that this function forms part of a Business Service that is invoked from a Workflow Process Step. The Process uses the output to determine what to do next.

function CodeChallenge3(Inputs, Outputs)
{
  // Declare variables
  var boContact, bcContact;

  try
  {
    // Instantiate new BC instance
    boContact = TheApplication().GetBusObject("Contact");
    bcContact = boContact.GetBusComp("Contact");

    with (bcContact)
    {
      // Create query context
      ClearToQuery();
      SetViewMode(AllView);
      SetSearchSpec("Id", Inputs.GetProperty("ContactId"));
      ExecuteQuery(ForwardOnly);

      // Record is found
      if (FirstRecord())
      {
        Outputs.SetProperty("Found", "true");
      }
    }
  }
  catch(e)
  {
    // Call the custom LogError function to write error to error log
    LogError("Woops, an error has occurred!");
  }
  finally
  {
    // Destroy objects
    bcContact = null;
    boContact = null;
  }
}

Answers on a postcard or post in the comments block below!

VN:F [1.9.14_1148]
Rating: 0.0/10 (0 votes cast)

Siebel Code Challenge – #2

UPDATED: Okay, Rick wins this one with an early correct answer! Definitely an easy one but I was surprised to come across this. Never underestimate ‘schoolboy errors’ creeping in to code! I’ve seen plenty of occurrences of using the assignment operator (=) in place of the equality operator (==) but this was the first time I’d come across it the other way around! Well done to all who spotted the mistake and to everyone who identified other issues in the code. Note that the field was Force Active, I just forgot to tell you. ;) Virtual pints all round, I think!

An easy one this time round. However, as before, this is a genuine coding error that I found in a live Siebel environment! As usual, a virtual prize (i.e. no prize) to the first poster to spot what’s wrong!

function CodeChallenge2(sContactId)
{
  // Declare variables
  var boContact, bcContact;

  try
  {
    // Instantiate new BC instance
    boContact = TheApplication().GetBusObject("Contact");
    bcContact = boContact.GetBusComp("Contact");

    with (bcContact)
    {
      // Create query context
      ClearToQuery();
      SetViewMode(AllView);
      SetSearchSpec("Id", sContactId);
      ExecuteQuery(ForwardOnly);

      // If record is found, update the status
      if (FirstRecord())
      {
        SetFieldValue("Status", "Active");
        WriteRecord();
      }
    }
  }
  catch(e)
  {
    // Call the custom LogError function to write error to error log
    LogError("Woops, an error has occurred!");
  }
  finally
  {
    // Destroy objects
    bcContact == null;
    boContact == null;
  }
}

Answers on a postcard or using the comments box below!

VN:F [1.9.14_1148]
Rating: 0.0/10 (0 votes cast)

Siebel Code Challenge – #1

UPDATE: Well done to Ranjith for spotting the error: the RaiseErrorText will itself raise on exception, which is trapped and ignored by the catch statement. As a result, the message that the developer thinks the user will see will be suppressed and never display. Ranjith chose a virtual pint of lager as his reward – more code challenges to follow so more opportunities to win non-existent prizes! :)

I came across the following code the other day in a live Siebel environment. There’s a free virtual pint to whomever first identifies what’s wrong with this picture!

function CodeChallenge1(sContactId)
{
  // Declare variables
  var boContact, bcContact;

  try
  {
    // Instantiate new BC instance
    boContact = TheApplication().GetBusObject("Contact");
    bcContact = boContact.GetBusComp("Contact");

    with (bcContact)
    {
      // Create query context
      ClearToQuery();
      SetViewMode(AllView);
      SetSearchSpec("Id", sContactId);
      ExecuteQuery(ForwardOnly);

      // If record is not found, inform the user
      if (!FirstRecord())
      {
        TheApplication().RaiseErrorText("Record not found! Try again.");
      }
    }
  }
  catch(e)
  {
    // Call the custom LogError function to write error to error log
    LogError("Woops, an error has occurred!");
  }
  finally
  {
    // Destroy objects
    bcContact = null;
    boContact = null;
  }
}

Answers on a postcard – or use the comments box below! :)

 

VN:F [1.9.14_1148]
Rating: 0.0/10 (0 votes cast)

Hiding Applet Controls

Christmas is fast approaching and it’s all change here at Ollerenshaw IT! ;) Our Siebel upgrade project is on hold and I’m back in the development hotseat, doing what we all secretly love doing best – writing code!

Working in Siebel 8 shows just how things have moved on since the old days of Siebel 99, 6 and Siebel 7. Nowadays, we have loads of User Properties at our disposal and there’s less and less of an excuse to write script. Inevitably, however, Oracle haven’t quite thought things through and we have to resort to good old eScript. It’s just the way of things.

This week I came across an annoying oversight. A simple requirement to hide a button on an applet for all but a select Responsibility. Easy peasy, surely? Not so!

A quick search reveals a number of Blog entries, including one from Alex Hansal’s fantastic site, detailing a ‘Hide Control’ user property. Alas, this property is only available on a very small subset of Applet classes and so cannot be used as a ubiquitous solution.

And so we must turn to code and configuration.

Again, there are a number of Blog posts out there that provide this information, but I just wanted to go a little further and provide a full solution with some little hints and tips. Here’s what I did:

  1. Create a new field in the Personalization Profile BC, to tell us if the user has the appropriate Responsibility
  2. Name: OLI – HasAdminResp
    Calculated: Y
    Calculated Value: IIf(InList(‘Siebel Administrator’,GetProfileAttrAsList(‘User Responsibilities’)), ‘Y’, ‘N’)

  3. Now, add some Browser Script on the Applet_Load event to hide the control, based on the the new Profile Attribute:
function Applet_Load ()
{
/******************************************************************************
* Created By: Iain Ollerenshaw
* Created On: 12th December 2011
* Purpose: Called on Applet Load
*
* Modification History:
*
* Date Who Comment
* 12/12/2011 Iain Ollerenshaw Added code to hide 'Admin' button
******************************************************************************/

// First, determine if user has the 'Siebel Administrator' Responsibility
var isAdmin = TheApplication().GetProfileAttr("Me.OLI - HasAdminResp");

// If not, find and hide the control
if (isAdmin == "N")
{
	var oCtrl = this.FindActiveXControl("Admin");
	if( oCtrl != null )
	{
		// Hide the control
		oCtrl.style.visibility="hidden";
	}
}
}

It’s a shame that so much code is required to do something so simple. Hopefully, ‘Hide Control’ will make it into the base classes sometime in the future.

Happy Holidays! :)

VN:F [1.9.14_1148]
Rating: 9.7/10 (3 votes cast)