Tuesday, August 7, 2018

Converting a Change Set to a Salesforce DX project

I *really* dislike the change set UI.  I also had a want / need to start getting my team more involved with source control and Salesforce DX. 

A lot of our projects are in existing orgs, so spinning up a scratch org and starting from scratch isn't really an option.

There is an option to migrate existing sandboxes to Salesforce DX  using an unmanaged package, but holy moly.  When you add a few fields to the package, it brings in a TON of dependencies!  I wanted the ability to cherry pick the dependencies I wanted to store in source control.  Reason being?  I only wanted the work that our team is in charge of developing instead of the client's complete metadata.

Enter change sets.

Turns out you can generate a package.xml through a change set (similar to what you would do through Eclipse or other IDEs).

Here's the basic steps I took to convert a change set to a DX project:

  • Create a change set in a sandbox.
  • Populate the change set with any necessary metadata.
  • Validate the change set against, say, production.
  • Rinse lather repeat until you're able to validate the change set successfully.
  • In workbench (workbench.developerforce.com), click on the Migration tab, then click Retrieve.
  • In "Package Names" specify the name of your change set.  You might have to delete / remove old change sets, otherwise, you'll get an error that multiple packages exist.
  • When the retrieve is successful, then click "Download zip file"
  • This zip file will have a root directory of "unpackaged", inside of which the package.xml file is stored.
  • Create a directory for DX project, and add the sfdx-project.json file, along with the config/project-scratch-def.json files, etc.  If you're connecting to a sandbox environment, you'll want to make sure project-scratch-def.json points to test.salesforce.com instead of login.salesforce.com
  • If you haven't already, authenticate with your sandbox (this will pop up an oauth screen in your web browser and ask for permission so that Salesforce DX can connect to it):
sfdx force:auth:web:login -a HeyThisIsMySandboxAliasAndYouCanChangeIt
  • Copy the package.xml from step 7/8 into the directory.
  •  Issue the following command (It will retrieve the source from your sandbox, using the package.xml and generate a zip file in the root level of your project directory):

sfdx force:mdapi:retrieve --retrievetargetdir ./  -k package.xml -u HeyThisIsMySandboxAliasAndYouCanChangeIt

  • Make a temp directory for the contents of the zip file:
mkdir temp
  • Unzip the zip file into a temp directory:
unzip unpackaged.zip -d ./temp/

  • Change directories into temp.  If you see a folder called "unpackaged", rename this to "src".  Because.. reasons?
cd temp | mv unpackaged src

  • Now, convert the source from the "metadata api format" to the "dx format"
sfdx force:mdapi:convert -r ./temp 
Boom, now you can either work with it in a scratch org, and/or commit it to source control.


Salesforce DX and Windows Paths: Issue with Spaces

Salesforce DX has an issue when it attempts to resolve paths with spaces.  This can happen in Windows environments, and reared its ugly head because the person that set up my work laptop added a space to the username.

When you issue a Salesforce DX command, you'll get an obscure error like C:\Users\User is not a valid command.

To account for this, you can simply issue the following in command prompt: FOR %d IN ("%LOCALAPPDATA%") DO SET LOCALAPPDATA=%~sd


Saturday, March 19, 2016

Navigating Soft Skills and the Salesforce Advantage with Trailhead

Trailhead has been my goto tool for learning about new Salesforce functionality and brushing up on my existing Salesforce skills for over a year now.  There are a plethora (I love being able to sneak in a good use of the word plethora) of trails and modules for both admins and developers alike.

One thing that has been missing though are soft skills related modules.  Soft skills are something that we all can benefit from.  Whether you're a developer, administrator, manager, president of a company.  No matter your role, there's always room for refining those soft skills.

The Salesforce Cultivate Equality at Work Trail offers advice for improving on those soft skills and includes modules for promoting workplace equality.  Another trail that offers soft skills is the "Manage the Salesforce Way" trail which promotes exploring and improving your listening and managerial soft skills.

In addition to the soft skills above, you'll also want to check out the new trail for Navigating the Salesforce advantage.  This trail contains modules / badges that explain the various factors that sets Salesforce apart from other CRM and software eco systems. (Hint: my favorite factor is the amazing community that makes the Salesforce ecosystem thrive)

So, what are you waiting for? Head over to https://developer.salesforce.com/trailhead today and start earning one of the many badges!

Tuesday, December 22, 2015

Introducing the newest Trailhead Peak: The Apex Integration Services module



As an integration architect, I spend a substantial amount of time with clients discussing how to integrate with their systems external to Salesforce.  Most times, fortunately, clients have a pre-existing system with a set of available APIs that are exposed either as RESTful or SOAP APIs.

A prime example of this, is the work I helped with on a hi-fidelity music service.  In order to get licensing information, track and album details, and other information, we made several RESTful calls out to a music content provider.  Additionally, we used SOAP services to handle payment processing, tax calculations, and address verification.

