Tuesday, July 15, 2014

How to add SOAP header to a Salesforce call out

There are situations when we need to add a SOAP header to the call out being made. If your WSDL has a definition for a SOAP header then the Apex to WSDL tool will generate the header code for you.

But most of the times the WSDL does not have the header information and the receiving server needs specific SOAP header to validate the call. In such a case we can add a custom header to the call. Here are the steps to add a customer.  e.g. If we need to send the following in the header.

<ApplicationContext>
    <consumerSystem>UN</consumerSystem>
    <organisation>PW</organisation>
</ApplicationContext>

1. Add a data structure to the stub generated for your data to be sent. For the example the class to be added to the stub would look like .
public class PolicyManagement_V2_Schema{ // this is the parent class which has the stub definition
public class ApplicationContext {
        public String consumerSystem;
        public String organisation;
        private String[] consumerSystem_type_info = new String[]{'consumerSystem','<SOAP Namespace>',null,'0','1','false'};
        private String[] organisation_type_info = new String[]{'organisation','<SOAP Namespace>',null,'1','1','false'};
        private String[] apex_schema_type_info = new String[]{'<SOAP Namespace>','true','false'};
        private String[] field_order_type_info = new String[]{'consumerSystem','organisation'};
    }
}
2. Add the following code to the class which makes the call out. Declare the application context as a local class variable and use <variable>_hns = '<PrimaryNode>=<SOAP Namespace>'. Adding the _hns node tells salesforce to put the information of the class in the SOAP header.
public PolicyManagement_V2_Schema.ApplicationContext Header;
private String Header_hns = 'ApplicationContext=http://www.iag.co.nz/soa/apexiaa/v2';

3. Once you have done step 1 and 2, you are all set to send custom data in SOAP header call out. All you need to do now is to instantiate the header variable in the actual call out and set the values for the class variables which would be sent as part of SOAP header. 

Monday, June 16, 2014

Salesforce Hover Helptext on fields not in apex page block section

We come across various use cases where we can not have the apex input field as a child item directly under the apex page block section. Or we cannot use apex input field at all and hence need to use some other tag. If you want to show salesforce field helptext with an on-hover icon then here is a way which would allow you to addyour custom hover help text which looks and behaves exactly same to the standard hover help text.

Here is the code you need to add in your pageblocksectionitem. The label needs to be a child item of a span and we will pass the id of the span to the standard function which is available by standard salesforce.com javascript itlself.

  <apex:outputPanel >
       <span class="helpButton" id="ANZSICcodeforLiab-_help"> 
             <apex:outputLabel value="{!$ObjectType.Common_Details__c.fields.Primary_Rating_ANZSIC_Code__c.Label}" for="PrimaryRatingANZSIC"/>
             <img class="helpOrb" src="/s.gif" />
             <script>
                  sfdcPage.setHelp('ANZSICcodeforLiab', '{!JSENcode($ObjectType.Common_Details__c.fields.Primary_Rating_ANZSIC_Code__c.inlineHelpText)}');
             </script>
       </span>
</apex:outputPanel>

The Label tag is added under an output panel because pageblocksection item can only have 2 direct children.
The important points to note are

  • Id of span passed to the JavaScript function is the first part of the string. The second part i.e. "-_help" is not passed to the setHelp method. 
  • sfdcPage.setHelp is the method which adds the on hover functionality to the image. 
  • If you miss the style class "helpButton"  to the span then the on hover behavior will not work properly.  



Sunday, May 18, 2014

How to Collapse the Apex Page block Panel on page load

If you have a big page with a lot of fields and multiple sections on the form, then you might want to collapse some of the sections on the form on page load. Although salesforce does not provide any thing out of the box to have those sections as collapsed by default but we can write a quick javascript hack to do this. 

Salesforce has a function twistSection which gets fired on click of the image to collapse or expand the page block section. So all we need to do is to pass the image object to this function and it toggles the section. On page load the sections are always expanded hence just by calling this function on page load will ensure that the section is collapsed after the page load. 

Here is the code to collapse a section on page load. 

Suppose the panel code is as given below 

<apex:pageBlockSection collapsible="true" title="MD" id="MDsection">

