Monday, May 18, 2015

Forecasting Quota and Risk of Salesforce Upgrade


Problem

This is a bit of old problem, but we had this custom Visualforce interface in our internal org that allows you to mass insert and edit Forecast Quota.  This has been working fine for years, but when we tried to enter forecast for this year, we suddenly got this error:

Missing Required Field: [Quota Quantity]
However, when we tried to modify the code to allow manual entering of quota, we were getting error indicating that this field is not writable.


Solution

What turned out happen was that you need to have ForecastingType set if you are using ForecastingQuota inside of code after API v28.  Once we enabled a revenue forecast on opportunity (Setup > Customize > Forecasts > Setting), the interface worked again.

Takeaway

This was another lesson on using custom code with Salesforce (especially something that interacts with Standard feature, such as Standard object) and Salesforce upgrade.  Writing custom code can certainly improve the usability of Salesforce, and I do believe it to be one of major feature of Salesforce, but one has to be mindful that it can suddenly get broken without warning.  This is one of the reason why Salesforce recommends using as much of standard functionality as possible (70 to 80% standard functionality is the Salesforce benchmark).

Strange error when saving from Developer Console

This post is more of a reference for future if I encounter this error again, but I had a rather strange error when trying to save a modification to a Apex class from Developer Console:

Failed to create createContainerMember for containerId=undefined: null is not a valid containerId
After some googling, I had found following help article indicating that you need to create a new workspace when this error appears.  This did fix my error, but it doesn't really explain why this error appears.  If you have more in-depth explanation as to why this would happen, let me know.

Taking control of Custom Action in Salesforce1

I have been involved with a few projects that incorporated Visualforce pages into Salesforce1's custom action since the launch of Salesforce1, and one thing I had found annoying was that there was no documentation on how one can take over the action associated with "Submit" and "Cancel" button on top of the custom action page.



However, Salesforce has recently updated their documentations on how you can add your own action to these two buttons using Publisher SDK.  I first saw this on Visualforce Mobile Trailhead, but they have updated Salesforce1 Mobile App Developer Guide to include it as well.

To add your own Javascript action to the "Save" button, you would first include Publisher SDK:


<!-- Publisher SDK -->

<script type='text/javascript' src='/canvas/sdk/js/publisher.js'></script>

Then, you would modify following Javascript function inside your Visualforce page.

// When the panel is displayed, enable the submit button
Sfdc.canvas.publisher.subscribe({name: "publisher.showPanel", onData:function(e) {
    Sfdc.canvas.publisher.publish(
        {name: "publisher.setValidForSubmit", payload: "true"});
}});

// Action to be performed when submit button is pressed
Sfdc.canvas.publisher.subscribe({ name: "publisher.post", onData: function(e) {

    // ***************************************************
    // Add your own action here
    /* myOwnAction([params], 
          // Callback
          function(error, records) {
             if (error) {
               // Do something on error
             }
             else {
               // Close the window
               Sfdc.canvas.publisher.publish(
                { name: "publisher.close", payload:{refresh:"true"}});
             }
       }); */
}});

Tabs and Searching

As you gain more experience with Salesforce, you come to run into limits that make you think "why did they put that limit?"  One of such feature is searching custom object.  Over a year ago, we had a project with a customer who had quite a few custom objects in its org and had used up all their tabs.   One of the requirements for the project is to enable the search on a new custom object, but when we have set all the search layout, we weren't seeing the object in the search.  After some googling, we found out that you can search a custom object only if you have custom tab associated with it.  When we had contacted Salesforce support, we found out that you could purchase additional tabs just so that you can enable additional searching.  Also, you could implement your own Visualforce searching page, but I still find this to be rather strange limitation.

Saturday, March 28, 2015

History is in Detail! - Migrating Master-Detail Relationship with History Tracking on Child Object

Problem

Over the years as Force.com developer, I found that migration and trigger are two area where I encountered issues most frequently, and here is another interesting issue with migration in Salesforce.  I had a custom sObject that were in Master-Detail relationship with Account.  When I tried to migrate this object using Force.com Migration Tool, I was getting following error:

duplicate value found <unknown> duplicates value on record with id: <unknown> 
After much googling, I found this post on StackExchange, indicating that History Tracking might be a problem.  When I disabled the history tracking on the object, I was able to migrate the object.

Work-around
With the cause of the problem tracked down, I still found the prospect of manually enabling history tracking on the object and each field in the destination org quite troubling.  With Salesforce.com migration, some manual steps are unavoidable (e.g. Community setup, Quote enablement, etc.), but you do want to minimize the manual steps as much as possible, and I thought there might be a way to automate this step using Force.com Migration Tool.

First solution I considered was creating the object first with a lookup relationship with Account, then have another deployment of the same object with relationship change to Master-Detail relationship.  This did eliminate the "duplicate value..." error, but the problem was that when you change a relationship from Lookup to Master-detail (or vice-versa), it triggers sharing rule recalculation, which causes problem if you had any sharing rule being migrated at the later stage of the deployment step, which we did have for this project.