In order to work with these external systems, Salesforce provides mechanisms like WSDL2Apex, JSON and HttpRequest utilities that developers can utilize in order to interact with external systems.  If you're not familiar with how this works yet, I strongly urge you to check out the newest Trailhead module "Apex Integration Services".

The new module, which can be found here: https://developer.salesforce.com/trailhead/module/apex_integration_services, contains a lot of useful information on how to develop and test callouts to both REST and SOAP services.  The latter part is key, because the module requires you to use mock callout classes in order to unit test your callouts.  In days past, developers would skip over their callout unit tests using the dreaded if check of !Test.isRunningTest().  However, I'm glad that the module teaches new developers on how to properly test their callouts.

I have to be honest here though, and ask that when you walk through the challenges for the Apex Integration Services module, that you take a bit of heed.  For instance, you might notice that the check for your REST challenge might fail if you don't use this exact line when constructing the HTTP instance:

Http http = new Http();

One boards poster found the following line caused in issue with the rules engine when checking their hallenge:

Http h = new Http();

Also, when you start the SOAP services module, be very careful on how you import the WSDL file.  After you click the "Import WSDL" button, you need to rename the Apex class from the defaulted "parksServices" text to "ParkService".  The case sensitivity along with the correct name is vital to ensuring your challenge is completed successfully.

With those caveats in mind though, the instructions are laid out well and once you pass the Apex Integration Services, you'll have a better understanding of how to integrate Salesforce with external systems.

Happy Trails!



Saturday, September 26, 2015

The Neverending Trail



The Neverending Trail

Before we get started with this blog post, let's go over a few facts:
  1. I watched The Neverending Story no less than 1.2 million times throughout daycare and elementary school.  Also fitting that I never finished watching the movie.  Want to go ride a bike?
  2. There are currently 65 badges on Trailhead!  Sixty-Five!  Well, 66 if you include the April Fools edition Catter badge.
  3. I'm a little addicted to Trailhead and went on a binge to get the 20 or so recent badges.  #BingeBadging
  4. I am officially dubbing Trailhead "The Neverending Trail".  With 66 badges currently and many more likely to come, it really is a trail of never-ending, amazing hands on Salesforce experience.

The "Neverending Trail" may seem a bit daunting term, but I mean it endearingly.  As a commoner on the Developer Boards, one of the easiest questions to answer is "How do I learn about "X" on Salesforce without having any project experience?"  The answer is always to head on over to http://developer.force.com/trailhead and check out all of the amazing hands on training excercises.  

The endless influx of training content is not only a savior for answering questions around the Salesforce community, but the amount of knowledge I walk away with from each module is so rewarding.  Yes, the badges, points, and other gamfication aspects are addictive, but even more so is the breadth of knowledge that you walk away with after completing those hand on training exercises known as Trailhead modules.  

With the 20+ badges released the week prior to Dreamforce, there is literally something for everyone on Trailhead. Are you a new Admin? If so brush up on the Admin Trail.  Are you looking to learn about the new Lightning Experience?  If so, throw some confetti and hop on one of the Lightning Experience trails.  Are you a developer looking to learn more about Heroku Connect?  There's a project for that.  

Oh, by the way, there's three modules / badges on Wave, a Salesforce Analytics platform you may have heard about.  Even if you aren't a self-proclaimed analytics junkie, you NEED to check out the Wave modules.  They are far and above my favorite Trailhead modules to date.  After completing the Wave modules, I felt like Keannu/Neo in the Matrix:


So again, do you have all 65 available Trailhead badges?  If not, what are you waiting for?  Head on over to http://developer.force.com/trailhead and start down your own trail(s) today!  

Thursday, September 24, 2015

CSS Animations and the Lightning Design System

I've had the fortune of tinkering with Lightning Components and in particular using them with the Lightning Design System lately.  If you're unfamiliar with the Lightning Design System, I strongly urge you to head over to http://www.lightningdesignsystem.com and read up on it now.

