Wednesday 13 November 2019

Calculating Difference Between two dates in Siebel eScript - Part 2

Hello All,

I my previous post we calculated difference between 2 Dates i.e. Sysdate and Other date that was stored in Database in Date format.

Recently i had to compare a date stored as varchar in database with sysdate.

Var storedDate = '30-11-1990' ;

I had to compare if the var storedDate is greater then current date or not, its very easy we just need to make the variable a date object.

Note: The format of string to be passed should be DD/MM/YYYY
var storedDate = '01/11/2019';
var dd2 = storedDate.substring(0,2);
var mm2 = storedDate.substring(3,5);
var yy2 = storedDate.substring(6,10);
var formatedStoredDate= dd2 + "/" + mm2 + "/" + yy2;

now we have date in DD/MM/YYYY format, lets convert this to date Object

var nDate = new Date (formatedStoredDate);

to compare this date with current date ,

var currDate = new Date ()

if (nDate > currDate )
{
// Stored date is Greater
}
else
{
//stored date is smaller
}

Tuesday 15 October 2019

Update Records in Siebel Scripts - Chat UI Business Service

Hello All,

Whenever we require to update a record we use Inbound Email Database Operations Business Service, but this BS has a major limitation if there are no records matching the search Specification it throws an error which is not desirable and requires us additional error handling.

Query Using Inbound Email Database Operations,





var sBusService = TheAppliation().GetService("Inbound E-mail Database Operations");
var Inputs = TheAppliation().NewPropertySet();
var Outputs = TheAppliation().NewPropertySet();
Inputs.SetProperty("BusComp", "Order Entry - Line Items");
Inputs.SetProperty("BusObj", "Order Entry (Sales)");
Inputs.SetProperty("QueryFields", "Id");
Inputs.SetProperty("Id",Order_Item_Id);
Inputs.SetProperty("ValueFields", "Order Header Id");
Outputs =  sBusService.InvokeMethod("FindRecord",Inputs);                                   




error returned , 

No record matching the search specification is found.(SBL-CMI-00122)



The Alternative ,

Chat UI Business Service's FindRecord method, this uses the same inputs and does not return any error in case no records are found.
syntax:



var sBusService = TheAppliation().GetService("Chat UI Business Service");
var Inputs = TheAppliation().NewPropertySet();
var Outputs = TheAppliation().NewPropertySet();
Inputs.SetProperty("BusObj", "Order Entry (Sales)");
Inputs.SetProperty("BusComp", "FS Invoice");
Inputs.SetProperty("QueryFields","Order Id");
Inputs.SetProperty("Order Id", "1-3B39B13S_1");
Inputs.SetProperty("ValueFields","Invoice Number");`
Outputs =  sBusService.InvokeMethod("FindRecord",Inputs);                                               

Writing Output in XML file - EAI XML Write to File

Hello All,

I was working on a requirement where after performing a update action i needed to capture the records in a file for EOD verification.
There are multiple ways to achieve this, i used WritePropSet method of EAI XML Write to File Business service.

Approach 1: 
Use Property Set to store Output and call PropSetToXML method of EAI XML Converter Business Service , then call EAI XML Write to File Business service's WriteXMLHier method to get the final XML.

Approach 2: 
Use Property Sets to store data , in Hierarchical Format (i.e. create Property sets in a way to maintain Hierarchical structure), then call EAI XML Write to File Business service's WritePropSet method to get the final XML.

Final Code :



Storing Data in Outputs:

var outPropset1 = TheApplication().NewPropertySet() ;//for output logging
outPropset1.SetType("Processed Invoices") ;
outPropset1.SetValue("Invoice Number :"+sInvoiceNum) ;
Outputs.AddChild(outPropset1);                                                                                                 




Passing Output in EAI Write to File:

var timestamp = new Date();
var month = timestamp.getMonth() + 1;
timestamp=timestamp.getDate()+"-"+month+"-"+timestamp.getFullYear()+" "+timestamp.getHours()+":"+timestamp.getMinutes()+":"+timestamp.getSeconds();

var XMLConvertorBS = TheApplication().GetService("EAI XML Write to File");
var xInputs = TheApplication().NewPropertySet();
var xOutputs = TheApplication().NewPropertySet();
Outputs.SetProperty("FileName","/siebel_as/ses/siebsrvr/temp/ProcessReceipt"+timestamp+".xml");

XMLConvertorBS.InvokeMethod("WritePropSet",Outputs,xOutputs);                                                                                                



Final XML:

  <?xml version="1.0" encoding="UTF-8" ?>
  <?Siebel-Property-Set EscapeNames="true"?>
  <PropertySet>
  <Processed Invoices>Invoice Number :81KHH66464</Processed Invoices>
  <Processed Invoices>Invoice Number :81KHH66465</Processed Invoices>
  <Processed Invoices>Invoice Number :81KHH66466</Processed Invoices>
  <Processed Invoices>Invoice Number :81KHH66467</Processed Invoices>
  </PropertySet>


 more detailed ways of manipulating Property sets :

 http://www.siebelfoundations.com/2016/08/working-with-property-sets-in-siebel.html

Deleting Multiple Records in Siebel Script

Hello All,

Recently i had a requirement wherein i wanted to delete some records in Script.
Its very simple but i was missing a very basic thing.


while(FRecord)   

     FRecord = DeleteRecord();
    FRecord = NextRecord(); 
}                                                                                                               


This script deleted only the first record not subsequent record, reason was just after deleting the records the cursor was set to First Record so NextRecord was not fetching any results.
Final Script required me to call FirstRecord again after performing DeleteRecord.

Working Code:


with(ErrorBC)
{
   ActivateField("Error Object");
   ClearToQuery();
   SetViewMode(AllView);
   SetSearchSpec("Error Object", "Todays Failure");//Deallocate 0-D5B3
   ExecuteQuery(ForwardBackward);
   var FRecord=FirstRecord();
   while(FRecord)   

FRecord = DeleteRecord();
    //This did the trick. The Cursor would always be reset to First record and the deletion went fine.
      FRecord=FirstRecord();

}
}

Thursday 8 August 2019

Handling Special Characters in Siebel Script

Hello All,

Recently i was working with a very basic requirement where in i had to restrict user from entering some special character in a fields.

@$&*!?~^

#

>

<

|...etc


We had done this earlier with the below code , though the code is perfect but still has some undesired looping

        var HouseNumber = this.GetFieldValue("House Number");
if ((HouseNumber != ""))
  {
  var RegillegalChars = "\\-)(,:;@*_=?.`<>[]{}!£$%^&*#/~|+' '";
      for (c=0;c< RegillegalChars.length;c++)
    {
    fax_char = RegillegalChars.substring(c,c+1);
    if (Regno.indexOf(fax_char,0) != -1)
    {
TheApplication().RaiseErrorText("'House Number' contains the "+"\'"+ fax_char +"\'"+" char. This is not allowed.");
    }
    }//for loop
    }