Then first we need to get the panel element by id using the code 

var mdsec = document.getElementById('{!$Component.MDsection}');

You might have to use form name and page block name based on where you put the  java script code in the page.

After this on page load you need to write the following code

twistSection(mdsec.childNodes[0].childNodes[0]);

This will ensure that the page block section will be collapsed on the page load.

Tuesday, April 29, 2014

Understanding generated code from WSDL to Apex Tool

We all have generated Apex code from WSDL in Salesforce.com. But there are alot of limitations in the xml parser and code generator. Out of these the biggest is the XSD extensions. If your wsdl Schema has xsd extensions then the Apex generator simply ignores it. As a result the code generated is incapable of handling the  response payload or send the correct request.

This can be a big challenge if the request and response xmls are complex. The only way out of this is looking at the xmls and writing the apex code your self. This can be challenging if we really dont understand the generated code properly.

Here in my blog I am giving a shot at it and trying to explain various components of the generated code. So that we can write our own code if the need be.

For example if your response/request xml looks something like this

<RetrieveIndustriesResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="<schema>" xmlns="<ur schema>" xsi:schemaLocation="..../XSD/iagiaa_v2.xsd">
<industry>
<dynamicProperties>
<kind>&lt;B&gt;Classification Information&lt;/B&gt;</kind>
<conformanceType>text</conformanceType>
</dynamicProperties>
<dynamicProperties>
<kind>Primary Activities</kind>
<conformanceType>text</conformanceType>
<theValue>This class consists of units mainly </theValue>
</dynamicProperties>
<dynamicProperties>
<kind>Exclusions</kind>
<conformanceType>text</conformanceType>
<theValue>Units mainly engaged in</theValue>
</dynamicProperties>
<description>Other Takeaway Food Retailing (not part of Restaurant)</description>
<industryCode>4512C</industryCode>
</industry>
</RetrieveIndustriesResponse>

and if the DynamicProperties is an extension then in the generated apex code for the xsd this property will be ignored and you will have to write it on your own.

The final code will look something like this.