There are several goodies and easter eggs in the Lightning Design System, including the "Visibility" utilities (https://www.lightningdesignsystem.com/components/utilities/visibility).  The visibility utilities allow you to show and hide SLDS elements within your application, including in your Lightning Components.

In Lightning Components, you can easily utilize JavaScript controller logic to toggle CSS, utilizing a method like below:

({
hideMe : function(component, event) {
var el = component.find('myAuraIdGoesHere');
         $A.util.toggleClass(el,'slds-transition-hide');
}
})

Combining the toggleClass method along with the slds-transition-hide class from the Lightning Design System, allows you to hide (and show) elements when some event happens within your lightning component, such as clicking on a close button or perhaps swiping an element left or right in a tindr-like fashion.

The slds-transition-hide class is excellent. However, it has two major issues right out of the gate.

  1. The opacity is set from 0 to 1 immediately, and can be "jarring" to the user.
  2. The opaque / hidden element still takes up space on the screen if it's a block layout, such as a div.
Enter CSS and Styling.  The Visibility documentation on the Lightning Design System hints that you should use a transition property to control transition and animation of the element you're hiding: 

"Note: To control the timing of the transition, add an additional transition property to control the opacity change."
The transition property is a CSS style you can give an element to control a limited set of properties such as the opacity and the height of an element.  Unfortunately, the display property is one that you cannot transition on.  In other words, I can't transition from display: inline-block to display: none.  So, to get around the 2nd limitation of the slds-transition-hide styling, we'll have to utilize the height of our element and "shrink" the element over a duration of time.  To do this, I extended two of the classes I'm using in the Lightning Design System by modifying the "Style" of my Lightning Component Bundle:

.THIS.slds-media{
max-height: 250px;
.THIS.slds-transition-hide{
opacity: 0;
height: auto;
max-height: 0;
transition: opacity 2s linear, max-height 2s linear;
}
First, I had to guess the max-height of my div.  The div height is variable, but it *should* never exceed a height of 250px.  Without setting the max height of the visible div, the transition has nothing to compare to the new max-height, so you get a very jarring and immediate transition to 0px if that's the case.  Try it for yourself and you'll see what I mean.

The second class gets toggled when a close button is clicked in my lightning component (from the first snippet above).  Using the height, max-height, and transition properties and applying them to the LDS's slds-transition-hide class, we will now get a fairly smooth transition of both opacity and height over a duration of 2s.

So now that I've showed you both the component bundle's controller and the component bundle's style, let's take a peek at what the component itself looks like:

<aura:component > <aura:attribute name="someType" type="SomeTypeGoesHere" description="Some Description" />     <ltng:require styles="/resource/LightningDesignSystem/assets/styles/salesforce-lightning-design-system-vf.css" />         <div class="slds-media slds-tile slds-hint-parent" aura:id="myElementId">           <div class="slds-media__figure">               <img class="img" src="{!v.someVar.Image_Url__c}"/>           </div>           <div class="slds-media__body">             <div class="slds-grid slds-grid--align-spread slds-has-flexi-truncate">               <p class="slds-tile__title slds-truncate"><a href="#">{!v.someVar.Name}</a></p>               <button onclick="{!c.hideMe}" class="slds-button slds-button--icon-border-filled slds-button--icon-border-small slds-shrink-none">                 <c:svgIcon class="slds-button__icon slds-button__icon--hint slds-button__icon--small" svgPath="utility-sprite/svg/symbols.svg#close"/>               </button>             </div>             <div class="slds-tile__detail">               <dl class="dl--horizontal slds-text-body--small">                 <dt class="slds-dl--horizontal__label">                   <p class="slds-truncate">Label:</p>                 </dt>                 <dd class="slds-dl--horizontal__detail slds-tile__meta">                   <p class="slds-truncate">                       {!v.someVar.Value1__c}                   </p>                 </dd>                 <dt class="slds-dl--horizontal__label">                   <p class="slds-truncate">Label2:</p>                 </dt>                 <dd class="slds-dl--horizontal__detail slds-tile__meta">                     <p class="slds-truncate">{!v.someVar.Value2__c}</p>                 </dd>                 <dt class="slds-dl--horizontal__label">                   <p class="slds-truncate">Label3:</p>                 </dt>                 <dd class="slds-dl--horizontal__detail slds-tile__meta">                     <p class="slds-truncate">                         <ui:outputCurrency value="{!v.someVar.Value3__c}" />                     </p>                 </dd>               </dl>             </div>           </div>         </div> </aura:component>

In the component above, when you click on the close icon, it calls the hideMe method in the controller, which toggles the CSS class starts the CSS transition.  Putting it all together, here's what the component looks like in action:



And there you have it, a way to utilize the Lightning Design System, Lightning Components, and CSS Transitions / Animations.  Granted, my solution may not be the best solution.  If you have a better solution than the one above, feel free to comment on this post and let me know.

Monday, August 10, 2015

Thirty Six Badgers ready for the Taking. Conquer the Trail today!

Check that out, it's been exactly 1 year since my last post on here.  For the few that will see this particular post, I typically post on my company's blog here: http://www.edlconsulting.com/author/james-loghry/

That being said, one of my favorite topics to blog on lately has been Trailhead (https://developer.salesforce.com/trailhead/).  For a quick introduction, trailhead is an amazing platform for hands on experience and training with all things Salesforce.

  • Starting to study for your Administrator, Developer, Advanced Developer, Consultant certifications? See Trailhead.
  • Curious about learning hybrid or mobile development and Salesforce? See Trailhead.
  • Have been working on Lightning components, but can't remember how to handle events in the component bundle? See Trailhead.
There are currently 36 badges available for a variety of trails, modules, and projects.  I have 37 of them (Catter was available as a limited April Fools day version and no longer available).  Badges themselves are addicting, but honestly it's the knowledge within the modules and projects that keeps bringing me back.

As a personal anecdote, I was working on a project utilizing the Lightning Communities pilot, but was having a hard time grasping the new event-centric infrastructure that is Lightning components.  Going back through the Lightning related modules and projects helped shed more light on the components and helped me make sense of the framework.
Of the 7 trails, 30 badges, and 6 projects I will say the following:
  • The new DF15 badge and Salesforce Basics modules are the easiest to get started with.
  • The new event monitoring badge is great.
  • Be sure to explore the "Projects" link, as it is easy to miss. 
  • Some of the projects can take quite a while (as in hours) to complete, so plan accordingly.
  • I can't wait for even moar badge(r)s!
So what are you waiting for?  Drive your browser to the Trailhead (https://developer.salesforce.com/trailhead/) and start earning your badges and conquering those trails today!

Monday, August 11, 2014

It's off to Dreamforce we go!

Dreamforce is the Mecca of Salesforce Development.  It's a pilgrimage that a Salesforce Developer must make at least once in their careers.  Although the cost is high, whether it's through registration, lodging, or billable hours as a Consultant, the benefits are enormous.

For one, Dreamforce offers an opportunity to network with your peers and top developers within the Salesforce community.  Chances are the moment you step foot out of your hotel on Monday morning, you will find someone you recognize.  Whether that person is a colleague, Salesforce employee, AE, or an MVP, who knows.  Don't be afraid to walk up and introduce yourself.

It's going to be a long day.  On your way to Moscone West, where all the techies hang out, stop by Starbucks and grab your latte.   It's always fun to see how they mispronounce your name on your cup.  Last year, they somehow turned "James" into "Juarez". Check out the Mini Hacks area and just walk around and explore for a bit.  It's overwhelming.

After you get settled in a bit, go check out some sessions.  The best and most informative sessions I attended were on the first day at Dreamforce last year.  I picked up some excellent pointers, and I'm sure you will too.

As the week progresses, don't be afraid to check out other areas outside Moscone West.  Head to the declarative sessions and pick up declarative tips from the formula geniuses like SteveMo or from the Success Community Zone where the MVPs hang out and answer any questions you may have.

As you soak everything in, make sure you take moments to reflect on your week.  Bring your ipads, notebooks, business cards, and document all you have learned over the long week.  In fact, here is my list of must haves for your Dreamforce trip.


  1. A notebook or an iPad for taking notes
  2. Your most recent business cards for networking
  3. Comfortable shoes.  You'll be walking a lot.  I racked up 35,000 fitbit steps on the first day last year.
  4. Precut moleskin pads.  You will get blisters.  Be prepared.  The precut pads are best, otherwise you will need to cut the moleskin, which isn't an easy venture.
  5. Extra space in your luggage for freebies such as books from the Developer Zone, swag from the Expo, or prizes you may win.  Although, you might have trouble finding room for a Mustang or Tesla.
  6. Umbrella.  In general, be prepared for the weather.  Last year it rained a bit, but having an Umbrella helped getting from point A to point B.
  7. A mobile battery pack for your smart phone.  If you're anything like me, your phone will drain quickly.  Here's a battery pack that works well for my iPhone: http://www.amazon.com/dp/B00BZD6QCW
  8. A camera.  I'm a photography fan, so traveling without my Nikon is not an option.  You'll find lots of photographic opportunities around town or in the various Dreamforce venues.  Fisherman's Wharf is a short walk down Market Street.  Or you may be lucky enough to catch a ride from a Marine Biologist down to the Golden Gate bridge, who knows!
  9. Maybe you're a Google Glass user or a Fitbit fanatic or a Pebble Pedestrian.  Either way, bring your wearables along to Dreamforce for an enhanced experience.
  10. Bring a plan.  Odds are your plan will change during the conference.  However, having a general idea of what you want to get out of Dreamforce goes a long way.  
Still interested in attending Dreamforce 2014?  It's fast approaching (http://isitdreamforceyet.com/), so head on over to the following link for more info and start pestering your boss today: http://bit.ly/df14infblog

Monday, April 15, 2013

Lions, Tigers, and Lead Conversion, Oh My!

For something as simple as clicking a button on a Lead to flip its status from "Open" to "Qualified", there sure are a lot of operations and complexity happening behind the scenes.  Converting a lead takes a lot of forethought.  For instance it must abide by Business processes associated with its Record Type. Fields must be mapped correctly for them to be carried over to the related Opportunity, Account, and Contact records.

What if you want to step outside the box with Lead conversion?  What if you want to implement your own lead button with a custom Visualforce UI?  What if you want to implement mass lead conversion through an integration or middleware?  The latter is where lead conversion gets really tricky, and that's the topic of this blog post.

I'm working on a rather large scale integration, which synchronizes both standard and custom objects from a source Salesforce org to another target Salesforce org.  The integration itself is a bit too complex to go with a standard Salesforce to Salesforce implementation.  One of the objects is Leads, and hence Converted Leads as well.

After digging into Lead conversion and how to integrate converted leads, I felt like Frodo getting caught by the spider



A few things I needed to consider were:

  • How do I convert leads using an external id?
  • How do I talk back to the source record, after a successful conversion, and prevent that record from being synchronized again?
  • Can this be accomplished with a successful web service call or two?
After toying around with a simple web service, it was quickly apparent that a single call really wouldn't suffice.  The leads in the integration are basically under a single account, and once you try and convert leads under a single account using logic similar to below, you get a "Duplicate Id in list exception".  Here's my post on Stackexchange asking for help on this issue: http://salesforce.stackexchange.com/questions/10520/best-approach-for-integrating-converted-leadswith-external-ids/10531?noredirect=1#10531

 List leadConversions = new List();
        for(Lead l : leadsToConvert){
            Database.LeadConvert lc = new Database.LeadConvert();
            if(l.Contact__r != null){
                lc.setContactId(l.Contact__r.Id);
                lc.setAccountId(l.Contact__r.AccountId);
            }
            lc.setLeadId(l.Id);
            lc.setDoNotCreateOpportunity(true);
            lc.setConvertedStatus(status);
            leadConversions.add(lc);              
            leadExternalIds.add(l.External_Id__c);
        }
     
        List lcr = new List();
        Integer i=0;
        for(Database.LeadConvertResult r : Database.convertLead(leadConversions,false)){
            lcr.add(
                new LeadConversionResult(
                    r.isSuccess(),
                    r.getErrors().isEmpty() ? null : r.getErrors().get(0).getMessage(),
                    leadExternalIds.get(i++)
                )
            );
        }

After realizing this wouldn't work, it was time for a completely different approach.  Breaking out SoapUI (http://www.soapui.org/), a handy plugin for testing web service calls, and your best friend for testing out the Salesforce.com Enterprise and Partner WSDLs,  it was apparent that the api convertLead operation behaves differently than the apex version.  The convertLead operation does allow multiple leads under the same account!  Continuing the LOTR theme, the convertLead operation was my Samwise Gamgee to my integration Shelob (http://en.wikipedia.org/wiki/Shelob)

Taking the above into consideration I came up with the following solution:

  1. When the source lead is converted, the external id is loaded into a custom object.  This allows the control successes and failures in the integration since leads cannot be updated after they are converted.
  2. The integration queries the converted object queue above and passes the external ids to a webservice on the target org to retrieve their Salesforce Ids.  Since the external ids are Unique, and Case sensitive, it's a straight 1-1 mapping.
  3. The ids are transformed into a convertLead request, which is a operation available on the partner wsdl.
  4. Any successes are passed back to a third webservice call, which deletes successful conversions from the custom object "queue".  Errors are left in the queue for re-processing
The flow of the operation looks something like this:


And there you have it, a solution for integrating converted leads.



Wednesday, February 13, 2013

Managed Package Unknown Server Errors (Gacks)

Creating a Salesforce managed package and get a non-descript "Salesforce has encountered an Unknown error "8675309" code?  These are called gacks in Salesforce land.  The only way to decode these errors is to contact Salesforce support, or someone at Salesforce who can look up the gack for you.

Through a bit of trial and error, here are the reasons I've encountered gacks while uploading packages

  1. Record Types or Business Processes have the same name (even though they are across different objects)  
    1. The resolution for this is simple (hopefully) and involves renaming the record type or business process to be distinct, such as RecordTypeName_ObjectName
  2. Invalidated class.  
    1. The result of perhaps only deploying a subset of classes to the packaging org.  I deployed a change to a VF controller, but removed a method its test class was dependent on.  After fixing the issue, the package was successfully uploaded.
  3. Permission Sets
    1. Permission sets containing CRUD permissions on Standard objects fail with "Unknown error".  This is because Permission sets cannot by design update Contacts, Leads, Accounts, Opportunities, and other standard objects.  The fix for this issue is to modify the permission set to uncheck all permissions on standard objects, and update them manually when installed.
If you have any other gacks and resolutions to them you've come across, feel free to comment below, and I will update the list above.

Tuesday, November 20, 2012

POSTing sensitive data over VisualForce

The Problem

My current project has a requirement for passing credentials from SFDC to an external site for auto-logging in users.  The requirement is a bit different from SSO, as these are Sales support representatives needing to log in to their customer's orgs for troubleshooting purposes.  The credentials are inherently sensitive, since they are username and passwords.

The current legacy system simply posts the credentials to a Cold Fusion form over HTTPS.  To mimmick this functionality, making it slightly more secure I implemented the following:
  The client's integration into SFDC stores the username / password data in encrypted fields, only allowing the System Admin to view the password data.  Secondly, the auto login function does its best to obscure the private information.  Furthermore, the auto login must be an HTTP POST to a form, rather than an HTTP GET.

Posting from VisualForce

POSTing from Visualforce is a bit tricky.  There's no real good way of going about it.  I've gotten comments on twitter (@dancinllama, by the way) regarding using the action parameter to do a HTTP callout on load.  However, the VF action also has to redirect to the page keeping the user logged in.  When I attempted this route, the browser never maintained the session.  Perhaps I was doing something wrong here, but I decided to go with a different solution.

In order to POST from Visualforce, I created a simple form with a username and password field.  The form was a straight HTML form, not utilizing the standard VF component.  On page load, JavaScript submits the form (to an HTTPS URL) and auto-logins the user.

Security through Obfuscation

The form itself was simple, but lead to a potential security flaw:  What if a "hacker" viewed the HTML source?  Even though the form input utilizes type="password" for masking in the UI, any schmuck can view the source and see the password in plain text.  Ruh-roh.  The solution was to utilize @RemoteAction call to populate the password value before the form was submitted.

The Code

Below is the simple @RemoteAction method.  Since the method is static, I had to pass in three variables to perform a dynamic query for retrieving the password on the fly.


  @RemoteAction
  public static String getPass(String field, String apiName, String recordId){
    String ans = null;
    try{
      sObject sobj = Database.query('Select ' + field + ' From ' + apiName + ' Where Id=:recordId');
      ans = (String)sobj.get(field);
    }catch(Exception e){}
    return ans;
  }

The remote action is called on page load from the VisualForce page using javascript wizardry, which passes in the object api name, the field api name, and the id of the record to query.



<form method="post" id="uform" name="uform" action="{!url}">  <input type="text" name="username" value="{!username}" />  <input type="password" name="password" value="" />  <input type="submit" value="Submit" /></form>



<script type="text/javascript"> function getPass() {
   Visualforce.remoting.Manager.invokeAction(
     '{!$RemoteAction.MyClass.getPass}',        '{!passwordFieldName}'        '{!objectApiName}'        '{!recordId}',        function(result, event){
          if(event.status){
            document.getElementById('pass').value=result;
            document.uform.submit();
          }
        },
        {escape: true}
    );
}
if(window.attachEvent){
    window.attachEvent("onload",getPass);
}else{    window.addEventListener("load",getPass, false);
}
</script>


Although it's a bit clumodgeony, it gets the job done.  The end result is the user is redirected to "url" and if they have valid credentials, are logged into the external system.  If you have any questions, comments, or critiques, please leave them below or ping me on twitter (@dancinllama).








Thursday, May 17, 2012

Overriding Approval Button Label

I had a recent need for override the label of the 'Submit for Approval' button, which is enabled by creating an approval process on an object out of the box in Salesforce.  Unfortunately, since the Submit for Approval is sort of generic across different objects, there is no way of overriding the label through Setup->Customize->Tab Names and Labels.

The solution is to implement a two line VF page and hook it up to it's own button, complete with the new label.  The VF page still uses standard out of the box functionality, and no apex was used nor harmed during this customization.  

The trick is to utilize the $Action global variable.  If you take a look at the Name of the Submit For Approval button on the page layout, you should find the name of the button/action is "Submit".  Going forward with this, I created the following simple Visualforce page:

<apex:page standardController="Case" action="{!URLFOR($Action.Case.Submit,case.Id)}">
apex:page>

Note that utilizing the action parameter is considered a CSR security risk and will be flagged if you depend on packaging up the Visualforce page.

After the Visuaforce page is created, the next step is to create a custom detail page button, opening the page in existing window with sidebar.  Set the label on the button to the text you desire.  Finally, modify the page layout(s) and replace the 'Submit for Approval' button with your custom VF button.

There you have it, an easy-peasy way to "override the label" using (mostly) out-of-the-box functionality.

Friday, January 6, 2012

Adding a default value for Campaign Standard Field

Scenario: Without needing to enter the Campaign Name field on the edit Campaign screen, have a trigger define the Campaign Name field based on a formula like criteria.


Problem:  The Name field is required on the Campaign, and saving the page layout fires a field validation rule before the before update trigger runs.  Furthermore, there is no option to provide a default value for the Name field unlike custom text fields.


Solution: Feed a dummy data value into the Campaign name through a custom Visualforce solution.  The solution involves overriding the New button on the Campaign and directing the user to the Campaign edit page with the Campaign name pre-populated, allowing the campaign to save and fire the trigger.


Step 1) Create a Controller extension to prepopulate the Campaign Name:


Apex controller extension (CampaignExtension.cls):
public with sharing class CampaignExtension {

  public CampaignExtension(ApexPages.StandardController stdController) { 
  }
  
  public PageReference gotoUrl(){
    PageReference pageRef = new PageReference('/701/e');
    Map params = pageRef.getParameters();
    params.put('nooverride','1');
    params.put('RecordType',recordType);
    //See notes below
    params.put('cpn1','Campaign Name');
    return pageRef;
  }
}



** Notes:  
The 'cpn1' parameter is related to whichever field to default.
Viewing the HTML source of the Campaign edit screen reveals that the HTML id of the Name field is 'cpn1', hence the cpn1 parameter for the Campaign Name field.

Step 2) Create a VF page:


<apex:page standardController="Campaign" 
  extensions="CampaignExtension" 
  action="{!gotoUrl}" />

Step 3) Override standard new button for Campaign:
  1. Setup->Customize->Campaigns->Buttons and Links
  2. Click Edit next the standard New button
  3. Select the Visualforce Page radio button and select the Visualforce page from Step 2 above.
  4. Validate that "Skip Record Type Selection Page" is unchecked. 
  5. Save the override properties
Wa-la, you should have a mechanism to set the default value for a required standard field on a standard object.






Tuesday, August 16, 2011

Convert Credit Card Exp date to YYYY-MM-DD

Had a recent requirement to convert a credit card expiration date from MMYY to YYYY-MM-DD so that it could be sorted upon in Salesforce.  Fortunately, I only had to modify the view in Oracle to the following:

select
    DECODE(
      NVL(myColumn,'N/A'),
      'N/A',
      'N/A',
      to_char(last_day(to_date(myColumn,'MMYY')),'YYYY-MM-DD')
    )
  from myTable


Friday, March 18, 2011

Bug in Email templates with similar Standard and Custom field names

I've been working on several workflow and email alerts lately.  I recently came across a curious defect with email templates.  Honestly, I don't know if it's strictly limited to the templates.  The defect involves an object which has standard and custom fields with the same 'name'.

If the object has a Standard field name and a custom field Name__c, an email template will pick up the custom field.

Steps to recreate:
1) Go to Setup->Create and Create a custom object 'obj' with a custom field of Name.
2) Go to Setup->Create and Create a tab to the custom object.
3) Go to the custom object tab and populate the object with Name='AAA', Name__c='BBB'.
4) Go to Setup->Communication Templates and create a test email template with:
  Subject: Name should be AAA {!obj__c.Name}
  Body: Name 1 should be AAA: {!obj__c.Name}
  Name 2 should be BBB: {!obj__c.Name__c}