i was going through some javascripts sites and found on more way of achieving this,

charCodeAt(0), function that checks for the first character in a variable

and using ascii values for the variable rather then the char value, so the code modified as

var HouseNumber = this.GetFieldValue("House Number");                                                
if(HouseNumber.charCodeAt(0) <= 47)
{
TheApplication().RaiseErrorText('Invalid Character!');                                                       
}

we avoided multiple loops, and achieved the same functionality :-)

*I have used 47, as the ASCII values for special characters are less then 47 , for complete list see below
https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html

Related Post, http://www.siebelfoundations.com/2019/08/handling-special-characters-in-siebel.html

Wednesday 19 June 2019

Modifying Labels in List Applets: Applying Color Coding

Hello All,

Recently i got a query from one of my friend, where in he wanted to have header labels in list applets to be in different color.

i.e. Suppose in Contact List Applet , first 5 fields that have Personal Information appear with red Label,
Next 5 with Address Information appear in Green label and last 5 with Random Information appear in blue label.

Seems pretty simple isn't it.

Well actually it is a bit tricky, why? you might ask and will only know the catch when you try to achieve this.



The issue is with the Id's(Dynamic Id) siebel generated for the labels , one time id will be say jqgr_2_1_first_name and at the next login it will be jqgr_2_4_first_name 

So any hard coded Id's will not work :-( , Now we need to traverse the applet to always fetch current Id's for the label and then apply any CSS changes,

below snippet of code needs to be used.

var pm = this.GetPM();var appletFullId = this.GetPM().Get("GetFullId");var appletPlaceHolder = $("#s_" + appletFullId + "_div"); // example: "s_S_A5"


