<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Clint Lee</title>
	<atom:link href="http://www.clintslee.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.clintslee.com</link>
	<description>Salesforce Consulting :: CRM Implementation:: Business Process Design</description>
	<lastBuildDate>Thu, 19 Jan 2012 17:25:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Display Inaccessible Objects to (Salesforce) Portal Users</title>
		<link>http://www.clintslee.com/2011/06/28/display-inaccessible-objects-to-salesforce-portal-users/</link>
		<comments>http://www.clintslee.com/2011/06/28/display-inaccessible-objects-to-salesforce-portal-users/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 05:11:21 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apex]]></category>
		<category><![CDATA[Sites]]></category>
		<category><![CDATA[Visualforce]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=640</guid>
		<description><![CDATA[It&#8217;s quite late, and I can&#8217;t think of anything particularly clever to say, so I&#8217;ll just get straight to the point. If you&#8217;ve ever built a custom portal using Salesforce Sites then you&#8217;ve most likely had to navigate your way through the various portal licenses at some point. Let&#8217;s see, there&#8217;s a Customer Portal, a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clintslee.com/wp-content/uploads/2011/06/offlimit1.jpg"><img class="size-full wp-image-646 alignnone" style="border: 2px solid #cccccc;" title="Off Limits" src="http://www.clintslee.com/wp-content/uploads/2011/06/offlimit1.jpg" alt="Off Limits" width="500" height="333" /></a></p>
<p><a href="http://www.clintslee.com/wp-content/uploads/2011/06/offlimit1.jpg"></a>It&#8217;s quite late, and I can&#8217;t think of anything particularly clever to say, so I&#8217;ll just get straight to the point.</p>
<p>If you&#8217;ve ever built a custom portal using Salesforce Sites then you&#8217;ve most likely had to navigate your way through the various portal licenses at some point. Let&#8217;s see, there&#8217;s a Customer Portal, a High Volume Customer Portal, an Authenticated Sites, and perhaps another one.  Oh yeah, then there&#8217;s the Public Site profile.  Each license has its own nuances &#8211; object access, CRUD permissions, cost.  Inevitably you&#8217;ll need to decide on the license type that best fits what you&#8217;re trying to do, knowing that you might have to concede something down the road as you hit a gotcha! or two.</p>
<p>I came across a particular situation where I needed to display information from the Account object to the user.  The Site being built utilized the Authenticated Sites portal license (which provides user authentication but requires a lot of development since it requires only Visualforce pages).  Unfortunately, the Authenticated Sites license doesn&#8217;t provide the user with access to the Account object.  When I say no access I mean they can&#8217;t even read it.  So, a workaround ensued&#8230;</p>
<p>The following solution is not particularly mind-blowing, or really even that sophisticated, but it works for displaying data in what could be termed as &#8220;inaccessible&#8221; objects.  These are objects that Authenticated Sites licensees can&#8217;t read like Accounts, Opportunities, and Cases.  Enter&#8230;.(drumroll, please)&#8230;the Wrapper Class.  Yes, folks, the Wrapper Class.  To most, this was probably obvious from the start but for me it took some noodling around.  Therefore, I decided to share in an effort to prevent others like me from noodling for too long.</p>
<p>Go ahead and create a wrapper class for your object, like so. Name it whatever you like.  I call mine AccountToString b/c it sounds fancy.</p>
<pre class="brush: java; title: ; notranslate">
public class AccountToString {
	   private Account acct;

	   public AccountToString(Account acct) {
	   	      this.acct = acct;
	   }

	   public String getName() {
	   	      return acct.Name;
	   }

	   public String getAddress() {
	   	      return acct.BillingAddress;
	   }

	   public String getCity() {
	   	      return acct.BillingCity;
	   }

	   public String getState() {
	   	      return acct.BillingState;
	   }

	   public String getZip() {
	   	      return acct.BillingPostalCode;
	   }

}
</pre>
<p>Write a controller method to turn your accounts into AccountToStrings.  I needed a table with Account data so I populated a class variable with a list of AccountToStrings.  Here&#8217;s an example.</p>
<pre class="brush: java; title: ; notranslate">
// This method could run in the controller's constructor.
public void findAccounts() {
           List&lt;Account&gt; accts = [select Id, Name, BillingAddress, BillingCity, BillingState, BillingPostalCode from Account];
           for(Account a : accts) {
                 AccountToString aString = new AccountToString( Name = a.Name, BillingAddress = a.BillingAddress, BillingCity = a.BillingCity, BillingState = a.BillingState, BillingPostalCode = a.BillingPostalCode);
                 aStringList.add(aString); // aStringList is a public class variable
           }
</pre>
<p>Finally, in your Visualforce page, this is one way that you could access your list of AccountToStrings.</p>
<pre class="brush: java; title: ; notranslate">
&lt;apex:page controller=&quot;MyPortalController&quot;&gt;
    &lt;apex:outputPanel layout=&quot;block&quot;&gt;
        &lt;apex:dataTable id=&quot;mytable&quot; value=&quot;{!aStringList}&quot; var=&quot;a&quot;&gt;
             &lt;apex:column &gt;
                  &lt;apex:facet name=&quot;header&quot;&gt;Account Name&lt;/apex:facet&gt;
                  &lt;apex:outputText value=&quot;{!a.name}&quot; /&gt;
             &lt;/apex:column&gt;
             &lt;apex:column &gt;
                  &lt;apex:facet name=&quot;header&quot;&gt;Address&lt;/apex:facet&gt;
                  &lt;apex:outputText value=&quot;{!a.address}&quot; /&gt;
             &lt;/apex:column&gt;
             &lt;apex:column &gt;
                  &lt;apex:facet name=&quot;header&quot;&gt;City&lt;/apex:facet&gt;
                  &lt;apex:outputText value=&quot;{!a.city}&quot; /&gt;
             &lt;/apex:column&gt;
             &lt;apex:column &gt;
                  &lt;apex:facet name=&quot;header&quot;&gt;State&lt;/apex:facet&gt;
                  &lt;apex:outputText value=&quot;{!a.state}&quot; /&gt;
             &lt;/apex:column&gt;
             &lt;apex:column&gt;
                  &lt;apex:facet name=&quot;header&quot;&gt;Zip&lt;/apex:facet&gt;
                  &lt;apex:outputText value=&quot;{!a.zip}&quot; /&gt;
             &lt;/apex:column&gt;
          &lt;/apex:dataTable&gt;
     &lt;/apex:outputPanel&gt;
&lt;/apex:page&gt;
</pre>
<p>I hope this makes sense and perhaps saves you some time.  As always, I look forward to any comments or feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/06/28/display-inaccessible-objects-to-salesforce-portal-users/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Summer &#8217;11 Master-Detail Quirk [UPDATED]</title>
		<link>http://www.clintslee.com/2011/06/23/summer-11-master-detail-quirk/</link>
		<comments>http://www.clintslee.com/2011/06/23/summer-11-master-detail-quirk/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 03:28:07 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apex]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=618</guid>
		<description><![CDATA[*****UPDATE June 30, 2011****** Shortly after this post I was contacted by Salesforce&#8217;s Apex product manager who wanted to follow up on this issue and help resolve it.  Major kudos to Salesforce for monitoring the blogosphere and addressing the problems of their partners and customers.  After spending some time trying to recreate this problem the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clintslee.com/wp-content/uploads/2011/06/summer11.gif"><img class="size-full wp-image-619 alignnone" title="Salesforce Summer 11 Logo" src="http://www.clintslee.com/wp-content/uploads/2011/06/summer11.gif" alt="Salesforce Summer 11 Logo" width="375" height="103" /></a></p>
<p><strong>*****UPDATE June 30, 2011******</strong></p>
<p>Shortly after this post I was contacted by Salesforce&#8217;s Apex product manager who wanted to follow up on this issue and help resolve it.  Major kudos to Salesforce for monitoring the blogosphere and addressing the problems of their partners and customers.  After spending some time trying to recreate this problem the SFDC team could not replicate it, and so apparently whatever was causing this quirky issue to happen has been resolved, effectively making the rest of this post obsolete.  But, you can read on for the history if you&#8217;d like&#8230; <img src='http://www.clintslee.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>*****************************</strong></p>
<p>The good news about working on the Salesforce platform is that three times a year, while you&#8217;re lying asleep at night, the little Salesforce elves are hard at work rolling out the newest release.  The bad news is that sometimes on a Monday morning you start seeing Apex errors in your inbox.  This past release of the Summer &#8217;11 upgrade was one of those times for me.  I thought I&#8217;d share the details to prevent anyone else from banging their noggin&#8217; against the wall.  Spoiler Alert! The story ends happily with a working solution.</p>
<p><strong>The Background</strong></p>
<p>We had a portion of Apex code that, when executed, created a custom object which was the detail side of a master-detail relationship.  Nothing special going on here, just straightforwardness.</p>
<p><strong>The Problem</strong></p>
<p>On the Monday morning after the org was upgraded to Summer &#8217;11 errors started to kick off whenever this particular piece of code was executed.  The error given was &#8220;Field Not Writable&#8221; and it referred to the lookup field that looked up to the Master object.  For all the visual learners out there (like me!) see the diagram below.</p>
<p style="text-align: left;"><a href="http://www.clintslee.com/wp-content/uploads/2011/06/Screen-shot-2011-06-23-at-10.05.22-PM.png"><img class="aligncenter size-full wp-image-631" style="border: 1px solid #CCC;" title="Master-Detail Visual" src="http://www.clintslee.com/wp-content/uploads/2011/06/Screen-shot-2011-06-23-at-10.05.22-PM.png" alt="Master-Detail Visual" width="485" height="288" /></a></p>
<p style="text-align: left;">Whenever an Object B was attempting to be inserted we would get an error on Field 1 saying &#8220;Field Not Writable&#8221;.  Very strange since two days earlier this was working splendidly and nothing had changed since.  After quite some time of trying to track down the root problem we submitted a Case to Salesforce assuming this was some bug related to the upgrade.  As it usually goes, shortly after submitting the case we developed a solution that worked.  Here it is&#8230;</p>
<p style="text-align: left;"><strong>The Solution</strong></p>
<p style="text-align: left;">This is actually so simple it hurts.  The object was being created like this.</p>
<pre class="brush: java; title: ; notranslate">
Object_B__c objB = new Object_B__c();
objB.field1__c = objectAId;
insert objB;
</pre>
<p>The solution was simply to instantiate the Master object field in the constructor.  Like so&#8230;</p>
<pre class="brush: java; title: ; notranslate">
Object_B__c objB = new Object_B__c(field1__c = objectAId);
insert objB;
</pre>
<p>A very subtle quirk in the new release but nonetheless one that can cost you hours of time trying to understand and resolve.  Salesforce support did respond and let me know that they were unaware this change had happened.  The case was forwarded on for analysis.  No word yet on whether this was intended or unintended but for now all is good.</p>
<p>I hope this helps and as always I look forward to any comments or feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/06/23/summer-11-master-detail-quirk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Will Database.com Handle Big Data?</title>
		<link>http://www.clintslee.com/2011/05/28/will-database-com-handle-big-data/</link>
		<comments>http://www.clintslee.com/2011/05/28/will-database-com-handle-big-data/#comments</comments>
		<pubDate>Sat, 28 May 2011 20:05:18 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=587</guid>
		<description><![CDATA[I&#8217;m really looking forward to next week&#8217;s sneak peek webinar of Salesforce&#8217;s new DaaS (database-as-a-service) appropriately named Database.com. Salesforce is touting the new service as the premiere cloud database for enterprises &#8220;that is designed for the next generation of collaborative, mobile and real-time apps.&#8221; The question I have is will Database.com give any real or [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clintslee.com/wp-content/uploads/2011/05/blog_bigdata.jpg"><br />
</a><a href="http://www.clintslee.com/wp-content/uploads/2011/05/blog_bigdata.png"><img class="size-full wp-image-613 alignright" title="blog_bigdata" src="http://www.clintslee.com/wp-content/uploads/2011/05/blog_bigdata.png" alt="" width="462" height="260" /></a></p>
<p>I&#8217;m really looking forward to next week&#8217;s sneak peek webinar of Salesforce&#8217;s new DaaS (database-as-a-service) appropriately named Database.com.  Salesforce is touting the new service as the premiere cloud database for enterprises &#8220;that is designed for the next generation of collaborative, mobile and real-time apps.&#8221;  The question I have is will Database.com give any real or affordable options for handling big data?</p>
<p><strong>What is Big Data?</strong><br />
To simplify, big data refers to datasets that are so large they become unmanageable using traditional database management tools (think hundreds of terabytes or event petabytes of data).  Big Data datasets can also be highly unstructured, meaning that the data in them doesn&#8217;t fit neatly into a traditional relational database.  Handling this type of data requires new sets of tools and frameworks that are designed for capturing, storing, searching, and analyzing such large amounts of data.</p>
<p><strong>But Who Needs to Worry About Processing This Much Data? </strong><br />
In the past, the problems associated with handling datasets of this size might have been limited to only the largest research institutions like NASA, CDC, National Weather Service, etc.  However, with the explosion of new social and mobile applications and the ubiquity of mobile devices it&#8217;s no longer unthinkable to amass such large datasets.  For example, there are more than 30 billion (yes, billion) pieces of content shared on Facebook each month.  All of these data points have to get stored in a database, right?  Yep.  And when you login to your Facebook account the system has to query all of your friends, then query all of your friends&#8217; shared content, and then display it in your news feed &#8211; all in a matter of milliseconds.  Now multiply that by 600 million users.</p>
<p><strong>Database.com is for the Enterprise, Not Wannabe Facebook Startups, Right?</strong><br />
Right.  Well&#8230; wait.  Actually&#8230;well, I&#8217;m not sure.  This is a good question.  Although I follow Salesforce pretty closely and stay on top of what&#8217;s happening in the community I&#8217;m still uncertain as to Database.com&#8217;s ultimate business model and who it&#8217;s mainly geared toward.  With Database.com&#8217;s pre-built toolkits for Ruby, iOS, Android, PHP, and it&#8217;s recent acquisition of Heroku it would seem as though Salesforce is targeting web application developers in general who need a scalable database.  I could also see existing Salesforce CRM or Platform customers building Business-to-Consumer web applications that are integrated with their existing Salesforce database.  But as your active user base increases, and if you provide social and mobile aspects to your application, then your content storage, search, analysis, and computational needs are going to increase as well.  And if there&#8217;s one thing I know about Salesforce it&#8217;s that additional storage capacity gets quite expensive.</p>
<p><strong>What&#8217;s Out There for Managing Big Data?</strong><br />
This is an enormous topic and well beyond exploration in the scope of this post.  However, there are a number of technologies that have emerged in the last several years, primarily from Google and Yahoo, since internet search engines were among the first companies to encounter the challenges with big data.</p>
<p>Open Source technologies such as <a href="http://hadoop.apache.org/">Hadoop</a>, <a href="http://en.wikipedia.org/wiki/MapReduce">MapReduce</a>, and <a href="http://en.wikipedia.org/wiki/BigTable">BigTable</a> are among the core of big data management.  It essentially requires spreading out the storage and transactional computations among a distributed network of servers.  Companies like <a href="http://www.cloudera.com/">CloudEra</a> have emerged to offer services and proprietary software that help companies more easily implement and maintain these data management systems.</p>
<p>Here are some additional resources on Big Data:<br />
<span id="more-587"></span></p>
<ul>
<li><a title="SMAQ Stack" href="http://radar.oreilly.com/2010/09/the-smaq-stack-for-big-data.html" target="_blank">The SMAQ Stack</a></li>
<li><a title="BigTable: Google Research Paper" href="http://www.clintslee.com/wp-content/uploads/2011/05/bigtable-osdi06.pdf" target="_self">BigTable: Google Research Paper</a></li>
<li><a title="MapReduce: Google Research Paper" href="http://www.clintslee.com/wp-content/uploads/2011/05/mapreduce-osdi04.pdf" target="_self">MapReduce: Google Research Paper</a></li>
</ul>
<p>Here&#8217;s a great video of Robert Scoble interviewing Mike Olson, CloudEra&#8217;s CEO, on the evolution from conventional relational databases to systems more conducive to processing big data.<br />
<iframe width="560" height="349" src="http://www.youtube.com/embed/S9xnYBVqLws" frameborder="0" allowfullscreen></iframe></p>
<p><strong>Is This the Future of Data Management?</strong><br />
Things were simpler in an era when most data in enterprise databases was human-created and consisted of structured data made up of nice, neat rows and columns.  It was hard to amass gigabytes of data, much less terabytes&#8230; and petabytes?  Forget it.  But now, with the ability and desire of companies to store and analyze information from so many data-producing devices, and with the seeming necessity to create social applications in a world where mobile devices can lead to a constant stream of pictures, text, files, videos, and other content being saved and queried &#8211; finding yourself in a world of big data might soon be the new norm.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/05/28/will-database-com-handle-big-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Klout + Salesforce = Identify Your Social Influencers</title>
		<link>http://www.clintslee.com/2011/05/18/klout-salesforce-identify-your-social-influencers/</link>
		<comments>http://www.clintslee.com/2011/05/18/klout-salesforce-identify-your-social-influencers/#comments</comments>
		<pubDate>Wed, 18 May 2011 17:21:03 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Marketing]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=568</guid>
		<description><![CDATA[As these things often do, this project came about as I was searching for the solution to a problem. I couldn&#8217;t find anything that worked so I decided to try and solve it myself. The Use Case I was working with one of our clients on a Salesforce implementation and since they&#8217;re very active on [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clintslee.com/wp-content/uploads/2011/05/klout+logo.jpg"><img class="size-full wp-image-581 alignleft" style="border: 1px solid #CCCCCC;" title="Klout Logo" src="http://www.clintslee.com/wp-content/uploads/2011/05/klout+logo.jpg" alt="Klout Logo" width="300" height="98" /></a></p>
<p>As these things often do, this project came about as I was searching for the solution to a problem.  I couldn&#8217;t find anything that worked so I decided to try and solve it myself.</p>
<p><strong><br />
The Use Case</strong></p>
<p>I was working with one of our clients on a Salesforce implementation and since they&#8217;re very active on Twitter they naturally wanted to take advantage of the <a href="http://appexchange.salesforce.com/listingDetail?listingId=a0N30000003HpEQEA0">Salesforce For Twitter</a> app by ForceDotCom Labs.  We decided to incorporate a Twitter Username field into most of their web forms and after a short time they had begun to capture a large number of twitter usernames for their Leads and Contacts.  We&#8217;d also been discussing the idea of the emerging new science around measuring an individual&#8217;s social influence.  Tracking and understanding someone&#8217;s social influence has broad applications for businesses and non-profits alike.  For marketers wanting to spread information about a new product, to non-profit fundraisers wanting to disseminate information about an upcoming event, knowing who your most socially influential contacts are might be a handy piece of information to have.  But how do you track this information?</p>
<p><strong>The Solution</strong><br />
It seemed obvious to start with utilizing <a href="http://www.klout.com">Klout</a> for their influence scoring.  Klout seems to be the gold standard when it comes to social influence measuring tools.  I first looked on the AppExchange to see if there was an existing tool that connected Salesforce with Klout.  No such luck.  Next, I googled and searched my way around the Salesforce community looking for something that would accomplish the task at hand.  Hmmm&#8230;no luck again.</p>
<p>Long story short, I ended up with a tool that lets you pull Klout directly into Salesforce based on a Lead or Contact&#8217;s Twitter username.  This is available in an unmanaged package and I also submitted it to the Salesforce Code Share in case anyone wants to improve upon it.  You can view the video below for an overview and <a href="https://login.salesforce.com/?startURL=%2Fpackaging%2FinstallPackage.apexp%3Fp0%3D04tG0000000A54w">install the package here</a>.</p>
<p><strong>Demo</strong><br />
<iframe src="http://player.vimeo.com/video/23864093" width="640" height="512" frameborder="0"></iframe></p>
<p>For anyone interested in the source code, you can find it <a href="https://github.com/clintslee/Klout---Salesforce-Mashup">here on GitHub.</a></p>
<p>As always, I look forward to any feedback and comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/05/18/klout-salesforce-identify-your-social-influencers/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Got Data? A Salesforce and Rapleaf Mashup</title>
		<link>http://www.clintslee.com/2011/03/01/got-data-a-salesforce-and-rapleaf-mashup/</link>
		<comments>http://www.clintslee.com/2011/03/01/got-data-a-salesforce-and-rapleaf-mashup/#comments</comments>
		<pubDate>Tue, 01 Mar 2011 18:49:03 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Rapleaf]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=471</guid>
		<description><![CDATA[Salesforce-Rapleaf Mashup &#8211; A 4:00 Overview Any company with customers and/or prospective customers ought to know about customer segmentation.  I mean all customers (and prospective customers) are not equal, right?  Some are older, some are younger.  Some live here, some live over there.  They have different interests, backgrounds, and even purchasing histories.  Customer segmentation gives [...]]]></description>
			<content:encoded><![CDATA[<p><iframe src="http://player.vimeo.com/video/20521772?portrait=0" width="640" height="360" frameborder="0"></iframe>
<p><a href="http://vimeo.com/20521772" onclick="javascript:pageTracker._trackPageview('/outgoing/Vimeo/Rapleaf">Salesforce-Rapleaf Mashup &#8211; A 4:00 Overview</a></p>
<p>Any company with customers and/or prospective customers ought to know about customer segmentation.  I mean all customers (and prospective customers) are not equal, right?  Some are older, some are younger.  Some live here, some live over there.  They have different interests, backgrounds, and even purchasing histories.  Customer segmentation gives you the ability to tailor targeted messaging to specific channels of your business, or even to develop algorithms to predict customer retention, among numerous other benefits.  Anyone with a database of customers and prospects should be employing some level of customer segmentation.</p>
<p>This thinking should naturally lead to the questions:</p>
<ul>
<li>What information about my customers and/or prospects do I need?</li>
<li> Where do I find this data?</li>
<li>What if I only have a limited amount of information to start with?</li>
<li>How long will it take to gather this info?</li>
</ul>
<p>After thinking through these questions myself, and doing some research, I found a company named <a title="Rapleaf.com" onclick="javascript:pageTracker._trackPageview('/outgoing/Rapleaf.com');" href="http://www.rapleaf.com" target="_blank">Rapleaf</a>.  Rapleaf&#8217;s proclaimed mission is to &#8220;create a more personalized world&#8221;.  They do this by aggregating a potentially large amount of data and building a profile around email addresses.  This is unique because the only piece of information that you really need in order to access their database is an email address.  Since an email address is something that we typically have for most of our customers and prospects this service looks like it could be pretty valuable.   This led me to a few more questions such as, &#8220;What type of information can I get?&#8221;, &#8220;How much will it cost&#8221;?, &#8220;How accurate is Rapleaf&#8217;s data&#8221;?, and &#8220;How can I integrate it with Salesforce&#8221;?</p>
<p>I checked out the <a title="Rapleaf API docs" onclick="javascript:pageTracker._trackPageview('/outgoing/Rapleaf API Docs');" href="http://www.rapleaf.com/developers/api_docs/personalization/direct" target="_blank">API docs</a> to understand how to access Rapleaf&#8217;s database, and after trading a few emails  with Rapleaf&#8217;s Co-Founder <a title="Manish Shah LinkedIn Profile" onclick="javascript:pageTracker._trackPageview('/outgoing/Manish Shah Profile');" href="http://www.linkedin.com/in/mnshah" target="_blank">Manish Shah</a> I was able to get a full listing of potential data and pricing.  Setting up a free account with Rapleaf will get you an API Key and access to unlimited age, gender, and location data queries.  There are many additional fields available, and since it&#8217;s my understanding that Rapleaf is working on revising their pricing, you can just contact them and they&#8217;ll be happy to go over the cost structure with you.  </p>
<p>I searched the Salesforce community and didn&#8217;t find any existing code for integrating with Rapleaf so I decided to build something myself in Apex and share it.  There are three classes that handle the Rapleaf mashup, Rapleaf, RapleafResponse, and RapleafSetup.  I&#8217;ve also included a sample trigger for fetching Rapleaf data when a new lead is inserted.  Test classes are included, as well.  <a onclick="javascript:pageTracker._trackPageview('/downloads/Salesforce-Rapleaf');" href="http://www.clintslee.com/wp-content/uploads/2011/02/Salesforce-Rapleaf.zip">The full source code can be downloaded here</a>.  It basically works like this:</p>
<p><span id="more-471"></span></p>
<h2>Rapleaf</h2>
<table cellpadding="10">
<thead>
<tr>
<th scope="col">Method</th>
<th scope="col">Arguments</th>
<th scope="col">Return Type</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr style="background: #CCC;">
<td>searchRapleaf</td>
<td>String <em>email</em>, String <em>hash</em></td>
<td>RapleafResponse</td>
<td>This method takes an email address and returns the RapleafResponse with data.  Hash is an optional parameter used for hashing the email address for security.  Valid values are &#8216;MD5&#8242; or &#8216;SHA1&#8242;</td>
</tr>
</tbody>
</table>
<p style="border: 1px solid #CCC;">
<h2>RapleafResponse</h2>
<table cellpadding="10">
<thead>
<tr>
<th scope="col">Method</th>
<th scope="col">Arguments</th>
<th style="width: 75px;" scope="col">Return Type</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr style="background: #CCC;">
<td>getAge</td>
<td></td>
<td>String</td>
<td>Returns the Age field corresponding to the supplied email address, as received from the Rapleaf database</td>
</tr>
<tr style="background: #CCC;">
<td>getGender</td>
<td></td>
<td>String</td>
<td>Returns the Gender field corresponding to the supplied email address, as received from the Rapleaf database</td>
</tr>
<tr style="background: #CCC;">
<td>getLocation</td>
<td></td>
<td>String</td>
<td>Returns the Location field corresponding to the supplied email address, as received from the Rapleaf database</td>
</tr>
</tbody>
</table>
<p style="border: 1px solid #CCC;">
<h2>RapleafSetup</h2>
<table cellpadding="10">
<thead>
<tr>
<th scope="col">Variable Name</th>
<th scope="col">Value</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr style="background: #CCC;">
<td>API_KEY</td>
<td>String <em>your Rapleaf api key</em></td>
<td>Paste your api key.  It will be used to construct the HTTP Request.</td>
</tr>
<tr style="background: #CCC;">
<td>PERSONALIZATION_URL</td>
<td>&#8216;https://personalize.rlcdn.com/v4/dr?&#8217;</td>
<td>This is the base URL that is used to construct the endpoint for the HTTP Request.  It might be subject to change, and if it does, you&#8217;ll just need to change it here.</td>
</tr>
<tr style="background: #CCC;">
<td>FORMAT</td>
<td>&#8216;xml&#8217;</td>
<td>Defines the type of HTTPResponse that you want Rapleaf to send.  By default, Rapleaf sends a JSON response.</td>
</tr>
<tr style="background: #CCC;">
<td>METHOD</td>
<td>&#8216;GET&#8217;</td>
<td>The HTTP method used to send a request.  Currently, Rapleaf just supports the GET method.</td>
</tr>
</tbody>
</table>
<p>Below is an example of a sample trigger used to implement the Rapleaf mashup.</p>
<pre class="brush: java; title: ; notranslate">
trigger LeadTrigger on Lead (after insert)
{
	LeadManager.handleNewLeadsAfterInsert(Trigger.New);
}
</pre>
<p style="border: 1px solid #CCC;">
<pre class="brush: java; title: ; notranslate">
public class LeadManager {

	public static boolean isTest = false;
	public static String hash = null;

	/**
	 * This method handles after insert logic for leads.  Here, it creates a Set of Lead Id's from the trigger and calls the futureRapleafCall() method.
	 * @param newList   A list of leads passed in from Trigger.New.
	 */
	public static void handleNewLeadsAfterInsert(List&lt;Lead&gt; newList)
	{
		Set &lt;Id&gt; leadIds = new Set &lt;Id&gt;();
		for(Lead lead : newList)
		{
			if(lead.Email != '')
			{
				leadIds.add(lead.Id);
			}
		}
		futureRapleafCall(leadIds);
	}

	/**
	 * This is the asynchronous method that allows the program to make callouts from the trigger.  It constructs a new Rapleaf object for each lead and calls
	 * the searchRapleaf() method.  Then, it assigns values from the response to the appropriate Lead field.
	 * @param ids   A set of Ids that is passed in from the handleNewLeadsAfterInsert() method above.
	 */
	@future (callout=true)
	private static void futureRapleafCall(Set&lt;Id&gt; ids)
	{
		Map&lt;Id,Lead&gt; leadMap = new Map&lt;Id,Lead&gt;([SELECT Lead.Age__c, Lead.Gender__c, Lead.Location__c, Lead.Email, Id
								 FROM Lead
								 WHERE Id
								 IN :ids]);
		for(Id id : ids)
		{
			Lead lead = leadMap.get(id);
			try
			{
				Rapleaf rap = new Rapleaf();
				// System.debug('MADE A NEW RAPLEAF OBJECT');
				// System.debug('TEST: ' + isTest);
				if(isTest) rap.isTest = true;
				// System.debug('RAP TEST: ' + rap.isTest);
				RapleafResponse resp = rap.searchRapleaf(lead.email, hash);
				// System.debug('RAPLEAFRESPONSE: ' + resp);
				lead.Age__c = resp.getAge();
				// System.debug('LEAD AGE: ' + lead.Age__c);
				lead.Location__c = resp.getLocation();
				lead.Gender__c = resp.getGender();
			}
				catch(RapleafResponse.RapleafException e)
				{
					System.debug('ERROR: ' + e);
				}
		}

		update leadMap.values();
	}

	public static void handleNewLeadsTest(List&lt;Lead&gt; testList)
	{
		isTest = true;
		handleNewLeadsAfterInsert(testList);
	}
}
</pre>
<p>As always, I look forward to any feedback, thoughts, and/or suggestions.  If you&#8217;re using a similar service to collect this type of data I&#8217;d love to hear about that, too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/03/01/got-data-a-salesforce-and-rapleaf-mashup/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>It&#8217;s 2011- Time to Get Balanced</title>
		<link>http://www.clintslee.com/2011/02/17/its-2011-time-to-get-balanced/</link>
		<comments>http://www.clintslee.com/2011/02/17/its-2011-time-to-get-balanced/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 14:02:56 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Personal Development]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=461</guid>
		<description><![CDATA[For some reason, I felt compelled to share this TED video.  Perhaps it&#8217;s because I&#8217;m a new father and the &#8216;life&#8217; part of work-life balance has been taken to a whole new level.  Maybe it&#8217;s because today is Thursday which means that tomorrow I&#8217;ll see a slurry of TGIF status updates on Facebook.  This kind [...]]]></description>
			<content:encoded><![CDATA[<p>For some reason, I felt compelled to share this TED video.  Perhaps it&#8217;s because I&#8217;m a new father and the &#8216;life&#8217; part of work-life balance has been taken to a whole new level.  Maybe it&#8217;s because today is Thursday which means that tomorrow I&#8217;ll see a slurry of TGIF status updates on Facebook.  This kind of saddens me as it seems like there&#8217;s this prevalent mindset which is to spend five days a week doing something you dislike in order to pay for the two days of doing what you enjoy.  That doesn&#8217;t seem very balanced.  Balance doesn&#8217;t have to mean drastic changes, however.  It can be as easy as simply paying attention to the little things.  Just watch this video, it&#8217;s entertaining (and, hey, there&#8217;s a moral).</p>
<p><!--copy and paste--><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="446" height="326" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="wmode" value="transparent" /><param name="bgColor" value="#ffffff" /><param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/NigelMarsh_2010X-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/NigelMarsh-2010X.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=1069&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=nigel_marsh_how_to_make_work_life_balance_work;year=2010;theme=what_makes_us_happy;theme=a_taste_of_tedx;theme=new_on_ted_com;event=TEDxSydney;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /><param name="src" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" /><param name="bgcolor" value="#ffffff" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="446" height="326" src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" flashvars="vu=http://video.ted.com/talks/dynamic/NigelMarsh_2010X-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/NigelMarsh-2010X.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=1069&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=nigel_marsh_how_to_make_work_life_balance_work;year=2010;theme=what_makes_us_happy;theme=a_taste_of_tedx;theme=new_on_ted_com;event=TEDxSydney;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" bgcolor="#ffffff" wmode="transparent" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/02/17/its-2011-time-to-get-balanced/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Salesforce IRC – All the Cool Kids Are Doing It</title>
		<link>http://www.clintslee.com/2011/02/08/salesforce-irc-all-the-cool-kids-are-doing-it/</link>
		<comments>http://www.clintslee.com/2011/02/08/salesforce-irc-all-the-cool-kids-are-doing-it/#comments</comments>
		<pubDate>Tue, 08 Feb 2011 16:28:44 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[IRC]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=446</guid>
		<description><![CDATA[If you&#8217;re ever feeling a bit nostalgic about the mid-90&#8242;s I&#8217;ve got the cure for you.  Go jump on the Salesforce IRC channel.  Despite reminiscing about your teenage days sitting in your parents&#8217; basement, tying up the phone line, and chatting online with babes (not that I did that), you might just learn a little [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clintslee.com/wp-content/uploads/2011/02/aol.png"><img class="size-full wp-image-448 alignleft" title="AOL CD" src="http://www.clintslee.com/wp-content/uploads/2011/02/aol.png" alt="" width="220" height="222" /></a>If you&#8217;re ever feeling a bit nostalgic about the mid-90&#8242;s I&#8217;ve got the cure for you.  Go jump on the Salesforce IRC channel.  Despite reminiscing about your teenage days sitting in your parents&#8217; basement, tying up the phone line, and chatting online with babes (not that I did that), you might just learn a little something.</p>
<p><a href="http://www.twitter.com/metadaddy" target="_blank">Pat Patterson</a> (aka metadaddy) did a <a href="http://bit.ly/fVm0ak" target="_blank">how-to post</a> on the Developer Force blog to get you going in case you don&#8217;t remember how to access an IRC channel.  I use an IRC client for the Mac called Colloquy.</p>
<p>There&#8217;s usually a good-sized crowd on the chat including some notable figures in the Salesforce community like <a href="http://www.twitter.com/apexsutherland" target="_blank">@apexsutherland</a>, <a href="http://www.twitter.com/reidcarlberg" target="_blank">@reidcarlberg</a>, <a href="http://www.twitter.com/metadaddy" target="_blank">@metadaddy</a>, <a href="http://www.twitter.com/vnehess" target="_blank">@vnehess</a>, <a href="http://www.twitter.com/gokubi" target="_blank">@gokubi</a>, <a href="http://www.twitter.com/colinloretz" target="_blank">@colinloretz</a>, <a href="http://www.twitter.com/fractastical" target="_blank">@fractastical</a>, and a lot of other very smart folks who use Salesforce.  Whether you&#8217;re stuck on a particular development problem and need help, or you&#8217;re wanting to contribute, or you just want to see who&#8217;s doing what with Salesforce &#8211; this is a great place to start.  You&#8217;re <span style="text-decoration: line-through;">always</span> usually in for some lively discussion.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/02/08/salesforce-irc-all-the-cool-kids-are-doing-it/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Salesforce + Twilio + Receiving Incoming Texts</title>
		<link>http://www.clintslee.com/2011/02/08/salesforce-twilio-receiving-incoming-texts/</link>
		<comments>http://www.clintslee.com/2011/02/08/salesforce-twilio-receiving-incoming-texts/#comments</comments>
		<pubDate>Tue, 08 Feb 2011 06:15:02 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apex]]></category>
		<category><![CDATA[Sites]]></category>
		<category><![CDATA[Visualforce]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=413</guid>
		<description><![CDATA[Recently, I've been toying with mashing up Salesforce and Twilio's SMS capabilities.  For those of you who don't know what Twilio is, you should check it out.  Twilio is a web service that gives you the ability to integrate voice and SMS into your apps and they have a simple API and documentation.  This is a pretty handy service and there are a lot of use case scenarios where this functionality makes sense.  For example:

Text-based marketing to leads/contacts.
Notification of certain events to sales reps or field personnel.
A text-based web service that runs on Force.com.]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been toying with mashing up Salesforce and Twilio&#8217;s SMS capabilities.  For those of you who don&#8217;t know what <a title="Twilio" href="http://www.twilio.com" target="_blank">Twilio</a> is, you should check it out.  Twilio is a web service that gives you the ability to integrate voice and SMS into your apps and they have a simple API and documentation.  This is a pretty handy service and there are a lot of use case scenarios where this functionality makes sense.  For example:</p>
<ul>
<li>Text-based marketing to leads/contacts.</li>
<li>Notification of certain events to sales reps or field personnel.</li>
<li>A text-based web service that runs on Force.com.</li>
</ul>
<p><a href="http://twitter.com/kylemroche" target="_blank">Kyle Roche</a> and <a href="http://twitter.com/aslambari" target="_blank">Aslam Bari</a> put together a great library to help developers use Twilio with the Force.com platform.  You can find it <a href="http://developer.force.com/codeshare/projectpage?id=a06300000059aEWAAY" target="_blank">here</a> on the Force.com Code Share.</p>
<p>The best way to get started is to create a free Twilio trial account so you can get your API credentials and sandbox info.  The API for sending texts is <a href="http://www.twilio.com/docs/api/2010-04-01/rest/sms">here</a>, and with Kyle and Aslam&#8217;s library it is really simple to start sending texts from your Salesforce account.</p>
<p>It basically works like this.</p>
<p><a href="http://www.clintslee.com/wp-content/uploads/2011/02/diagram.png"><img class="aligncenter size-full wp-image-432" title="Twilio Diagram" src="http://www.clintslee.com/wp-content/uploads/2011/02/diagram.png" alt="" width="600" height="238" /></a></p>
<p>If you&#8217;re already using Twilio to send SMS, have you set up a way to process an incoming message?  Perhaps you&#8217;re sending info to  prospects and you want them to reply &#8220;Yes&#8221; if they&#8217;re interested.   Then, you want to trigger some workflow from that incoming text.  Well,  Twilio will accept incoming texts and you can configure where you want the SMS info to be sent.  Basically, Twilio receives incoming SMS messages and then sends an HTTP request to you with a number of parameters.  Three of the most important parameters are From (the number of the message sender), To (your Twilio number), and Body (the contents of the message).  Here is the <a href="http://www.twilio.com/docs/api/2010-04-01/twiml/sms/twilio_request" target="_blank">documentation</a> for how Twilio handles incoming texts.</p>
<p>In order to process these incoming SMS messages you first need an Apex Controller and Visualforce page.  The request will get sent to this page and the parameters will be stored.  Using the stored parameters we&#8217;ll create a closed task and associate it with the appropriate Contact.   The code for the Controller and VF page are below.</p>
<p><span id="more-413"></span></p>
<pre class="brush: java; title: ; notranslate">
/*********************************************************************************
This controller will grab the three parameters From, To, and Body when the Twilio
HTTP request is made.  Once we have the From number (which is the sender's number)
we can use it to query Salesforce for a Contact matching that (presumably) mobile
number.  When we've found a matching Contact we create a closed Task to record the
message of the incoming text, and it will now show up under the Activity History
related list for this Contact
*********************************************************************************/
public with sharing class TwilioRequestControllerContacts {

	// Set instance variables to capture the To, From, and Body Parameters that Twilio sends in the HTTP request
	public String fromNumber = ApexPages.currentPage().getParameters().get('From');
	public String toNumber = ApexPages.currentPage().getParameters().get('To');
	public String body = ApexPages.currentPage().getParameters().get('Body');
	public PageReference response = new PageReference('http://your_site_url/TwilioResponse');

	// This is the initial method that gets called when the TwilioResponse page loads
	public PageReference init()
	{
		// Helpful with debugging
		System.debug('FROM: ' + fromNumber);
		System.debug('TO: ' + toNumber);
		System.debug('BODY: ' + body);

		// If we capture all of the parameters successfully, call the saveIncomingText() method
		if(fromNumber != null &amp;&amp; toNumber != null &amp;&amp; body != null)
		{
			response = saveIncomingText();
			return response;
		}

		return null;
	}

	private PageReference saveIncomingText()
	{
		// Call the method to clean the incoming phone number
		String cleanFromNumber = formatPhone(fromNumber);

		// Query the student whose phone number matches the incoming phone number
		List &lt;Contact&gt; contactList = [SELECT Id, FirstName, LastName
									     FROM Contact
									     WHERE MobilePhone =: cleanFromNumber limit 1];

		// Move forward only if we find at least one match.
		if(contactList.size() &gt; 0)
		{
	    	for (Contact contact : contactList)
	    	{
				System.debug(contact.FirstName + ' ' + contact.LastName);

				// Create a new Task to store the record of the incoming text, then attach it to the appropriate Contact
	    		Task text = new Task();
	    		text.Subject = body;
	    		text.WhoId = contact.Id;
	    		text.Status = 'Completed';
	    		text.Type = 'Incoming Text';

	    	    // Insert the Incoming Text object and return the response page.
	    	    try
	    		{
	    		   insert text;
	    		   return response;
	    		}
	    		catch(DmlException e)
	    		{
	    		  System.debug('INSERT TASK FAILED: ' + e);
	    		}
	    	}
		}

	    return response;
	}

	// Twilio sends the phone number as +15555551234.  We have to reformat the string to (555) 555-1234
	private String formatPhone(String fromNumber)
	{
		String areaCode = fromNumber.substring(2,5);
		String prefix = fromNumber.substring(5,8);
		String last4 = fromNumber.substring(8);
		String formattedPhone = '(' + areaCode +')' + ' ' + prefix + '-' + last4;
		System.debug('FORMATTED PHONE IS: ' + formattedPhone);
		return formattedPhone;
	}
}
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;!--Visualforce Page--&gt;
&lt;!--This is a simple page that calls the init method when it loads--&gt;
&lt;apex:page controller=&quot;TwilioRequestControllerContacts&quot; action=&quot;{!init}&quot; showHeader=&quot;false&quot; sidebar=&quot;false&quot;&gt;
   &lt;apex:pageBlock title=&quot;Twilio Request Listener&quot;&gt;&lt;/apex:pageBlock&gt;
&lt;/apex:page&gt;
</pre>
<p>The next step is to give your Site access to this page and controller.  If you&#8217;ve not worked with <a href="http://wiki.developerforce.com/index.php/An_Introduction_to_Force.com_Sites" target="_blank">Salesforce Sites</a> it is pretty simple to set one up.  Utilizing Sites is how we can expose our Visualforce page to the outside world, thus letting the Twilio HTTP request hit our page.  You should also make sure that your Public Access Settings on the Site give at least read access to the Contact object.</p>
<p>The last step is to tell Twilio where to send the request.  Log in to your Twilio account and click &#8216;My Account&#8217;.  Under the heading Developer Tools you&#8217;ll see a field titled SMS URL.  Paste the full URL path to your Visualforce page into that field.</p>
<p style="text-align: left;"><a href="http://www.clintslee.com/wp-content/uploads/2011/02/twilioshot1.png"><img class="aligncenter size-full wp-image-434" title="Twilio Diagram" src="http://www.clintslee.com/wp-content/uploads/2011/02/twilioshot1.png" alt="" width="496" height="454" /></a>As always, any feedback or questions are welcome.  If you&#8217;ve implemented a different solution to handle this issue I&#8217;d love to hear about it, too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2011/02/08/salesforce-twilio-receiving-incoming-texts/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Trigga What? A Simple Non-Profit Trigger Example</title>
		<link>http://www.clintslee.com/2010/10/09/trigga-what-a-simple-non-profit-trigger-example/</link>
		<comments>http://www.clintslee.com/2010/10/09/trigga-what-a-simple-non-profit-trigger-example/#comments</comments>
		<pubDate>Sun, 10 Oct 2010 02:58:41 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apex]]></category>
		<category><![CDATA[Non-Profit]]></category>
		<category><![CDATA[Trigger]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=395</guid>
		<description><![CDATA[I do some consulting work for non-profit organizations that use Salesforce.com.  There are so many non-profits that use Salesforce but many often lack the internal resources necessary to truly realize the benefits of adopting it.  It is highly rewarding work and I would encourage you to check out the Salesforce Foundation as one way of [...]]]></description>
			<content:encoded><![CDATA[<p>I do some consulting work for non-profit organizations that use Salesforce.com.  There are so many non-profits that use Salesforce but many often lack the internal resources necessary to truly realize the benefits of adopting it.  It is highly rewarding work and I would encourage you to check out the <a title="Salesforce Foundation" href="http://www.salesforcefoundation.org" target="_self">Salesforce Foundation</a> as one way of getting involved with non-profits who use Salesforce.</p>
<p>The Salesforce Foundation has a very successful program that gives non-profits the ability to get 10 donated (free) Enterprise Edition user licenses. This is a great program that offers a huge benefit to non-profits.  If you&#8217;re a non-profit you can learn more about how to apply for your licenses <a title="Salesforce Foundation - Apply" href="http://www.salesforcefoundation.org/products/donation" target="_self">here</a>.  If you have experience in configuring, customizing, administering, consulting, and/or developing on the Force.com platform you can get involved by emailing <a href="emailto:foundation@salesforce.com">f</a><a href="mailto:foundation@salesforce.com">oundation@salesforce.com</a> and letting them know you&#8217;re interested in volunteering your time and expertise.  This is a great first step towards getting involved.</p>
<p>With that being said I&#8217;d like to share a specific real world example for an Apex Trigger that might be helpful.</p>
<p><strong>Use Case</strong></p>
<p>Here&#8217;s the scenario.</p>
<p><span id="more-395"></span></p>
<p>We use Linvio&#8217;s PaymentConnect app to process online donations that come through our website.  When someone pays online via a credit card a Payment object record is created.  Payment is a custom object included in the PaymentConnect package.  The Payment record captures information about the transaction including credit card info, payment gateway, donation amount, etc.  It also captures the name, email, and contact info of the donor who initiates the transaction.  With this contact info a Contact record is either created (if no match is found) or the Payment is related to an existing Contact (if a match is found).</p>
<p>The challenge we faced is that we track donations through Opportunities.  While the Payment record does capture the amount of the donation and relates it to a Contact, we really wanted an Opportunity to be created that reflects each payment because that is how we report on donation income, do forecasting, etc.  We also wanted to relate the Contact to this Opportunity through a Contact Role.</p>
<p>One option could have been to create a workflow rule,that fires everytime a payment is successfully processed, and sets a Task for someone to manually create a new opportunity and relate it to the Contact.  But we wanted to automate this process as much as possible so we decided to write a trigger.</p>
<p>Below is the code for the trigger and the Apex Class that handles it.  Keep in mind that we are using the NonProfitForce configuration.  You can read more about <a title="NonProfitForce" href="http://wiki.developerforce.com/index.php/Nonprofit_Starter_Pack#Functionality" target="_blank">NonProfitForce here</a>.</p>
<p>The main point of the trigger is to create a Closed Opportunity (Donation) each time a successful Payment is processed.  Then, the corresponding Contact is related to the Opportunity through an OpportunityContactRole.  This trigger is bulkified to handle multiple Payments without easily tripping governor limits.  Read up on trigger governor limits <a title="Trigger Governor Limits" href="http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_triggers.htm" target="_blank">here</a>.</p>
<p>I&#8217;d also highly recommend considering <a title="Linvio PaymentConnect Application" href="http://sites.force.com/appexchange/listingDetail?listingId=a0N300000016cbMEAQ" target="_blank">Linvio&#8217;s PaymentConnect</a> app for your ecommerce and payment processing needs.  Ron Wild and his team are highly competent and helpful.</p>
<p><strong>Trigger</strong></p>
<pre class="brush: java; title: ; notranslate">

trigger NewDonationAfterPayment on pymt__PaymentX__c (after insert) {
 PaymentManager.handleNewPayment(Trigger.New);
}
</pre>
<p><strong>Apex Class</strong></p>
<pre class="brush: java; title: ; notranslate">
public with sharing class PaymentManager {

 public Class PaymentManagerException extends Exception {}

 public static void handleNewPayment(List &lt;pymt__PaymentX__c&gt; newPayments) {
 List &lt;pymt__PaymentX__c&gt; completedPayments = new List &lt;pymt__PaymentX__c&gt;();
 List &lt;Opportunity&gt; donationList = new List &lt;Opportunity&gt;();
 List &lt;OpportunityContactRole&gt; ocrList = new List &lt;OpportunityContactRole&gt;();

 // Loop through all new Payment objects in the trigger and add the ones with a 'Completed' status and Type of 'Payment'.
 for (pymt__PaymentX__c payment : newPayments) {
 if (payment.pymt__Status__c == 'Completed' &amp;&amp; payment.pymt__Transaction_Type__c =='Payment') {
 completedPayments.add(payment);
 }
 } //close for-loop

 // If there are new Payments that fit our criteria above then move forward.
 if (completedPayments.size() &gt; 0) {

 // Loop through the Payments that fit our criteria and create a new Opportunity that mirrors certain information from the Payment.
 for (pymt__PaymentX__c p : completedPayments) {
 Opportunity donation = new Opportunity();
 donation.Name = p.Name + ' - ' + p.pymt__Amount__c;
 donation.CloseDate = date.Today();
 donation.StageName = 'Posted';
 donation.Amount = p.pymt__Amount__c;
 donationList.add(donation);
 }

 // Insert these new Opportunities (called Donations in NonProfitForce)
 try {
 insert donationList;
 } catch (Dmlexception e) {
 System.debug('donationList not inserted: ' + e);
 }

 // Create two new Lists that will be used to relate the new Opportunities to the Payments in the trigger.
 // Select all the opportunities that we just created and order them by Name.  Then select all the Payments that fit our criteria from the trigger
 // and order them by Name.  Theoretically, these lists should be the same size and follow the same order since the Names mirror each other..
 List &lt;Opportunity&gt; oppList = new List &lt;Opportunity&gt;([Select Id, Name FROM Opportunity WHERE Id IN :donationList ORDER BY Name]);
 List &lt;pymt__PaymentX__c&gt; pymtList = new List &lt;pymt__PaymentX__c&gt; ([Select Id, Name FROM pymt__PaymentX__c WHERE Id IN :completedPayments ORDER BY Name]);

 //  This loop will assign the opportunity id to the Payment object.
 for (Integer i=0; i &lt; pymtList.size(); i++) {
 pymtList[i].pymt__Opportunity__c = oppList[i].Id;
 }

 // Update the list of Payments from above, this should save the Opportunity Id that we just added.
 try {
 update pymtList;
 } catch (Dmlexception e) {
 System.debug('pymtList not inserted: ' + e);
 }

 // Create a new list of Payment objects so we can relate the Contacts to the Opportunities that we just created.
 //Since the Payment object is related to both the Contact and Opportunity we can query those Id's directly from the Payment object.
 List &lt;pymt__PaymentX__c&gt; listForContRole = new List &lt;pymt__PaymentX__c&gt; ([Select Id, pymt__Contact__r.Id, pymt__Opportunity__r.Id FROM pymt__PaymentX__c WHERE ID IN :completedPayments]);
 List &lt;OpportunityContactRole&gt; contRoles = new List&lt;OpportunityContactRole&gt;();

 // Loop through this new list of Payment objects.  Create a new OpportunityContactRole and using the Opp and Contact Id's from the Payment object.
 for (pymt__PaymentX__C p : listForContRole) {
 OpportunityContactRole ocr = new OpportunityContactRole();
 ocr.ContactId = p.pymt__Contact__r.Id;
 ocr.OpportunityId = p.pymt__Opportunity__r.Id;
 contRoles.add(ocr);
 }

 // Insert this new list of OpportunityContactRoles
 try {
 insert contRoles;
 } catch (DmlException e) {
 System.debug('ocrList not inserted: ' + e);
 }

 } //close if-statement

 } //close handleNewPayment method

} //close PaymentManager Class
</pre>
<p>I hope this is helpful, and as always look forward to your feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2010/10/09/trigga-what-a-simple-non-profit-trigger-example/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How Do You Eat An Elephant?</title>
		<link>http://www.clintslee.com/2010/09/11/how-do-you-eat-an-elephant/</link>
		<comments>http://www.clintslee.com/2010/09/11/how-do-you-eat-an-elephant/#comments</comments>
		<pubDate>Sat, 11 Sep 2010 04:28:25 +0000</pubDate>
		<dc:creator>Clint Lee</dc:creator>
				<category><![CDATA[Business Management]]></category>
		<category><![CDATA[Salesforce Consulting]]></category>

		<guid isPermaLink="false">http://www.clintslee.com/?p=336</guid>
		<description><![CDATA[First Of All, Why Would You Eat An Elephant? As my friend and partner Bryan O&#8217;Rourke once said to me, &#8220;How do you eat an elephant? I replied very intelligently, &#8220;Hmm&#8230;I don&#8217;t know.&#8221; &#8220;One bite at a time&#8221;, he said. &#8220;Oh&#8221;, I said, all the while thinking &#8216;Why the hell would I want to eat [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clintslee.com/wp-content/uploads/2010/08/elephant1.jpg"><img class="size-full wp-image-381 alignleft" style="border: 5px solid #cccccc;" title="Eating an Elephant One Bite At a Time" src="http://www.clintslee.com/wp-content/uploads/2010/08/elephant1.jpg" alt="Elephant" width="269" height="242" /></a></p>
<h3 style="text-align: left;"><strong>First Of All, Why Would You Eat An Elephant?</strong></h3>
<p style="text-align: left;">As my friend and partner <a href="http://www.bryankorourke.com">Bryan O&#8217;Rourke</a> once said to me, &#8220;How do you eat an elephant?</p>
<p style="text-align: left;">I replied very intelligently, &#8220;Hmm&#8230;I don&#8217;t know.&#8221;</p>
<p style="text-align: left;">&#8220;One bite at a time&#8221;, he said.</p>
<p style="text-align: left;">&#8220;Oh&#8221;, I said, all the while thinking &#8216;Why the hell would I want to eat an elephant?&#8217;.</p>
<p style="text-align: left;">
<h3 style="text-align: left;"><strong>Of Elephants &amp; CRM Implementations</strong></h3>
<p style="text-align: left;">Surprisingly, there may really be benefits to learning how to eat an elephant&#8230;</p>
<p style="text-align: left;">CRM implementation projects can be like elephants &#8211; large, hairy, and complex.  Developing an initial strategy for how to best complete a successful implementation can be a daunting and overwhelming  task when the project is viewed as a singular unit.  This is where knowing how to eat elephants comes in handy.  Learn to break down the project into bite-sized chunks.  More importantly, if you&#8217;re in an outside consulting role, be sure to communicate this strategy to your clients.  In previous posts I&#8217;ve talked about <a href="http://www.clintslee.com/2010/07/03/salesforce-implementation-success-tip-1/" target="_self">working with the client&#8217;s internal project manager</a> on the implementation; it&#8217;s highly effective when you communicate this elephant-eating strategy to him or her.  The reason is that taking on the task of implementing a new system like this not only involves a lot of work in process design and technical effort, but there is a great deal of change management that needs to occur which is often a source of frustration for a company&#8217;s leadership.  Therefore, using a chunking strategy can create quick wins and help foster more rapid adoption.</p>
<h3 style="text-align: left;"><strong>What is Chunking?</strong></h3>
<p><strong><span id="more-336"></span><br />
</strong></p>
<p>One definition of <a href="http://en.wikipedia.org/wiki/Chunking_%28psychology%29" target="_blank">Chunking </a>is, &#8220;to organize items into familiar manageable units&#8221;.  Psychologists have coined the term &#8220;chunking&#8221; in reference to studying cognitive learning and memorization in humans, and it&#8217;s actually quite interesting &#8211; but in this case I&#8217;m simply referring to breaking something large into two or more smaller, more manageable pieces.</p>
<p>Let&#8217;s say you were tasked with giving a 30-minute speech.  If you used a chunking strategy you might first break your speech into 3 equal 10-minute topics.  Then, you&#8217;d take those 3 topics and break them into 3 equal 3-minute and 20-second sections.  For example, a speech on dead presidents may look like the outline below.</p>
<p>George Washington &#8211; 10 minutes</p>
<ol>
<li>Childhood &#8211; 3:20</li>
<li>Presidency &#8211; 3:20</li>
<li>Post-Presidency &#8211; 3:20</li>
</ol>
<p>Thomas Jefferson &#8211; 10 minutes</p>
<ol>
<li>Childhood &#8211; 3:20</li>
<li>Presidency &#8211; 3:20</li>
<li>Post-Presidency &#8211; 3:20</li>
</ol>
<p>John F. Kennedy &#8211; 10 minutes</p>
<ol>
<li>Childhood &#8211; 3:20</li>
<li>Presidency &#8211; 3:20</li>
<li>Post-Presidency &#8211; 3:20</li>
</ol>
<p>Having nine very succinct sections makes it much easier to begin preparing information and practicing the speech.  Chunking is all about breaking something large into bite-sized, more manageable pieces.</p>
<p>A great tool that I came across recently is called <a href="http://www.xmind.net">XMind</a>.  This is an open source software program that is great for anyone in project management because it gives you a way to visually chunk your projects.  You can map out your projects in whatever way makes sense &#8211; by function, by team, by task, chronologically.  Having a visual depiction is an excellent way to communicate with clients and co-workers.</p>
<p>I&#8217;ll be curious to see if anybody actually tries to map out how to eat an elephant.</p>
<p style="text-align: left;">
<p style="text-align: left;">
<p style="text-align: left;">
<p style="text-align: left;">
<p style="text-align: justify;">
<p style="text-align: justify;">
]]></content:encoded>
			<wfw:commentRss>http://www.clintslee.com/2010/09/11/how-do-you-eat-an-elephant/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