5) Save the email template.
6) On the template, click 'Send test and verify merge results'
7) Populate the template with a valid contact and your new obj__c object.
8) You will see the defect.  The subject will say: Name should be AAA: BBB

Thursday, March 3, 2011

Leads, Campaigns, and Workflow

I have a requirement for a client that wishes to create a Web 2 Lead form and assign it to a campaign.
Once that is done, a workflow shall fire off a series of emails depending on what sort of campaign the lead is tied to.  This sounds easy enough to do with Salesforce's out of the box Web2Lead functionality and workflow, but there were some other tweaks we needed, so utilizing our own solution is the only way to go.

- The form -
Utilizing a jQuery modal, the user clicks a link and populates a small web to lead form.  When the user hits submit, sever side validation happens in a VF controller, so we can control the UI (messages and labels if a field is required for instance). 

- Allowing Portal users to use the web 2 lead form -
Once the form is submitted, it stores the lead in a custom lead object.  The custom lead object is needed, since leads cannot be created (owned) by Portal users.  When a portal user creates the mirrored lead object, it fires off a trigger calling an @future method to insert the lead and campaign member.

- Tricky workflows with Leads and Campaigns -
Here's the tricky part of the workflow.  When the lead is inserted, it doesn't have access to its related Campaign member and hence related Campaign (the Campaign member is a junction object to connect Campaigns to leads or contacts).  Our workflow needed to look at the Campaign Name field on the Campaign.  The lead doesn't have this when it is inserted, nor if the Campaign member is updated, does it update the lead.  Therefore, modifying the campaign member or campaign doesn't fire the workflow rule until the lead is updated next.  This is true even if the workflow rule is set to 'Created or did not previously meet the criteria'.