public class Industry {
        public list<IAGSOAPstub.dynamicProperty> dynamicProperties;
        public string description;
        public String industryCode;
        private String[] dynamicProperties_type_info = new String[]{'dynamicProperties','http://www.iag.co.nz/soa/iagiaa/v2',null,'0','-1','false'};
        private String[] description_type_info = new String[]{'description','http://www.iag.co.nz/soa/iagiaa/v2',null,'0','1','true'};
        private String[] industryCode_type_info = new String[]{'industryCode','http://www.iag.co.nz/soa/iagiaa/v2',null,'0','1','true'};
        private String[] apex_schema_type_info = new String[]{'http://www.iag.co.nz/soa/iagiaa/v2','true','false'};
        private String[] field_order_type_info = new String[]{'dynamicProperties','description','industryCode'};
    }
    public class dynamicProperty {
        public String kind;
        public String description;
        public String conformanceType;
        public String theValue;
        private String[] kind_type_info = new String[]{'kind',<Schema URL>',null,'0','1','false'};
        private String[] description_type_info = new String[]{'description','<Schema URL>',null,'0','1','false'};
        private String[] conformanceType_type_info = new String[]{'conformanceType','<Schema URL>',null,'0','1','false'};
        private String[] theValue_type_info = new String[]{'theValue','<Schema URL>',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'<Schema URL>','true','false'};
        private String[] field_order_type_info = new String[]{'kind','description','<Schema URL>','theValue'};
        
    }
   
    public class RetrieveIndustriesResponseType {
        public IAGSOAPstub.Industry[] industry;
        private String[] industry_type_info = new String[]{'industry','<Schema URL>',null,'1','-1','false'};
        private String[] apex_schema_type_info = new String[]{'<Schema URL>','true','false'};
        private String[] field_order_type_info = new String[]{'industry'};
    }




The public variables are nothing but the actual xml elements or nodes or attribute. For each node/attribute there will be one public variable. It can either be primitive datatype or object of some other class which represents another complex type in xsd. 
If the variable represents another XML element or a text node, then there needs to be a matching _type_info String[] e.g. bar_type_info. 
The elements of this array are: 1. XML element name 2. Schema 3. XML type 4. minOccurs 5. maxOccurs (set to '-1' for unbounded) 6. isNillable
If the variable represents an attribute, then there must be a matching _att_info String[] e.g. a_type_info. Thise simply contains the XML name of the attribute.
Note that if an class variable name is a reserved word, then _x is appended to it e.g. bar_x. This would affect the other variables names: bar_x_type_info. The Apex Developer's Guide explains their rules for names, but if you are manually creating it, I think you can give it whatever name you want--the arrays determine the XML element name...
The apex_schema_type_info array specifies information about the XML element represented by the class: 1. Schema 2. 'true' if elementFormDefault="qualified" 3. 'true' if attributeFormDefault="qualified"
field_order_type_info simply specifies the order of the child elements.

Tuesday, December 3, 2013

handling datetime field in a dynamic Query in Apex

We all need to make the Datetime comparisons in SOQL queries. But if the query is dynamic then the datetime comparison gives an error if you just add the datetime variable directly. e,g  if your code looks like 


date d = system.today().addDays(-7);
string query = 'Select ID from Opportunity where CreatedDate > ' +d;


Then you are likely to get a runtime SOQL datetime format error.

To resolve it we need to change the datetime into a format which is SOQL format. Hence I have written a method for the same.
Use the following method to change your datetime into a format which can be directly put into dynamic SOQL and SOSL where clauses. 


 public static String getSOQLDateTime(DateTime dt) {
        if (dt == null) return '';
        String datevalue = String.valueofGmt(dt);
        string [] datetimepair = datevalue.split(' ');
        string datepart = datetimepair[0];
        string timepart = datetimepair.size() > 1 ? datetimepair[1] : '';
        string [] dateparts = datepart.split('-');
        string [] timeparts = timepart == '' ? null : timepart.split(':');
        string hour = (timeparts == null)? '00' : timeparts[0];
        string minute = (timeparts == null)? '00' : timeparts[1];
        string second = (timeparts == null)? '00' : timeparts[2];
        string millisecond = '000';
        string month = dateparts[1];
        string year = dateparts[0];
        string day = dateparts[2];
        string result = year + '-' + month + '-' + day + 'T' + hour + ':'+ minute + ':' + second + '.' + millisecond + 'Z';
        return result;
    }

Monday, December 2, 2013

Generate barcode and attach it to a record in Salesforce

So today I came across a requirement where in I had to generate a bar code at run time and then attach it to the record.  For generating the bar code I used the jquery library and it was pretty straight forward.
The jquery library used
 <script type="text/javascript" src="jquery-1.3.2.min.js"></script>   
 <script type="text/javascript" src="jquery-barcode.js"></script> 
Now to take that bar code out as an image and attach it with the record had a lot of challenges.  Here is the solution for it.

1. Use HTML5 and ensure that the Barcode is generated as a canvas output. Here is code for the same.
<canvas id="canvasTarget" width="300" height="50"></canvas>  
 $("#canvasTarget").barcode("123456789", "code128",{barWidth:2, barHeight:30,output:"canvas"});

2. Use the toDataURL function to extract the base64 string encoded data for the barcode rendered in the canvas.
 var oCanvas = document.getElementById("canvasTarget"); 
  imageblob= oCanvas.toDataURL(); 



3. Now when you get this data it is prefixed with a lot of information like its an image , its type etc. Now before we post this data in salesforce and use it to generate an attachment, we need to clean it. You can either clean it before posting the data or clean it at the server side. I decided to clean it before posting hence I used the split function.

var res = imageblob.split(",")

4. Next is the actual posting. For this you can either you user javascript remoting or simple form post. As my form has no other elements hence I decided to post the entire form. I created a hidden element on my form and set the value of that element with the cleaned base 64 data.

5. Finally I wrote an action function which would post the form and assign it to my string variable in controller which is my case is "docbody"

6. In the controller the string element which contains the encoded data would be converted into a blob object using the base54decode method.
 Attachment a = new Attachment();
 a.ParentId = recid;
 a.Name = 'Test.jpeg';
 a.Body = EncodingUtil.base64Decode(docbody);
  insert a;

And finally I could generate a dynamic barcode and attach it to a record.