Monday, April 30, 2012

Chrome not displaying Listbox selected item when used inside an Ajax UpdatePanel

On a page with an ASP.NET ListBox (HTML select with a "size" attribute) that is contained within an UpdatePanel Chrome isn't scrolling the select control to display the selected item when the update panel updates the page. The selection has been made, it just can't be seen if it isn't within the first items displayed.

Firefox and Internet Explorer scroll the select to display the selected item as expected both on the initial page load and the update panels partial page refresh.

I solved this by registering a call to a Javascript function in the PageRequestManager endRequest event (this fires after the update panel does the partial page refresh). The new Javascript function loops through the options on the select and toggles the selected attribute on the one that is currently selected.

 <script type="text/javascript">

  // For callbacks in webkit force the listBox to reselect.
  if ($.browser.safari) {
   var prm = Sys.WebForms.PageRequestManager.getInstance();
   prm.add_endRequest(function () {
    FocusSelected();
   });
  }

  function FocusSelected() {
   var lb = document.getElementById("<%= listBoxControlNameHere.ClientID %>");
   if (lb != null) {
    var options = lb.options;
    for (var i = options.length - 1; i > 0; i--) {
     if (options[i].selected == true) {

      var x = options[i];

      x.selected = false;
      x.focus();
      x.selected = true;

      return;
     }
    }
   }
  }
 </script>

See Also:

Friday, April 20, 2012

Salesforce INVALID_FIELD_FOR_INSERT_UPDATE when updating Accounts and the __pc field suffix

I recently encountered the following error when updating a Salesforce Account with S4S.

Error INVALID_FIELD_FOR_INSERT_UPDATE - Account: bad field names on insert/update call: Field1__pc, Field2__pc, Field3__pc

Oddly, the fields referenced in the error were actually custom Contact fields. My first thought was an Account trigger the resulted in an update to a related Contact record.

That didn't lead anywhere, but I did notice the custom field suffix was "__pc" rather than the typical "__c".

Turns out the "__pc" suffix is used when the org is configured to use Person Accounts.

Some custom fields have __pc suffix instead of __c. Those are custom fields that have been merged from the Contacts object into the Accounts object. For example, if your Contacts object has a custom field height__c, it becomes height__pc in the Account object. All standard Contact fields are [pre]ppended with "person".
[1]

See also:

Friday, April 13, 2012

Using Saleforce Assignment Rules from G4S or S4S

S4S and G4S can both utilize the Lead Assignment Rules from Salesforce when inserting a new record.

Essentially an AssignmentRuleHeader needs to be added to the Salesforce binding with the useDefaultRule property set to true. This is equivalent to checking "Assign using active assignment rule" at the end of the Lead creation process in the UI.

After the insertion is complete the AssignmentRuleHeader should be cleared from the binding so it doesn't affect subsequent calls from that Session.

[TestMethod]
public void CreateLeadWithActiveAssignmentRule()
{
 SalesforceSession salesforceSession = SessionTest.GetActiveSession();
 Lead lead = null;

 LeadService leadService = null;

 try
 {
  lead = new Lead();
  lead.FirstName = "John";
  lead.LastName = "Brown";
  lead.Company = "ABC Corporation";
  lead.LeadSource = "Web";

  // Setting the lead source for a pre-existing lead assignment rule. This  
  // rule was created outside of this test case and will assign any new leads 
  // to a user who is not the current session owner.

  // Create the assignment rule header and add it to the proxy binding 
  AssignmentRuleHeader arh = new AssignmentRuleHeader();
  // Use the current default rule. Equivalent to checking "Assign using active assignment rule"
  arh.useDefaultRule = true;

  // Every operation that results in a new or updated lead will use the 
  // specified rule until the header is removed from the proxy binding 
  salesforceSession.Binding.AssignmentRuleHeaderValue = arh;

  leadService = new LeadService(salesforceSession);

  SaveResult saveResult = leadService.Insert(lead);
  if (!saveResult.success)
  {
   Assert.Fail(saveResult.errors[0].message);
  }

  // The lead will now have an Id
  Assert.IsTrue(leadService.ValidEntityId(lead.Id));

  // This call effectively removes the header. The next lead will be assigned 
  // to the default lead owner. 
  salesforceSession.Binding.AssignmentRuleHeaderValue = null;

  // Check that the assignment rule has been applied and the owner is not the current user.
  leadService.Refresh(lead, Lead.Fields.OwnerId);

  Assert.AreNotEqual(salesforceSession.SalesforceUserId, lead.OwnerId, "AssignmentRule should have changed the OwnerId");
    
 }
 finally
 {
  if (leadService != null && lead != null && lead.Id != null)
  {
   try { leadService.DeleteEntity(lead); }
   catch (Exception) { }
  }
 }
}

Sunday, April 8, 2012

Avoiding the Salesforce verification code activation

In the majority of cases the Salesforce verification code isn't too much of an issue. You access Salesforce from an unknown IP address, they email you a six digit code which you enter and then carry on.

However, there are cases where accessing this email can be particularly difficult. E.g.

  • Shared login credentials for development orgs (only one person gets the email)
  • After a Sandbox refresh where email addresses have a suffix
  • Apps on mobile devices that are roaming between different network connections.

In the simplest solution you add your known trusted network IP ranges and then carry on.

If that doesn't work you could try raising a case with Salesforce support to disable this feature for your org.

Alternatively, you could add every possible IP address to the Trusted Networks. This is simple in theory, but Salesforce will only allow you to add IP ranges of 33,554,432 addresses (225, a /7 CIDR block).

Doing so manually for every possible IP address will be time consuming as you will need 128 IP ranges.

I did find a package that will automate the process - Enable All Trusted IP Ranges for a Salesforce Org.
I'd probably advise against it in a production org but it was useful for a developer edition org.