The solution is to create the workflow rule on the Campaign member and not the Lead.  When the Campaign Member junction is created, it should have access to both its Campaign and its Lead objects.  Thus, when the member is created, we can create a rule like 'Campaign Name equals My Name' and fire off a workflow when the Lead is assigned to the particular campaign.

Hope this helps others.

Monday, January 3, 2011

Force.com Labs Round Robin Record Assignment - Case Owner issue

There's an existing defect in the Salesforce package for Round Robin Record Assignment.  (http://appexchange.salesforce.com/reviews?listingId=a0N3000000178fsEAA).  The Force.com lab unmanaged package assigns Cases to an owner/queue when available.  The package contains two triggers which assign the case to an owner; caseRoundRobin.trigger and caseOwnerUpdate.trigger.

The two triggers inadvertently fight with eachother.  The fighting causes a Case to be re-assigned to it's original owner when it is first reassigned ownership. Say you have a case w/ owner John, and you want to reassign it to owner Mary.  In the Salesforce UI, after you save the ownership, it reverts back to John on the first attempt.  A second attempt will get you to the right owner, however.

The defect arises in caseOwnerUpdateTrigger.  After the code loops through the effected cases in the Trigger, via Trigger.new, it adds the cases to a temp list and then does a SOQL query to retrieve them once more via Id. The second loop does a query against uncommitted data and returns the yet unmodified owner of the Case, which would be John from the example above.  The case is then updated w/ the former Owner and appears the Case never changes hands.

