Flow and FinishLocation

pulling-hair-out-321x300Have you tried using Flows with Visualforce pages and tried to set the finishLocation to a dynamic value?  Odds are yes, and odds are even better that you had (or are having) no end of frustrations trying to get it to fire right.

The key to get your dynamic finishLocation to fire right is to factor your PageReference in such a way where as you are progressing through the flow and while the wrapper Visualforce page is rerendering, you can effectively capture and utilize Flow output variables.

To start, let’s embed a flow in a Visualforce page:

<apex:page controller="flowController">
<flow:interview name="DemoFlow" interview="{!flDemo}" finishLocation="{!prFinishLocation}" />
</apex:page>

You’ll note that the “interview” attribute is in use.  That is one of the necessary steps to make this work – you need to link your Flow to the controller.

public class flowController{
// Instanciate the Flow for use by the Controller - linked by VF "interview" attribute
 public Flow.Interview.DemoFlow flDemo {get;set;}

 // Factor your PageReference as a full GET/SET
 public PageReference prFinishLocation {
 get {
 PageReference prRef = new PageReference('/your/page/location?var1= + strOutputVariable);
 prRef.setRedirect(true);
 return prRef;
 }
 set { prFinishLocation = value; }
 }

 // Factor your Flow output variable pull as a full GET / SET
 public String strOutputVariable {
 get {
 String strTemp = '';

 if(flDemo != null) {
 strTemp = string.valueOf(flDemo.getVariableValue('your flow output variable name');
 }

 return strTemp;
 }

 set { strOutputVariable = value; }
 } 

}

You’ll see that both the finishLocation’s PageReference as well as the variable that captures the Flow’s output variable are all in fully broken out GET/SET logic.  Factoring your code in this manner is the trick; as you move through the flow, the Visualforce page re-renders each time the user progresses through a Flow Screen.

**NOTE!  There is also a trick to how your actual Flow is set up.  For instance – if your Flow is creating a Contact and you want to direct the user to that Contact’s standard detail record upon completion of the Flow, you will need to have one last screen at the end to force the Visualforce page re-render so your controller can grab that Contact’s Id.

**ANOTHER NOTE!  You will NOT be able to get 100% test coverage when you link Flow to a controller like this.  Because Flow requires user-interaction, if you try and reference the “flDemo” variable from the example above without first checking to see if it’s null (which it will be in the Unit Test), your test will fail.  There is NO way right now (confirmed by Salesforce) to full test a Flow using this method…don’t pull your hair out trying.

Good luck!  Hit me up in the comments if you have other great Flow hacks or if you have issues getting this method to work.

Thanks for reading!

Sending Email Template via APEX – No TargetObjectId?

kitty-help-fix-computerHere’s a quick tip!

If you’re using APEX to send an email template to a group of addresses but don’t necessarily have a User, Contact, or Lead to associate the email to (setTargetObjectId) normally you’re out of luck right?

Not necessarily – insert a little dark magic…literally!   We’re going to insert a Contact (or Lead) in our APEX code with an email address of “no-reply@organization.com”, use that for our SingleEmailMessage, then delete it when we’re done.

DISCLAIMER!

Now – you want to always do a sanity check before slamming code like this in.  Make sure that you properly fit it in your org and ensure that you aren’t going to bump into any other triggers, validation rules, etc, etc, etc when you’re inserting this “dummy contact”.  This code is NOT necessarily best practice as-is, it’s here just to help you realize your own best-practice method.  =)

// Create Contact
Contact con = new Contact();
con.FirstName = 'Test';
con.LastName = 'Contact';
con.Email = 'no-reply@organization.com';
insert con;
// Create Email and Send
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
msg.setTemplateId('Your Email Template Id');
msg.setCcAddresses(new String[] {'email1@recipient.com', 'email2@recipient.com'});
msg.setTargetObjectId(con.Id);
msg.setWhatId('Your Record Id if applicable');
msg.setSaveAsActivity(false);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { msg });
// Don't Forget!  Clean up!
delete con;

Happy coding!

Why you should use System.Assert

assert-sign-photoshoppedOne of the many things I do to help further the awesomeness of Salesforce and to bring more developers on board is to review code – recommending best practices, coding styles, and just overall teaching good tips to write better code.