The eventual solution I came up with was a three-staged migration of the object.  First, I migrated a shell Metadata of the child object with Master-Detail Relationship on, but with history tracking turned off.  Second,  I migrated the shell Metadata file again, but with history tracking turned on.  Finally, I migrated the full retrieval of the child object Metadata.  One issue you have is that you have to manually maintain copies of shell Metadata files for these children objects, but schema for the shell is quite simple and you only have to create these shell files only once, whereas you have to perform manual step, which is prone to error, on every environment you migrate to.

I have checked in the code for the simplified version of this process in my github repository.  You can find it at https://github.com/jpaek/MasterDetailWithHistory.

Takeaway

The error message for this problem was rather misguiding for me, but this shouldn't come as a surprise to us Force.com developers, especially when working with migration.  Googling, as was case here, can help figure out what the problem is, but sometime you do have to manually figure out the problem by playing around with it, which can be quite cumbersome tasks.

Also, I want to point out that, with bit of thinking and experimentation, you can eliminate many of the manual steps involved with migration steps through Force.com Migration Tool.   

Monday, March 23, 2015

Task Trigger and Ugly Un-bulkfiication.

Problem

We had created a trigger on Case Task that would update a custom description field on the parent case with comment from the task when the status of the task changes to "closed."  This trigger worked at the beginning, but then this trigger started to fail with following error message:
Apex Task trigger cannot handle batch operations on recurring tasks.

It turns out that you cannot to have a trigger on event (including task) if you have any batch job on recurring events (see here) and that another team working with this client had implemented a batch apex job that managed recurring tasks related to some other object.  

Work-around

There really wasn't a work-around for this issue.  What we ended up doing was getting rid of the trigger and let user manually copy the value.

Takeaway

Trigger is one of the most problematic aspect of Salesforce.com development with many nuances, this being one of them.  With the release of the new Lightning Process Builder, we finally may have a work-around on this issue and many other trigger-related issues, although I cannot say that with high confidence as this very new feature with Salesforce.com.

Sunday, March 22, 2015

Mobile Design Template and Angular.JS

Problem

We had implemented a multi-step wizard for our client.  Two of the requirements for this wizard was that it needed to be mobile-friendly, and it needs to have bilingual support.  To meet this requirement I had tried to implement a mobile version of the wizard using Mobile Design Templates.   I had previously built a simple mobile-friendly Visualforce page using Mobile Design Templates and Underscore.JS following the Getting Started with Mobile Design Templates blog post from Salesforce.

Given the complexity of this application, I had used Angular.JS as the back-end.  However, I ran into trouble when I tried to incorporate the Mobile Design Templates' toggle input into this application.

We had this picklist field with two values that we want to render as a toggle input.  To do so I had the Angular.JS controller called the service that would grab the labels for those two values from Salesforce, in order to meet the bilingual requirement, and set those label as data-on-label and data-off-label.

(function() {

var app = angular.module('app', []);



 app.controller('InputCtrl', function InputCtrl(InputLabelService) {

        var inputScope = this;



        // Get the label of the input form from Salesforce
        InputLabelService.getFormValues().then(
            function(picklists) {
                inputScope. inputLabels = picklists. inputLabels;


               // This renders the toggle input
               $(document).trigger('onTemplateReady');
        });
    });
})();



<section class="border-bottom">
    <div class="content">
    <h3>Input</h3>
        <div class="form-control-group">
            <div class="form-control form-control-toggle" data-on-label="{{inputLabels[0]}}" data-off-label="{{inputLabels[1]}}">
                <input type="checkbox" name="toggle">
             </div>
         </div>
     </div>
 </section>
The problem was that Mobile Design Templates render data-on-label and data-off-label on the toggle input upon the call to 'onTemplateReady' Javascript trigger.  However, because how the two-way binding of Angular.JS is done, the rendering of the toggle input is done before Angular.JS can set the data-on-label and data-off-label with appropriate values, which ended up rendering the toggle input without any label.

Solution

The way I had gotten around this issue was by putting a $watch listener on the inputLabels and to trigger 'onTemplateReady' when it has a new value.

(function() {

var app = angular.module('app', []);



 app.controller('InputCtrl', function InputCtrl(InputLabelService) {

        // Get the label of the input form from Salesforce
        InputLabelService.getFormValues().then(
            function(picklists) {
                $scope.inputLabels = picklists.inputLabels;



                $scope.$watch('inputLabels', function(newVal, oldVal) {



                    if (newVal) {

                       // This renders the toggle input
                       $(document).trigger('onTemplateReady');
                   }
               });
        });
    });
})();




Takeaway

In the end, I actually ended up not using Mobile Design Templates as the tabbed navigation, which I had used in one of the page, didn't work in iPhone.  Instead, I ended up using Bootstrap along with Angular.JS.  I still think Mobile Design Templates is a good tool to have in your tool belt if you are building a very simple mobile application on Salesforce1; however, for any application with a moderate complexity, I would definitely look at alternative, such as Bootstrap I have used for this project or Ionic Framework.