The following change to the trigger should clear things up, consolidating everything into one loop, with no 'dirty', or uncommitted reads.

Two notes here: 1) Since the case in the loop is in process of being edited by the Trigger, it is locked and in read-only mode.  Therefore, a temp case is created and added to the update list.
2) The update call is made on the list of cases rather than on individual cases in the loop.  This is a Salesforce best practice, in order to mitigate SOQL queries and DML.

trigger caseOwnerUpdate on Case (after update) {
    List updateCS = new List();
    Map cases = new Map();
   
    for (Case cs : Trigger.new)
    {
        if(Trigger.isUpdate) { 
            System.debug('>>>>> Owner ID: '+cs.ownerId+' Temp Owner ID: '+cs.TempOwnerId__c);
            if(cs.TempOwnerId__c <> null && cs.TempOwnerId__c <> '') {
                if(cs.OwnerId <> cs.TempOwnerId__c) {
                    Case temp = new Case();
                    temp.OwnerId = cs.TempOwnerId__c;
                    temp.TempOwnerID__c = 'SKIP';
                    updateCS.add(temp);
                }
            }          
        }  
    }
 
    System.debug('>>>>>Update Cases: '+updateCS);
   
    //
    //Update last assignment for Assignment Group in batch
    //
    if (updateCS.size()>0) {
        try {
            update updateCS;
        } catch (Exception e){

        }
    }
}