One of the many things that I end up talking about is why verification of your unit tests is important, not just raw line coverage. Writing APEX Unit Tests is a new concept for most developers coming in from other languages and platforms.  I know it was a new concept and honestly a bit of a struggle for me coming from .NET!

Let’s start by talking about one of the most common ways Salesforce developers get bit by the Unit Test ghost.  It’s not the initial development that gets you – it’s when you have to deploy new code six months down the road after your original code has been in the wild.  Taking an extra 10-15 minutes up front to systematically verify your test results will save you hours down the road, trust me. With very rare exception, there isn’t a single Salesforce org that remains completely static and rigid for a month, much less six months. Businesses are dynamic with new workflows, validation rules, APEX code, fields, (must I go on?) being added as processes are changed or refined.

As Murphy’s Law would have it, the first organizational change done will break your unit tests, and naturally you’ll only see it when you’re pushing code at 11pm on Friday night.

Bottom line:  The sooner we accept that the world is dynamic and our code will break, the sooner we can learn how to make our code intelligent enough to help us figure out why and how to fix it.

Salesforce has a great article on “Testing Examples” – I’m not going to rehash the nitty-gritty details in this blog, but I strongly urge you to go read it. The big three things that this article points out are:

  1. Test for your desired result (POSITIVE)
  2. Test for common errors (NEGATIVE)
  3. Test as the user(s) and profile(s) that will use this functionality

Why should you always cover these three areas in your unit tests?  Two words…”Business Rules”.  What you created wouldn’t need to exist if there weren’t business rules that drove the data to it.

Who does it, what are they doing, when do they do it, where do they do it, and why do they do it?

To build a true unit test, you need to answer these questions both positively and negatively, as well as within the context of the specific user(s) that are doing it. Now you’re saying, “Ok, I get it…how do I do it?” right? Enter System.Assert, System.AssertEquals, and System.AssertNotEquals!

The first mistake I made was only to test for positive results.  “It should work here, and my Assert will just tell me if it doesn’t, that’s cool right?”  Not completely – we want to make sure we test for both positive AND NEGATIVE outcomes, as your users will never follow the “happy path” you’ve coded consistently.

Ok, so here’s your rule of thumb.  If you are changing data through variable assignment, DML, or even just through normal code logic, you need to ensure that after everything is said and done what you EXPECT should have happened…DID.

Here are some examples – keep in mind these are VERY simplistic and meant only as demonstration aids.  Please refer to the Salesforce link above for full best practices!  (try/catch blocks, multiple assertions, full logic testing, etc., are all part of good Unit Tests!)

Example Positive:

Use Case – simple insertion of Account record

Account acctTest = new Account(Name='Test Account');
insert acctTest;
System.Assert(acctTest.Id != null, 'The Test Account did not insert properly, please check validation rules and other mechanisms');

Example Negative:

Use Case – existing Validation Rule that does not allow ‘Test’ in an Account Name

Account acctTest = new Account(Name='Test Account');
try {
insert acctTest;
} catch (Exception ex) {
System.Assert(ex.getMessage().contains('Insert Failed'), 'Account Validation Rule did not fire');
}

Example User Context:

Use Case – The ‘Service’ Profile need to be able to execute a DML “Update” of an Account record

Profile prfStandard = [select id from profile where name='Service']; 
 User uServiceUser = new User(alias = 'standt', email='standarduser@testyourorg.local', 
 emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US', 
 localesidkey='en_US', profileid = prfStandard.Id, timezonesidkey='America/Los_Angeles', username='standarduser@testyourorg.local');
Account acctTest = new Account(Name='Test Account');
insert acctTest;
System.runAs(uServiceUser) {

acctTest.Name = 'Test Account - Service Mod';
update acctTest;
System.Assert(acctTest.Name = 'Test Account - Service Mod','The Service Profile was not able to update an Account properly!');
}

TL;DR

At first, you’ll be really annoyed that “I have to do WHAT?!? C’mon, the logic is right there!”, and for your initial deployment that will be the case. Believe me six months down the road when new business logic has been introduced and you are deploying new code only to see your old code is failing…

You’ll be happy that you have Assertions in there to help guide you home quickly.  =)

Questions?  Comment away!

Salesforce Integration Best Practices

DCSLogo_Maroon-Horizontal-GradientIntegration / interoperability is no longer an “if”, it’s a “when”.  Make sure you approach your project correctly and set you and your company up for success.  Check out a great “Best Practices” blog post I contributed to at Demand Chain Systems!