$(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[1].childNodes[1].id; // label of first element in list applet


$(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[2].childNodes[1].id; // label of second element in list applet


  • Here we are first finding the applet Id (appletPlaceHolder )
  • then we are searching for the labels in Label row (ui-jqgrid-labels') ,
  • then finding the Id for the label sequentially, .childNodes[1].childNodes[1].id; for 1st and .childNodes[2].childNodes[1].id; for 2nd
the last step is to apply css of formatting 

this can be done via 2 ways , 

1. Inline CSS 

var Label1 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[1].childNodes[1].id; /$("#" + Label1).css({'color':'red'});

2. Add Class Method (Need a custom css or need to add teh new style in existing css

var Label1 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[1].childNodes[1].id;
$("#" + Label1).addClass('label-color-red');

Link to PR file,


or you can use below PR file, 

if (typeof (SiebelAppFacade.ModifyControl) === "undefined") {
SiebelJS.Namespace("SiebelAppFacade.ModifyControl");
define("siebel/custom/ModifyControl", ["siebel/jqgridrenderer"], function () {

SiebelAppFacade.ModifyControl = (function () {

function ModifyControl(pm) {
SiebelAppFacade.ModifyControl.superclass.constructor.apply(this, arguments);
}

SiebelJS.Extend(ModifyControl, SiebelAppFacade.JQGridRenderer);

ModifyControl.prototype.ShowUI = function () {
var pm = this.GetPM();

SiebelAppFacade.ModifyControl.superclass.BindEvents.apply(this, arguments);

}

ModifyControl.prototype.BindEvents= function () {

var pm = this.GetPM();
var placeHolder = "s_" + pm.Get("GetFullId") + "_div";
var appletFullId = this.GetPM().Get("GetFullId");
//var pm = this.GetPM();
var appletPlaceHolder = $("#s_" + appletFullId + "_div"); // example: "s_S_A5"


           //     $("#" + placeHolder).find("Complaint Number")
      var Label1 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[1].childNodes[1].id;
                $("#" + Label1).addClass('color-control');
var Label2 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[2].childNodes[1].id;
                $("#" + Label2).addClass('color-control');
var Label3 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[3].childNodes[1].id;
                $("#" + Label3).addClass('color-control');
var Label4 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[4].childNodes[1].id;
                $("#" + Label4).addClass('color-control');


var Label5 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[5].childNodes[1].id;
                $("#" + Label5).addClass('color-controlblue');
var Label6 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[6].childNodes[1].id;
                $("#" + Label6).addClass('color-controlblue');
var Label7 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[7].childNodes[1].id;
                $("#" + Label7).addClass('color-controlblue');
var Label8 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[8].childNodes[1].id;
                $("#" + Label8).addClass('color-controlblue');

var Label9 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[9].childNodes[1].id;
                $("#" + Label9).addClass('color-controlgreen');
var Label10 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[10].childNodes[1].id;
                $("#" + Label10).addClass('color-controlgreen');
var Label11 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[11].childNodes[1].id;
                $("#" + Label11).addClass('color-controlgreen');
var Label12 = $(appletPlaceHolder).find('.ui-jqgrid-labels')["0"].childNodes[12].childNodes[1].id;
                $("#" + Label12).addClass('color-controlgreen');
SiebelAppFacade.ModifyControl.superclass.BindEvents.apply(this, arguments);
}

return ModifyControl;
}());
return "SiebelAppFacade.ModifyControl";
})
}




Custom Login Page in Siebel Open UI

Hello All,


In this Post i want to demonstrate how we can change login page in Siebel Application.
Login page is specified for every application and can be seen in Object Explore --> Application


Below are the high level Steps

1. Identify the Login Web Page from Application






2. Open The Web Page in Object Explore and find the Web Page, clone the existing page and Provide a new Web Template





3. Clone the Existing Web Template, in my case i named it Login Custom, change the definition of web template to refer new custom CSS and JS files
<link href="files/login_custom.css" rel="stylesheet"> --- line 8

<div od-type="include-script" file="login_custom.js"/> --- line 16






4. Now we have New Web Page and Web Template, replace Web Page for the application and test your changes






Vanilla Login Page:


Modified Login Page:




link to CSS file :

https://drive.google.com/open?id=1IwMdKAgWwFqQO7OC7O8hHtELwPe2iu0J

Wednesday 12 June 2019

Navigation One Record at a time in Siebel IP17/18

Hello All,


In this post i will share one of the enhancement or probably i should call it fix for enabling navigation to one record at a time that has been removed in siebel IP17 onwards.

In Open UI we have now navigation controls in bottom of applet In IP 13 to IP 16, we have below controls
  1. Next Record
  2. Previous Record
  3. Next Record Set
  4. Previous Record Set



In IP17 onwards there is change in navigation controls, now there is no option of Next and Previous record in list applet, we now have

  1. Next Record Set
  2. Previous Record Set
  3. Last Record Set
  4. First Record Set



Now with the below code we can mimic the buttons to act like IP 13 to IP 16
Major Points:

1. Remove/Supress the actual functionality of Buttons,


$('[id^="next_pager_s_"]').attr('id', '');
$('[id^="last_pager_s_"]').attr('id', '');
$('[id^="first_pager_s"]').attr('id', '');

$('[id^="prev_pager_s_"]').attr('id', '');

2. Bind Click event with the Icons to perform the naviation

$('[title="Next record"]').on("click", function (e) {

if (pm.ExecuteMethod("CanInvokeMethod", "GotoNext")) {
pm.ExecuteMethod("InvokeMethod", "GotoNext");
}
e.stopImmediatePropagation();


});

if (typeof (SiebelAppFacade.DefaultNavigationPR) === "undefined") {
SiebelJS.Namespace("SiebelAppFacade.DefaultNavigationPR");
define("siebel/custom/DefaultNavigationPR", ["siebel/jqgridrenderer"], function () {

SiebelAppFacade.DefaultNavigationPR = (function () {

function DefaultNavigationPR(pm) {
SiebelAppFacade.DefaultNavigationPR.superclass.constructor.apply(this, arguments);
}

SiebelJS.Extend(DefaultNavigationPR, SiebelAppFacade.JQGridRenderer);


DefaultNavigationPR.prototype.BindEvents = function () {
$('[id^="next_pager_s_"]').removeClass('ui-state-disabled');
$('[id^="last_pager_s_"]').removeClass('ui-state-disabled');
$('[id^="first_pager_s"]').removeClass('ui-state-disabled');
$('[id^="prev_pager_s_"]').removeClass('ui-state-disabled');
$('[id^="next_pager_s_"]').attr('id', '');
$('[id^="last_pager_s_"]').attr('id', '');
$('[id^="first_pager_s"]').attr('id', '');
$('[id^="prev_pager_s_"]').attr('id', '');
var pm = this.GetPM();
var placeHolder = "s_" + pm.Get("GetFullId") + "_div";
var that = this;
var appletFullId = this.GetPM().Get("GetFullId");
//var pm = this.GetPM();
var appletPlaceHolder = $("#s_" + appletFullId + "_div"); // example: "s_S_A5" 



$('[title="Next record"]').on("click", function (e) {

if (pm.ExecuteMethod("CanInvokeMethod", "GotoNext")) {
pm.ExecuteMethod("InvokeMethod", "GotoNext");
}
e.stopImmediatePropagation();


});
$('[title="Previous record"]').on("click", function (e) {

if (pm.ExecuteMethod("CanInvokeMethod", "GotoPrevious")) {
pm.ExecuteMethod("InvokeMethod", "GotoPrevious");
}
e.stopImmediatePropagation();


});


$('[title="Previous record set"]').on("click", function (e) {

if (pm.ExecuteMethod("CanInvokeMethod", "GotoPreviousSet")) {
pm.ExecuteMethod("InvokeMethod", "GotoPreviousSet");
}
e.stopImmediatePropagation();

});

$('[title="Next record set"]').on("click", function (e) {

if (pm.ExecuteMethod("CanInvokeMethod", "GotoNextSet")) {
pm.ExecuteMethod("InvokeMethod", "GotoNextSet");
}
e.stopImmediatePropagation();

});



SiebelAppFacade.DefaultNavigationPR.superclass.BindEvents.apply(this, arguments);
}

return DefaultNavigationPR;
}());
return "SiebelAppFacade.DefaultNavigationPR";
})
}

there was a miss in the PR file as reported by one reader,  this has been catered in related post 

Bringing back HI like navigation in Siebel IP 18

Hello All,

As explained in my previous Post Scrolling In List Applet , i explained how can we get scrolling in list applet from mouse scroll.
In previous post we were calling Next Record Set and Previous Record Set on scroll.

Here we will use the same approach but will navigate to Next Record and Previous Record not Full Record set.

The Code is almost the same, just a minor change in method.

pm.ExecuteMethod("InvokeMethod", "GotoNext");

Sample code:

$(appletPlaceHolder).bind('mousewheel', function (e) {
if (e.originalEvent.wheelDelta / 200 > 0) {
//console.log('scrolling up !');
e.preventDefault();
if (pm.ExecuteMethod("CanInvokeMethod", "GotoPrevious")) {
pm.ExecuteMethod("InvokeMethod", "GotoPrevious");
}
e.stopImmediatePropagation();


} else {
//console.log('scrolling down !');
e.preventDefault();
if (pm.ExecuteMethod("CanInvokeMethod", "GotoNext")) {
pm.ExecuteMethod("InvokeMethod", "GotoNext");
}
e.stopImmediatePropagation();

}
});

<<Parent Post >>

Wednesday 24 April 2019

Refreshing an Applet in Siebel : FINS Teller to the Rescue

Hello All,

This is a very basic requirement where in we need to refresh the applet once some changes has been done to BC field or a new record has been added.

There are various approaches to this

1. Execute a blank query after doing you operation 

2. Execute RefreshBuscomp method of BC , 

this.BusComp().InvokeMethod("RefreshBuscomp");

3. My Favourite, FINS Teller UI Navigation, as this is vanilla BS and maintains the context of the selected record.

Code,

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

or you can invoke the BS in the below syntax including the parameter "RefreshAll"

 var svc = TheApplication().GetService("FINS Teller UI Navigation");
 var psIn =  TheApplication(). NewPropertySet();
 var psOut =  TheApplication(). NewPropertySet();
 psIn.SetProperty("RefreshAll","Y");
 svc.InvokeMethod ("RefreshCurrentApplet", psIn, psOut) 



Favourites Windows in Siebel : Siebel Open UI Enhancement

Hello All, 

We have Recent record functionality in Siebel which is quite useful in navigation to recently accessed records.

Keeping the functionality as base and referring my Previous post on bookmarks, i have tried to implement a similar functionality, "My Favorites" 

In this functionality 

  • User can Mark a record as Favourite using the Button Add Favourite, You can give you Own Name to the favourites or it will take the Name with Entity + Row Id by Default 

  • The Added Favourite will appear in a floating window on the left corner of the screen

  • Clicking on the link will navigate the user to the detail of the record




  • There is no restriction of View/BO/Visibility i.e. if i am in Service View i can be navigated to any view
  • User can remove the Added link by clicking the X icon to keet the list updated 


Features 

  • This is based on Pure JavaScript, So lightweight
  • No Siebel BC/BO instance required
  • Works on 3rd Level View Tabs also i.e works on Parent-Child-Grandchild hierarchy as well
  • The List is stored in browser local storage so no Siebel data base is instantiated 
  • You can give you Own Name to the favorites or it will take the Name with Entity + Row Id by Default 


Short coming

N/A, As of now :-) 


Key Component of code 

get the exact URl formed when a record is navigated

  •  k = window.location.href;   

Appending to list each time Add favourite is clicked
  • $('#favorite-links').append('<li><a href="'+k+'">'+finaltext+'</a><button class="removebtn">x</button></li>');

Storing the List to local Storage of browser

  • localStorage.setItem('vk-links', $('#favorite-links').html());


Link to File 

Tuesday 12 March 2019

Bookmarks in Siebel : Use of Browser Web Storage

Hello All,

Recently i tried to mimic one very important feature of browser, the bookmarks.
Bookmarks store our saved web pages/ links to important websites which we want to visit again or are frequently accessed by us.

So i tried to built something in siebel UI wherein i can store some important websites and access them from siebel only.

Web storage which is property of browser, is the key to store this data.




Below is the sample solution ,                               


Links Applet on Home Page



Option to Add new link







Working Solution 






















  • Need a Container to capture the website information and store it in web storage 

var a = '<div id="container"><div id="header"><h2>My Favorite Links</h2><small>save your best links</small></div><div id="content"><ul id="favorite-links"><li><a href="http://www.siebelfoundations.com">Siebel Foundations</a><button class="removebtn">x</button></li><li><a href="http://www.google.com">Google</a><button class="removebtn">x</button></li><li><a href="https://support.oracle.com/">Oracle Support</a><button class="removebtn">x</button></li></ul><div id="new-link-button"><button>Add New Link</button></div></div><div id="add-link-form" style="display: block;"><label>Title</label><br><input id="title" placeholder="Title here"><br><label>URL</label><br><input id="url" value="http://"><br><button id="add">Save Link</button></div></div>'

$('#_swecontent').prepend(a);  // append it to page

  • Since this information is stored in web storage, values persists even after logout of application and no siebel files, Database is required

localStorage.setItem('vk-links', $ul.html());   // use of web storage       

Sample code for this can be found on , https://codepen.io/4gray/pen/glGun

                        
Limitation 


  • If we clear browser cache the values stored in web stores vanishes.


Benefits


  • No Database, Files, Preference file is accessed 
  • Lightweight and customizable to include links to internal screens and views (haven't yet explored this but feasible) --Tried to extend this functionality for Siebel View Navigation and it worked see article 



Thursday 7 March 2019

Tree Hierarchy in Siebel Open UI

Hello All,

In this post let us try to show data from a Entity in a Tree structure, to show a 360 Degree view all related entities in one place


Use Case, 

For any Entity Say contact if we need to See its related Opportunities, Account or Orders, we need to first drill down on contact and from 3rd level view bar navigate to particular view to see its details,

This approach can bring in all related entities in one view so avoiding any drill down and additional Navigation 

Solution, 

  • The implementation of its solution is very simple, we need to capture full details of current Contact in XML format so we can use any IO based on contact, 
  • Get IO Hierarchy using EAI Siebel Adapter Business Service 
  • Get XML by converting IO Hierarchy to XML using EAI XML Converter


Now we have XML, we need to display the XML in Expandable Format to mimic a tree structure,





















You can have multiple modification in the structure to include Drill downs, color combination etc.

Sample Code, 
https://drive.google.com/open?id=1EIxHVcwKJxz-IGfpzjFIuU52kHlQVUkw


Reports in Siebel Open UI without BI Publisher

Hello All,

in this post let us explore report generation functionality in siebel.
Generally we have BIP integration with siebel for any report generation.

RTF files/Templates are uploaded in siebel and we can genrated reports in the uploaded format.

I tried to achieve something that can generate reports/PDF files without BI Publisher, seems a bit absured but its achieveable.
Though it cannot get all the functionalites of BI Publisher but it servers the purpose for simple reports

The Solution

1. Get the values which we need to display in Report in PR file
2. Generating HTML in Desired format with field values/records from a PR file
3. Call 3rd party plugin to convert the HTML to Canvas and then to pdf

here's the output,

Click on Open Summary it displays a Preview and when i click on Generate Report, PDF for reports gets generated and downloaded













Benefits,


  • Although it cannot replace BI Publisher, but can be used for certain reports that are single page and require no/less calculations
  • Since no BIP is used, can be set up for some priority reports which are very critical and cannot afford  BIP unavailablility
  • No Cost included, so free :-)


Disadvantages

  • Since it works on HTML, so complex logics and multi page reports cannot be build
  • Need Individual Coding/Setup for each report which will be difficult to maintain
  • Generated Reports are not very clear i.e. qualty of pdf generated is not very good
  • Dependent on 3rd party,

Open UI Code

3rd Party Jquery required,

  • https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.22/pdfmake.min.js
  • https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js
Code that generates the PDF


$('.open-report').click(function () {
                html2canvas($('#report123')[0], {
onrendered: function (canvas) {
var data = canvas.toDataURL();
var docDefinition = {
content: [{
image: data,
width: 500
}]
};
pdfMake.createPdf(docDefinition).download("Table.pdf");
}
})

Complete Code, 

https://drive.google.com/open?id=14qCed01MaqnoN9rKJU-AWVQcaHSC5A0e





Thursday 28 February 2019

Timeline in Siebel : Siebel Open UI Enhancement

Hello All,

With OpenUI siebel UI/UX has unlimited room for innovations and development.

So i tried to make some changes in UI to get the feel of modern HTML5 based applications, a Timeline is what i tried to convert an applet into.

The Idea is pretty simple, for the business entities that displays data relative to time, show that in a timeline view to make the UI better, Informative and easy to understand for end user.

below is what i achieved, there can be a lot of improvement/modification in this which you can try


  • A Timeline view of Applet
















The Solution ,

  • Need to Identify the business entity , i am using address for illustration, others can be Audit Trail, Activity Stages, Opportunity / SR Life Cycle, Sales/ Service History, Interaction History.  
  • Embed the HTML and CSS in your PR file, you can either write inline CSS or create a separate CSS file

Note ,

the main work here is how to pass Siebel data to HTML i.e. how to pass list applet data to HTML container.

for this we can use, GetRecordSet



var pm = SiebelApp.S_App.GetActiveView().GetActiveApplet().GetPModel(); // for Application level PR

var pm = this.GetPM(); // for Applet level PR

b = pm.Get("GetRecordSet"); // for getting the record in Array b



And data can be extracted from array b , in below format

  b[i] [j]

i refers to the index of record
and
j refers to the column

e.g.

 var a = b[0]['City'];   // city for first record of applet
 var c = b[0]['Street Address'];  // Address for first record of applet


Working Code,

https://drive.google.com/open?id=1GkUbBiGw_WG0Z_uLFCfpfXwLZeVLSNaY

Wednesday 27 February 2019

Configuring Confirm Popup on New Record

Hello All,

I this post let us experiment with a very common functionality in Siebel.
Confirm Popup on deleting a record.



lets try to make something for New record also, wherein a prompt will appear confirming for new record creation.



to achieve this we need to identify the method invoked ,

  • we can use notification handler SWE_PROP_BC_NOTI_NEW_RECORD for the purpose


Display a prompt and based on user selection continue or cancel the operation


pm.AttachNotificationHandler(consts.get("SWE_PROP_BC_NOTI_NEW_RECORD"), function(){
               var retVal = confirm("Do you want to create a new record ?");
               if( retVal == true ) {
                  //document.write ("User wants to continue!");
                  return true;
               } else {
                pm.ExecuteMethod("InvokeMethod","UndoRecord");
               
               }
})

sample code for reference,

https://drive.google.com/open?id=1RVNemftNr2w1zfWUkJhnLYbrcf20Yi8-


Tuesday 12 February 2019

Preventing Unresponsive Sessions for Long Queries

Hello All,

In siebel Open UI there is Issue which most of us might have faced.

If we navigate to a view or Run a query and it takes more the 30 seconds,

  • The Busy cursor on the screen disappears 
  • The page becomes unresponsive as query is yet running in background 
  • and most likely we end up clicking randomly and session becomes unresponsive
so, to overcome this scenario lets try to break it into parts and find its solution

  • When a query is Fired , initiate a function to show some message that notifies Query has stated execution
  • When Query finished, notify that query has executed
  • In the Meanwhile from Executing Query to Fetching Results, show some message to user or Block the screen to prevent user interaction
The Solution :


  • Identify Query is Executed , 


$('.siebui-icon-executequery').click(function(){ // do something her to prevent user clicking on screen })


  • Notify Application that Query has finished execution ,


pm.AttachNotificationHandler(consts.get("SWE_PROP_BC_NOTI_END_QUERY"), function(){
  //alert("after query has completed fetching result");
})


  • Block the UI till Query fetches results


$('.siebui-icon-executequery').click(function(){   
var text = "Wait.. Fetching Results ";
    $("<table id='overlay'><tbody><tr><td>" + text + "</td></tr></tbody></table>").css({
        "position": "fixed",
        "top": 0,
        "left": 0,
        "width": "100%",
        "height": "100%",
        "background-color": "rgba(0,0,0,.5)",
        "z-index": 10000,
        "vertical-align": "middle",
        "text-align": "center",
        "color": "#fff",
        "font-size": "30px",
        "font-weight": "bold",
        "cursor": "wait"
    }).appendTo("body");})


sample working example looks like,





Benefits:


  • Overlay will be there till query completes execution 
  • Prevents unnecessary session unresponsiveness due to random click 
  • No 3rd Party jQuery Pluign , uses siebel PM methods


Sticky Notes in Siebel - Siebel Open UI Enhancement

Hello All,

The Title of the post may seem a bit absurd, as what can be the connection of Sticky Notes with Siebel.

But this post is inspired by yellow colored sticky notes which we generally use to jot down some tasks or write important memos.

So, the idea is to make something in siebel, that can be used as a writing pad where we can write some details like Account Name, Password, Username, Frequently used Entities, Mobile number etc.




My Approach,

I wanted to make this SRF and Database Independent , so i decided to juggle with SPF file.
SPF or user preference file in siebel is system generated file that stores details like

  • Last Navigated Records, which we call Recent Records
  • View and Tab Layout
  • Fields Layout
  • Theme Preferences etc.


Now, we need a way to read and write to SPF file and Expose it to logged in user for editing.

Below line of code does the purpose of updating SPF file

pm.OnControlEvent(consts.get("PHYEVENT_INVOKE_CONTROL"),pm.Get(consts.get("SWE_MTHD_UPDATE_USER_PREF")), inputPS);


Detailed Code :


 var inputPS = CCFMiscUtil_CreatePropSet(); 

 //get last value of User Prefrence
 var value = pm.Get ("User-Notes"); 

//set User Prefrence Name
inputPS.SetProperty("Key", "User-Notes");  

//set User Prefrence Value
inputPS.SetProperty("User-Notes", Notes);  
pm.SetProperty("User-Notes", Notes);  

//set our custom User Prefrence
pm.OnControlEvent(consts.get("PHYEVENT_INVOKE_CONTROL"), pm.Get(consts.get("SWE_MTHD_UPDATE_USER_PREF")), inputPS); 

above code initializes a Property set User-Notes   in which we capture the Notes and save in SPF file.

The final part is to create a Canvas to resemble a Sticky Notes , i have tried and achieved below 



Benefits :

  • Values Stays even after logout
  • SRF and Database Independent 
  • Lightweight and concise 
  • No 3rd Party jQuery library required
sample code for reference, 

https://drive.google.com/file/d/11G2ksqH6n5XK75ZQD3Es8DpixOuybv7_/view?usp=sharing




Friday 25 January 2019

Sending SMS in Siebel : Extending Default [ALT + F9] functionality

Hello All ,

 Sending Email in Siebel is very basic and very useful functionality ,which we widely use.
 Command F9 is provided by default for sending the email via Pick recipient option.

 so using existing framework lets try to extend this functionality for sending SMS,




 Solution,

  •   There is default option for Send Wireless Message in Siebel which is Invoked from Command ALT + F9

 lets extend this functionality to send SMS too ,


  • Find the target Applet , "Send SMS Applet" 


 by default there is Option to Pick Recipient which in turn selects email address as it is Based on Contact ,
 so we need to add some custom code here to Pick Phone number also for the contact
 also we need to enter the Text which we want to sens as SMS Body , and store it in a variable

 Below code in Applet PreInvoke does the needful,

 function WebApplet_PreInvokeMethod (MethodName)
 {
 if(MethodName == "SendSMS")
 {
 this.BusComp().ActivateField("Contact Id");
 this.BusComp().ActivateField("Email Body");

 var SMSBody = this.BusComp().GetFieldValue("Email Body"); // get SMS body to be sent
 var PhoneNum = this.BusComp().GetMVGBusComp("Contact Id").GetFieldValue("Cellular Phone #"); //get Phone number to send SMS
 sendSMS(SMSBody,PhoneNum);
 }



  •  Add Button to Invoke method say SendSMS , that will trigger SMS.


 Now we can send SMS as we have Phone number and Message Body,
 There are certain API available for this, i am using way2sms for this purpose,

 API for way2sms :
 apikey, unique key for user
 secret, unique key for user
 usetype, stage or Production
 phone, Number to send SMS to
 message, Message body

sample Request : http://www.way2sms.com/api/v1/sendCampaign?apikey=UO9EWGKEQI2YQA5BSCRJHT5TUXHORPP8&secret=UX93MQ92VIBTCGY7&usetype=stage&phone=999670002&message=HelloRahul"); 

Paramteterized Request : PhoneNumber and Message passed in Request as variable

http://www.way2sms.com/api/v1/sendCampaign?apikey=UO9EWGKEQI2YQA5BSCRJHT5TUXHORPP8&secret=UX93MQ92VIBTCGY7&usetype=stage&phone="+ PhoneNum +"&message"+ SMSBody;

now we can call Siebel EAI Transport to Hit the URL ,


 sendSMS(SMSBody,PhoneNum)

 ///SMS//////

var k = "https://smsapi.engineeringtgr.com/send/?Mobile=***67753*2&Password=able&Message="+SMSBody+"&To="+PhoneNum+"&Key=RAHULVsG7AhXF0bnm2uz";

var EAISiebelAdapter = TheApplication().GetService("EAI HTTP Transport");
var Inputs = TheApplication().NewPropertySet(); var Outputs = TheApplication().NewPropertySet();
Inputs.SetProperty("HTTPRequestURLTemplate","https://smsapi.engineeringtgr.com");
Inputs.SetProperty("HTTPRequestBodyTemplate",k);
Inputs.SetProperty("HTTPRequestMethod","POST");
//Inputs.SetProperty("HTTPContentType", "text/xml; charset=UTF-8");
EAISiebelAdapter.InvokeMethod("Send", Inputs , Outputs);
 ////sms end////TheApplication().RaiseErrorText( "SMS  "+ SMSBody +"  sent to user  with Phone Number  "+ PhoneNum);*/return (CancelOperation);
 }
 return (ContinueOperation);}


 Note:
 1. ALT + F9 is default command to Open Send Wireless Message applet
 2. SMS API depends on the client, as i have chosen free demo from way2sms, working with different API ,might require different code
 3. By Default there is Option of Pick Recipient which Open a Pick applet for choosing recipient first, before navigating to Send SMS Applet, this is default behavior and can be overridden with below steps (will share detailed solution in later post)

  •   Open The User Property for the BC
  •   Search for Enable Recipient in User Property
  •   Disable and Compile/Deliver




Friday 18 January 2019

Siebel Auto Complete Functionality :- Part 3

-------To take things a step ahead, -----

In my previous Posts

Siebel Autocomplete from Plugin

Siebel Autocomplete from Native Siebel jQuery

we achieved autocomplete functionality with one limitation that Values to be fetched for autocomplete were provided in the PR file itself that makes it less flexible solution in real case scenario

Now Lets Try to make siebel database layer to act as data source rather then hard code values.

the Solution ,

1. We need to have the value set stored somewhere in siebel , say LOV's Description
2. We need to fetch the value from LOV and pass it as source in the auto complete function

My Solution ,


  • Client Side BS to Fetch Source from List Of Values (Siebel Vanila BS can also be used for this)

BS Code :
{
  var boLOV, bcLOV; 
  boLOV = TheApplication().GetBusObject("List Of Values");
  bcLOV = boLOV.GetBusComp("List Of Values");
  var tags;
  var tag;
  with(bcLOV)   {
  ActivateField("Description"); 
  ActivateField("Type");
  ActivateField("Value");
  SetViewMode(AllView); 
  ClearToQuery(); 
  SetSearchSpec("Type", "AUTOCOMPLETE_LOV");
  SetSearchSpec("Value", "AUTOCOMPLETE");
  ExecuteQuery(ForwardOnly);    if (FirstRecord())
  tag = bcLOV.GetFieldValue("Description");   
  }
Outputs.SetProperty("Tags",tag);
}


  • Calling the BS in PR file and pass as input to autocomplete()


             var sBusService = SiebelApp.S_App.GetService("Query Siebel Data");
    var Inputs = SiebelApp.S_App.NewPropertySet();
    var Outputs = SiebelApp.S_App.NewPropertySet();
// Invoke the Business service Method and pass the Inputs
           Outputs =  sBusService.InvokeMethod("GetValue");
   Data = Outputs.GetChild(0).GetProperty("Tags");
        Array = Data .split(','); // split string on comma space


  • LOV with the Values 



now the final Code

if (typeof(SiebelAppFacade.AutoComplete) === "undefined")

{ SiebelJS.Namespace("SiebelAppFacade.AutoComplete");
  define("siebel/custom/AutoComplete", ["siebel/phyrenderer"], function ()
{
 SiebelAppFacade.AutoComplete = (function ()
 { function AutoComplete( pm )
 { SiebelAppFacade.AutoComplete.superclass.constructor.call( this, pm );

 if ( Data == '' || Data  == null )
 {
 var sBusService = SiebelApp.S_App.GetService("Query Siebel Data");
 var Inputs = SiebelApp.S_App.NewPropertySet();
 var Outputs = SiebelApp.S_App.NewPropertySet(); /
/ Invoke the Business service Method and pass the Inputs
 Outputs = sBusService.InvokeMethod("GetValue");
 Data = Outputs.GetChild(0).GetProperty("Tags");
 Array = Data .split(',');
// split string on comma space }
 }
 SiebelJS.Extend( AutoComplete, SiebelAppFacade.PhysicalRenderer ); 

// bind events function

 AutoComplete.prototype.BindEvents = function(){ SiebelAppFacade.AutoComplete.superclass.BindEvents.call( this );
 // Passing the Value for AutoComplete data too Function
 var tags = Array;

 $( '.siebui-ctrl-textarea').autocomplete(
{ source: function( request, response )
{ var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( request.term ), "i" );
 response( $.grep( tags, function( item ){ return matcher.test( item ); }) );
 }});
};
 return AutoComplete; }());
 return "SiebelAppFacade.AutoComplete"; });}

Working example


Siebel GoTo View - Handling Realtime cases

 Hello All,  We all must have used GoTo view functionality of siebel to navigate to a particular view from current view. What if the require...