Monday, December 27, 2010

Inheritance and Visualforce page controllers

Salesforce Apex is pretty finicky with inheritance in comparison to Java.
Even though it is Java based, there are many caveats, especially in inheritance and OO related principles.

In Visualforce, you have the option of denoting either a StandardController or Controller, in addition to controller extensions.  The extensions may or may not have code in common with the controller.  If they do, then you'll want to take advantage of inheritance and creating an abstract controller.

Below is a simple example of a Visualforce page utilizing an abstract controller.

Test.page:

<apex:page controller="Test" extensions="Test1,Test2,Test3">
<apex:form>
<apex:commandButton value="Go" action="{!go}" rerender="out" />
<apex:outputPanel id="out">{!output}</apex:form>
</apex:page>

Test.cls:
public abstract class Test {
  public String output {get; set;}
 
  private Test controller = null;
 
  public Test(){}
 
  public Test(Test controller){
      this.controller = controller;
  }
 
  public virtual void go(){
      output = 'Test';
  }
}

Test1.cls:
public class Test1 extends Test{
  public override void go(){
      this.output = 'Test1';
  }
  //Visual force needs this constructor to perform the controlling logic
  public Test1(Test test){ super(test); }
}

Test2.cls:
public class Test2 extends Test{
  public override void go(){
      this.output = 'Test2';
  }
  public Test2(Test test){super(test);}
}

Test3.cls:
public class Test3 extends Test{
  public override void go(){
      this.output = 'Test3';
  }
  public Test3(Test test){super(test);}
}

FYI, if you're reading through the Advanced developer study guide, 'Test1' is printed after clicking  the go command button.

Thursday, December 16, 2010

ORA-12519

I created a polling adapter in my BPEL process.  Once I threw it on the server, it caused the Oracle XE (10.1.3?) database to crash.  After the database crashed, I could not view the BPEL console nor execute any commands on the database through SQL Developer.  The error I received was 'ORA-12519'.

What happens is that the XE database by default only allows a small number of connections.  BPEL consumes those connections rather quickly. If you encounter this problem, restart the XE database:
  1.   Perform the following SQL as SYS user: ALTER SYSTEM SET PROCESSES=150 SCOPE=SPFILE
  2. Restart the database
  3. Restart BPEL / SOA

Wednesday, December 15, 2010

BPEL and TopLink - Method Accessors have not been selected

This error occurs when adding a DbAdapter in BPEL, having a master-detail or 1 to many relationship.  There's more information on this defect and a solution at this link: http://iadviseblog.wordpress.com/category/toplink/.  Search for 'Method accessors'.