http://bit.ly/19fUIqu

Visualforce Page Printable View

f02a62983ebcHow many times have you been asked to “can you make that a printable view, ya know, without the top and sidebar?” when you create a Visualforce Page?

If you have, you know the deal.  If not, oh don’t worry, you will before too much longer.

There is a quick and easy way to use the same VF page and APEX Controller that you already have built, using some Page variables, OutputPanels, some minor Javascript, and your “action” page attribute.

Step 1:  Create a Boolean variable and an “init” void method in your Controller

Something to the tune of:

public Boolean bolPrintableView {get;set;}

– and –

public void init() {
 String strPrintableView = ApexPages.currentPage().getParameters().get('print');
 bolPrintableView = (strPrintableView == '1');
}

Step 2:  Modify your VF Page attributes

<apex:page controller="YourPageController" showHeader="{!bolPrintableView}" sidebar="{!bolPrintableView}" action="{!init}">

Step 3:  Add a “Printable View” link to your VF Page

I will usually do this with an OutputPanel with the “rendered” attribute being set to the opposite of my controller’s printable view flag.  Doing this gets rid of the silly link for “Printable View” on your printed page along with any silly users clicking on the button again.

<apex:outputPanel rendered="{!NOT(bolPrintableView)}">
    <a href="/apex/YourVFPage?print=1" target="_blank">Printable View</a>
</apex:outputPanel>

Step 4:  Use a quick Javascript function to immediately call the print dialog on load

Again I’ll usually wrap this in another OutputPanel with the “rendered” attribute being set to what the printable view flag is – we don’t want this firing on the normal view of the page!

<apex:outputPanel rendered="{!bolPrintableView}">
 <script>
  window.print()
 </script>
</apex:outputPanel>

Optional Step 5:  Some pages just look better in Landscape mode – let’s use some CSS so it pops up like that by default.

<style type="text/css" media="print">
 @page { size: landscape; }
</style>

That’s it!  Works like a charm.  Questions?  Hit me below in the comments!

Public Anonymous Web Service on Salesforce Platform – No Login!

39645249So I was approached recently with the need to expose data to a vendor.  “Sure!” I thought…”What’s your endpoint, WSDL, and the format you want your data sent in?” was my initial response.

“No, we need to pull from you.” threw me for a loop – Salesforce ABSOLUTELY allows you to expose web services, but you need to establish a session first.  For an established vendor with 1,000’s of other clients they poll data from, there is no way in heck that they would change their process to add a log in component.

Hmmmph.  Well, let’s figure this out.  Salesforce is awesome, and there is always a way to do this.

Step 1:  Create your APEX Web Service

global class Generic_Whatever_Service {
webService static String yourWebService() {
String strReturnValue = 'Put whatever normal logic in here you would do';
return strReturnValue;
}
}

Step 2:  Create or Navigate to a Salesforce Sites instance

You’ll need to go in to the “Public Access Settings” button and configure the Guest Profile to be able to access your APEX class and any other objects that it may hit.

Step 3:  Download your WSDL and modify your endpoint

You’ll note that the endpoint in the WSDL is set to be https://yourinstance.salesforce.com/services/soap/class/name_of_your_class.  If you try to access this as it’s provided, you’ll be prompted for a sessionId, hence a login.

If you change your endpoint to be http://<your Sites URL>/<your Sites name if applicable>/services/soap/class/<name of your class> you’ll find that you now have a fully anonymous web service!

WAIT!  Don’t forget about security!

Honestly, there is no reason that you need to have a fully anonymously-accessible web service hosted by Salesforce.  The platform does a lot, but it’s just not geared for that IMHO.  (You should have an environment built for this if you are hosting data like that)

What I’ve done with the services I publish like this is to lock down access to it via the Guest Profile’s “IP Login Ranges”, found through the “Public Access Settings” button in Sites.  While this method doesn’t completely shut down access, people outside of your specified ranges will get an “INSUFFICIENT_ACCESS” error when trying to access your web service.

Questions?  Ask below.  =)

Call for posts!

Hello everyone!  Just passed 25,000 views on my blog and hit 500 Twitter followers – THANK YOU for taking time out of your day to stumble upon my blog here and read a few articles.  I only hope that what you found on here helped you out at least a little.  =)

What would you like to have me blog about next?  Mobile?  More how-to articles?  Comment below and challenge me.

-Andy