<?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>Jeff Douglas - Technology, Coding and Bears... OH MY! &#187; Technology</title>
	<atom:link href="http://blog.jeffdouglas.com/category/technology/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jeffdouglas.com</link>
	<description>Get your head out of your #@! and into the clouds!</description>
	<lastBuildDate>Thu, 02 Feb 2012 11:57:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Dependency Management with Play!</title>
		<link>http://blog.jeffdouglas.com/2011/10/25/dependency-management-with-play/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=dependency-management-with-play</link>
		<comments>http://blog.jeffdouglas.com/2011/10/25/dependency-management-with-play/#comments</comments>
		<pubDate>Tue, 25 Oct 2011 11:43:39 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Play!]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4243</guid>
		<description><![CDATA[Play! has dependency management baked into it. This allows you to express your application’s external dependencies in a single dependencies.yml file. So if your app requires commons-lang or log4j, you can list them in your depencies.yml file and Play! will download them for you and place them in your lib directory. So I&#8217;m making changes [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F10%2F25%2Fdependency-management-with-play%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F10%2F25%2Fdependency-management-with-play%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Play! has <a href="http://www.playframework.org/documentation/1.2.3/dependency">dependency management baked into it</a>. This allows you to express your application’s external dependencies in a single dependencies.yml file. So if your app requires commons-lang or log4j, you can list them in your depencies.yml file and Play! will download them for you and place them in your lib directory.</p>
<p>So I&#8217;m making changes to my <a href="http://blog.jeffdouglas.com/2011/09/26/telesales-play/">Play! demo app for salesforce.com</a> and am trying to specify the <a href="http://code.google.com/p/sfdc-wsc/">Force.com Web Service Connector (WSC)</a> in my dependencies.yml file. However, I think that I&#8217;m not referencing them correctly as the module is not being found in mavenscentral and downloaded. I&#8217;ve tried different combinations with the artifactId and groupId but nothing seems to work. Here&#8217;s my dependencies.yml:</p>
<pre>
require:
    - play
    - force-wsc -> force-wsc
&nbsp;
</pre>
<p>When I run <em>play dependencies &#8211;verbose</em> in Terminal I get the following:</p>
<pre>
:::: WARNINGS
module not found: force-wsc#force-wsc;->
==== mavenCentral: tried

http://repo1.maven.org/maven2/force-wsc/force-wsc/->/force-wsc-->.pom

-- artifact force-wsc#force-wsc;->!force-wsc.jar:

http://repo1.maven.org/maven2/force-wsc/force-wsc/->/force-wsc-->.jar

::::::::::::::::::::::::::::::::::::::::::::::
::          UNRESOLVED DEPENDENCIES         ::
::::::::::::::::::::::::::::::::::::::::::::::
:: force-wsc#force-wsc;->: not found
::::::::::::::::::::::::::::::::::::::::::::::
</pre>
<p>Any help with this issue would be greatly appreciated!</p>
<p><font color="red"><b>Update!!</b></font></p>
<p>I worked with <a href="http://twitter.com/jesperfj">@jesperfj</a> this morning and he pointed me in the right direction. I needed to include the groupId and version as well. The correct syntax looks like:</p>
<pre>
require:
    - play
    - com.force.api -> force-wsc 22.0.0
&nbsp;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/10/25/dependency-management-with-play/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I&#8217;m Addicted to Play! on Heroku</title>
		<link>http://blog.jeffdouglas.com/2011/10/25/im-addicted-to-play-on-heroku/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=im-addicted-to-play-on-heroku</link>
		<comments>http://blog.jeffdouglas.com/2011/10/25/im-addicted-to-play-on-heroku/#comments</comments>
		<pubDate>Tue, 25 Oct 2011 11:19:53 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Heroku]]></category>
		<category><![CDATA[Play!]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4227</guid>
		<description><![CDATA[I&#8217;ve been using Play! since Dreamforce 11 when Heroku announced support for it and I have to say that I&#8217;m addicted to it. If you love Java (and who doesn&#8217;t) but hate developing Java applications with all of the crap that goes along with it (Maven, XML config files, deployments, etc.) then the Play! framework [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F10%2F25%2Fim-addicted-to-play-on-heroku%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F10%2F25%2Fim-addicted-to-play-on-heroku%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>I&#8217;ve been using <a href="http://www.playframework.org/">Play!</a> since Dreamforce 11 when <a href="http://blog.heroku.com/archives/2011/8/29/play/">Heroku announced support for it</a> and I have to say that I&#8217;m addicted to it. If you love Java (and who doesn&#8217;t) but hate developing Java applications with all of the crap that goes along with it (Maven, XML config files, deployments, etc.) then the Play! framework my just be your savior.</p>
<p>I did a <a href="http://blog.jeffdouglas.com/2011/09/26/telesales-play/">small demo</a> with salesforce.com integration with Heroku and Play! if you would like some <a href="https://github.com/jeffdonthemic/Telesales-Play">sample code</a> or to <a href="http://telesales-play.herokuapp.com/">run it</a> for yourself.</p>
<p>Here&#8217;s what I like the most about Play!: it makes me productive. The development style is similar to Rails and I can simply get stuff done. I don&#8217;t have to save my Java code, restart Tomcat, wait for Hibernate to fire up and then see if my code runs as expected. With Play! I make my modifications, hit refresh in the browser and presto! my new app is either up and running or there is a nice, pretty error message. </p>
<p>Running Play! is a breeze. The framework comes bundled with <a href="http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty">Jetty</a> so I don&#8217;t have to install and maintain Tomcat locally and when I&#8217;m ready to put the app into production, I just push it to Heroku and they take care of the rest.</p>
<p>If you want a great intro to Play! and why you might to use it, check out the first 10 minutes of this video from Dreamforce 11, &#8220;Introducing Play! Framework: Painless Java and Scala Web Applications&#8221;. The reset of the preso gets into actually building an app so if you want to see some code, feel free to continue watching.</p>
<p><span class="youtube">
<object width="480" height="385">
<param name="movie" value="http://www.youtube.com/v/kAjERGwhmog?color1=d6d6d6&amp;color2=f0f0f0&amp;border=0&amp;fs=1&amp;hl=en&amp;loop=0&amp;showinfo=0&amp;iv_load_policy=3&amp;showsearch=0&amp;rel=1" />
<param name="allowFullScreen" value="true" />
<embed wmode="opaque" src="http://www.youtube.com/v/kAjERGwhmog?color1=d6d6d6&amp;color2=f0f0f0&amp;border=0&amp;fs=1&amp;hl=en&amp;loop=0&amp;showinfo=0&amp;iv_load_policy=3&amp;showsearch=0&amp;rel=1" type="application/x-shockwave-flash" allowfullscreen="true" width="480" height="385"></embed>
<param name="wmode" value="opaque" />
</object>
</span><p><a href="http://www.youtube.com/watch?v=kAjERGwhmog">www.youtube.com/watch?v=kAjERGwhmog</a></p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/10/25/im-addicted-to-play-on-heroku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Video &#8211; Debugging Apex Tools and Techniques (DF11)</title>
		<link>http://blog.jeffdouglas.com/2011/10/24/debugging-apex-tools-and-techniques/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=debugging-apex-tools-and-techniques</link>
		<comments>http://blog.jeffdouglas.com/2011/10/24/debugging-apex-tools-and-techniques/#comments</comments>
		<pubDate>Mon, 24 Oct 2011 12:00:43 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Apex]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4221</guid>
		<description><![CDATA[The new System Log (aka Apex CSI) is a cool new part of Winter 12 that significantly reduces the pain of debugging Force.com applications. This is a great video from Dreamforce 11 showing you how to use the new console to debug code, set &#8220;breakpoints&#8221; and examine heap variables and more. www.youtube.com/watch?v=Hl2cY7eW2Ko]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F10%2F24%2Fdebugging-apex-tools-and-techniques%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F10%2F24%2Fdebugging-apex-tools-and-techniques%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>The new System Log (aka Apex CSI) is a cool new part of Winter 12 that significantly reduces the pain of debugging Force.com applications. This is a great video from Dreamforce 11 showing you how to use the new console to debug code, set &#8220;breakpoints&#8221; and examine heap variables and more. </p>
<p><span class="youtube">
<object width="560" height="340">
<param name="movie" value="http://www.youtube.com/v/Hl2cY7eW2Ko?color1=d6d6d6&amp;color2=f0f0f0&amp;border=0&amp;fs=1&amp;hl=en&amp;loop=0&amp;showinfo=0&amp;iv_load_policy=3&amp;showsearch=0&amp;rel=1&amp;hd=1" />
<param name="allowFullScreen" value="true" />
<embed wmode="opaque" src="http://www.youtube.com/v/Hl2cY7eW2Ko?color1=d6d6d6&amp;color2=f0f0f0&amp;border=0&amp;fs=1&amp;hl=en&amp;loop=0&amp;showinfo=0&amp;iv_load_policy=3&amp;showsearch=0&amp;rel=1&amp;hd=1" type="application/x-shockwave-flash" allowfullscreen="true" width="560" height="340"></embed>
<param name="wmode" value="opaque" />
</object>
</span><p><a href="http://www.youtube.com/watch?v=Hl2cY7eW2Ko&fmt=18">www.youtube.com/watch?v=Hl2cY7eW2Ko</a></p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/10/24/debugging-apex-tools-and-techniques/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Salesforce Trigger when Rollups Summaries Not Possible</title>
		<link>http://blog.jeffdouglas.com/2011/08/23/salesforce-trigger-when-rollups-summaries-not-possible/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=salesforce-trigger-when-rollups-summaries-not-possible</link>
		<comments>http://blog.jeffdouglas.com/2011/08/23/salesforce-trigger-when-rollups-summaries-not-possible/#comments</comments>
		<pubDate>Tue, 23 Aug 2011 11:15:31 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Apex]]></category>
		<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4118</guid>
		<description><![CDATA[Master-Details relationships in Force.com  are very handy but don&#8217;t fit every scenario. For instance, it&#8217;s not possible to implement a rollup summary on formula field or text fields. Here&#8217;s a small trigger that you can use for a starter for these types of situations. The code for each class is available at GitHub for your [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F08%2F23%2Fsalesforce-trigger-when-rollups-summaries-not-possible%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F08%2F23%2Fsalesforce-trigger-when-rollups-summaries-not-possible%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://www.salesforce.com/us/developer/docs/api/Content/relationships_among_objects.htm">Master-Details relationships</a> in Force.com  are very handy but don&#8217;t fit every scenario. For instance, it&#8217;s not possible to implement a rollup summary on formula field or text fields. Here&#8217;s a small trigger that you can use for a starter for these types of situations. The code for each class is available at <a href="https://github.com/jeffdonthemic/Blog-Sample-Code">GitHub</a> for your forking pleasure.</p>
<p>So here&#8217;s the (not very useful) use case. Sales Order is the Master object which can have multiple Sales Order Items (detail object). The Sales Order Item has a &#8220;primary&#8221; Boolean field and a &#8220;purchased country&#8221; field. Each time Sales Order Items are inserted or updated, if the Sales Order Item is marked as &#8220;primary&#8221; then the value of &#8220;purchased country&#8221; is written into the &#8220;primary country&#8221; field on the Sales Order. I&#8217;m assuming that there can only be one Sales Order Item per Sales Order that is marked as primary. Essentially this is just a quick reference on the Sales Order to see which country is primary on any of the multiple Sales Order Items. Not very useful but illustrative.</p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2011/08/sales-order-item.png" rel="lightbox[4118]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/08/sales-order-item.png" alt="" title="sales-order-item" width="500" class="aligncenter size-full wp-image-4121" /></a></p>
<p>The code is broken down into a Trigger and an Apex &#8220;handler&#8221; class that implements the actual functionality. It&#8217;s <a href="http://blog.jeffdouglas.com/2010/10/21/force-com-programming-best-practices/">best practice</a> to only have one trigger for each object and to avoid complex logic in triggers. To simplify testing and resuse, triggers should delegate to Apex classes which contain the actual execution logic. See <a href="http://www.embracingthecloud.com/2010/07/08/ASimpleTriggerTemplateForSalesforce.aspx">Mike Leach’s excellent trigger template</a> for more info.</p>
<p><strong>SalesOrderItemTrigger</strong> (<a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/triggers/SalesOrderItemTrigger.trigger">source on GitHub</a>) - Implements trigger functionality for Sales Order Items. Delegates responsibility to SalesOrderItemTriggerHandler.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">trigger SalesOrderItemTrigger on Sales_Order_Item__c (after insert, after update) {
&nbsp;
  SalesOrderItemTriggerHandler handler = new SalesOrderItemTriggerHandler();
&nbsp;
  if(Trigger.isInsert &amp;&amp; Trigger.isAfter) {
    handler.OnAfterInsert(Trigger.new);
&nbsp;
  } else if(Trigger.isUpdate &amp;&amp; Trigger.isAfter) { 
    handler.OnAfterUpdate(Trigger.old, Trigger.new, Trigger.oldMap, Trigger.newMap);
&nbsp;
  }
&nbsp;
}</pre></td></tr></table></div>

</p>
<p><strong>SalesOrderItemTriggerHandler</strong> (<a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/classes/SalesOrderItemTriggerHandler.cls">source on GitHub</a>) - Implements the functionality for the sales order item trigger after insert and after update. Looks at each sales order item and if it is marked as primary_item__c then moves the primary_country__c value from the sales order item to the associated sales order&#8217;s primary_country__c field.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">public with sharing class SalesOrderItemTriggerHandler {
&nbsp;
  // update the primary country when new records are inserted from trigger
  public void OnAfterInsert(List&lt;Sales_Order_Item__c&gt; newRecords){
    updatePrimaryCountry(newRecords); 
  }
&nbsp;
  // update the primary country when records are updated from trigger  
  public void OnAfterUpdate(List&lt;Sales_Order_Item__c&gt; oldRecords, 
      List&lt;Sales_Order_Item__c&gt; updatedRecords,  Map&lt;ID, Sales_Order_Item__c&gt; oldMap, 
      Map&lt;ID, Sales_Order_Item__c&gt; newMap){
    updatePrimaryCountry(updatedRecords); 
  }
&nbsp;
  // updates the sales order with the primary purchased country for the item
  private void updatePrimaryCountry(List&lt;Sales_Order_Item__c&gt; newRecords) {
&nbsp;
    // create a new map to hold the sales order id / country values
    Map&lt;ID,String&gt; salesOrderCountryMap = new Map&lt;ID,String&gt;();
&nbsp;
    // if an item is marked as primary, add the purchased country
    // to the map where the sales order id is the key 
    for (Sales_Order_Item__c soi : newRecords) {
      if (soi.Primary_Item__c)
        salesOrderCountryMap.put(soi.Sales_Order__c,soi.Purchased_Country__c);
    } 
&nbsp;
    // query for the sale orders in the context to update
    List&lt;Sales_Order__c&gt; orders = [select id, Primary_Country__c from Sales_Order__c 
      where id IN :salesOrderCountryMap.keyset()];
&nbsp;
    // add the primary country to the sales order. find it in the map
    // using the sales order's id as the key
    for (Sales_Order__c so : orders)
      so.Primary_Country__c = salesOrderCountryMap.get(so.id);
&nbsp;
    // commit the records 
    update orders;
&nbsp;
  }
&nbsp;
}</pre></td></tr></table></div>

</p>
<p><strong>Test_SalesOrderItemTriggerHandler</strong> (<a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/classes/Test_SalesOrderItemTriggerHandler.cls">source on GitHub</a>) - Test class for SalesOrderItemTrigger and SalesOrderItemTriggerHandler. Achieves 100% code coverage.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">@isTest
private class Test_SalesOrderItemTriggerHandler {
&nbsp;
  private static Sales_Order__c so1;
  private static Sales_Order__c so2;
&nbsp;
  // set up our data for each test method
  static {
&nbsp;
  	Contact c = new Contact(firstname='test',lastname='test',email='no@email.com');
  	insert c;
&nbsp;
    so1 = new Sales_Order__c(name='test1',Delivery_Name__c=c.id);
    so2 = new Sales_Order__c(name='test2',Delivery_Name__c=c.id);
&nbsp;
    insert new List&lt;Sales_Order__c&gt;{so1,so2};
&nbsp;
  }
&nbsp;
  static testMethod void testNewRecords() {
&nbsp;
    Sales_Order_Item__c soi1 = new Sales_Order_Item__c();
    soi1.Sales_Order__c = so1.id;
    soi1.Quantity__c = 1;
    soi1.Description__c = 'test';
    soi1.Purchased_Country__c = 'Germany';
&nbsp;
    Sales_Order_Item__c soi2 = new Sales_Order_Item__c();
    soi2.Sales_Order__c = so1.id;
    soi2.Quantity__c = 1;
    soi2.Description__c = 'test';
    soi2.Purchased_Country__c = 'France';
    soi2.Primary_Item__c = true;
&nbsp;
    Sales_Order_Item__c soi3 = new Sales_Order_Item__c();
    soi3.Sales_Order__c = so2.id;
    soi3.Quantity__c = 1;
    soi3.Description__c = 'test';
    soi3.Purchased_Country__c = 'Germany';
    soi3.Primary_Item__c = true;
&nbsp;
    Sales_Order_Item__c soi4 = new Sales_Order_Item__c();
    soi4.Sales_Order__c = so2.id;
    soi4.Quantity__c = 1;
    soi4.Description__c = 'test';
    soi4.Purchased_Country__c = 'Germany';
&nbsp;
    Sales_Order_Item__c soi5 = new Sales_Order_Item__c();
    soi5.Sales_Order__c = so2.id;
    soi5.Quantity__c = 1;
    soi5.Description__c = 'test';
    soi5.Purchased_Country__c = 'Italy';
&nbsp;
    insert new List&lt;Sales_Order_Item__c&gt;{soi1,soi2,soi3,soi4,soi5}; 
&nbsp;
    System.assertEquals(2,[select count() from Sales_Order_Item__c where Sales_Order__c = :so1.id]);
    System.assertEquals(3,[select count() from Sales_Order_Item__c where Sales_Order__c = :so2.id]); 
&nbsp;
    System.assertEquals('France',[select primary_country__c from Sales_Order__c where id = :so1.id].primary_country__c);
    System.assertEquals('Germany',[select primary_country__c from Sales_Order__c where id = :so2.id].primary_country__c);
&nbsp;
  }
&nbsp;
  static testMethod void testUpdatedRecords() {
&nbsp;
    Sales_Order_Item__c soi1 = new Sales_Order_Item__c();
    soi1.Sales_Order__c = so1.id;
    soi1.Quantity__c = 1;
    soi1.Description__c = 'test';
    soi1.Purchased_Country__c = 'Germany';
&nbsp;
    Sales_Order_Item__c soi2 = new Sales_Order_Item__c();
    soi2.Sales_Order__c = so1.id;
    soi2.Quantity__c = 1;
    soi2.Description__c = 'test';
    soi2.Purchased_Country__c = 'France';
    soi2.Primary_Item__c = true;
&nbsp;
    insert new List&lt;Sales_Order_Item__c&gt;{soi1,soi2}; 
&nbsp;
    // assert that the country = France
    System.assertEquals('France',[select primary_country__c from Sales_Order__c where id = :so1.id].primary_country__c);
&nbsp;
    List&lt;Sales_Order_Item__c&gt; items = [select id, purchased_country__c from Sales_Order_Item__c 
      where Sales_Order__c = :so1.id and primary_item__c = true];
    // change the primary country on the sales order item. should trigger update
    items.get(0).purchased_country__c = 'Denmark';
&nbsp;
    update items;
    // assert that the country was successfully changed to Denmark
    System.assertEquals('Denmark',[select primary_country__c from Sales_Order__c where id = :so1.id].primary_country__c);
&nbsp;
  }
&nbsp;
}</pre></td></tr></table></div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/08/23/salesforce-trigger-when-rollups-summaries-not-possible/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Roll Your Own Salesforce &#8220;Lookup&#8221; Popup Window</title>
		<link>http://blog.jeffdouglas.com/2011/08/12/roll-your-own-salesforce-lookup-popup-window/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=roll-your-own-salesforce-lookup-popup-window</link>
		<comments>http://blog.jeffdouglas.com/2011/08/12/roll-your-own-salesforce-lookup-popup-window/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 12:18:48 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Apex]]></category>
		<category><![CDATA[Salesforce]]></category>
		<category><![CDATA[Visualforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4087</guid>
		<description><![CDATA[Let&#8217;s talk about the standard salesforce.com &#8220;lookup&#8221; popup window for a few minutes. You know what I&#8217;m talking about.. this button right here It&#8217;s a handy little button that pops up whenever you need to search for related records. It does a pretty good job but it has some serious drawbacks: It&#8217;s virtually impossible to [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F08%2F12%2Froll-your-own-salesforce-lookup-popup-window%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F08%2F12%2Froll-your-own-salesforce-lookup-popup-window%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Let&#8217;s talk about the standard salesforce.com &#8220;lookup&#8221; popup window for a few minutes. You know what I&#8217;m talking about.. this button right here</p>
<p><img title="custom-lookup-button.png" src="http://blog.jeffdouglas.com/wp-content/uploads/2011/08/custom-lookup-button.png" border="0" alt="Custom lookup button" width="292" height="116" /></p>
<p>It&#8217;s a handy little button that pops up whenever you need to search for related records. It does a pretty good job but it has some serious drawbacks:</p>
<ol>
<li>It&#8217;s virtually impossible to modify your search criteria. What if you want your users to do some crazy search based upon custom logic or search a field that is not typically available? Sorry&#8230; you are out of luck. Not possible.</li>
<li>It&#8217;s terrible for creating new records. Let&#8217;s say that a user searches for a specific related record and it (absolutely) doesn&#8217;t exist. To create the new record they need to close the lookup window, navigate to the tab to create the new related record, create the new record, then go back to the original record they were either editing or creating, pop up the lookup window again and find their newly created record. Wow! That&#8217;s a lot of work. </li>
<li>&#8220;Quick Create&#8221; is evil! You can enable the &#8220;Quick Create&#8221; option for an entire org but don&#8217;t do it! It displays, by default, on the tab home pages for leads, accounts, contacts, forecasts, and opportunities! The major problems are that you can only create new records for these 5 objects (what about the other ones!?), you can&#8217;t customize the fields on the page and validation rules don&#8217;t fire (can you say, &#8220;bad data&#8221;). </li>
</ol>
<p><img title="custom-lookup.png" src="http://blog.jeffdouglas.com/wp-content/uploads/2011/08/custom-lookup.png" border="0" alt="Quick Create is Bad" width="500" height="466" /></p>
<h3>Here&#8217;s the Solution!</h3>
<p>I have some good news and some bad news. For standard page layouts I can&#8217;t help you. Go vote for <a href="http://success.salesforce.com/ideaView?id=08730000000IYRFAA4">this idea</a> and <a href="http://success.salesforce.com/ideaview?id=08730000000IYB1AAO">this idea</a>. However, for Visualforce page I have a solution to all of these problems with code!</p>
<p><img title="custom-lookup1.png" src="http://blog.jeffdouglas.com/wp-content/uploads/2011/08/custom-lookup1.png" border="0" alt="Custom Lookup" width="500" height="250" /></p>
<p>Here&#8217;s how it looks. It may be easier to watch it full screen at <a href="http://www.youtube.com/watch?v=CGeFt6hdgRY">YouTube</a>.</p>
<p><span class="youtube">
<object width="560" height="340">
<param name="movie" value="http://www.youtube.com/v/CGeFt6hdgRY?color1=d6d6d6&amp;color2=f0f0f0&amp;border=0&amp;fs=1&amp;hl=en&amp;loop=0&amp;showinfo=0&amp;iv_load_policy=3&amp;showsearch=0&amp;rel=1&amp;hd=1" />
<param name="allowFullScreen" value="true" />
<embed wmode="opaque" src="http://www.youtube.com/v/CGeFt6hdgRY?color1=d6d6d6&amp;color2=f0f0f0&amp;border=0&amp;fs=1&amp;hl=en&amp;loop=0&amp;showinfo=0&amp;iv_load_policy=3&amp;showsearch=0&amp;rel=1&amp;hd=1" type="application/x-shockwave-flash" allowfullscreen="true" width="560" height="340"></embed>
<param name="wmode" value="opaque" />
</object>
</span><p><a href="http://www.youtube.com/watch?v=CGeFt6hdgRY&fmt=18">www.youtube.com/watch?v=CGeFt6hdgRY</a></p></p>
<p>Here&#8217;s the code you need to accomplish this. You need two Visualforce pages (the record you are editing and the popup window) and two Apex controllers (a simple one for the record you are editing and the controller for the search and new record popup).</p>
<p><strong>MyCustomLookupController</strong> - <a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/classes/MyCustomLookupController.cls">code at github</a></p>
<p>Here&#8217;s the Apex controller for the record you are either creating or editing. This is an extremely simple controller that just creates a new contact so you can use the lookup for the related account field.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">public with sharing class MyCustomLookupController {
&nbsp;
  public Contact contact {get;set;}
&nbsp;
  public MyCustomLookupController() {
    contact = new Contact();
  }
&nbsp;
}</pre></td></tr></table></div>

</p>
<p><strong>MyCustomLookup</strong> - <a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/pages/MyCustomLookup.page">code at github</a></p>
<p>This is the &#8220;magical&#8221; Visualforce page that uses jQuery to intercept the popup and instead of showing the standard salesforce.com pop, shows our custom popup instead. The user experience is seamless.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">&lt;apex:page controller=&quot;MyCustomLookupController&quot; id=&quot;Page&quot; tabstyle=&quot;Contact&quot;&gt;
&nbsp;
  &lt;script type=&quot;text/javascript&quot;&gt; 
  function openLookup(baseURL, width, modified, searchParam){
    var originalbaseURL = baseURL;
    var originalwidth = width;
    var originalmodified = modified;
    var originalsearchParam = searchParam;
&nbsp;
    var lookupType = baseURL.substr(baseURL.length-3, 3);
    if (modified == '1') baseURL = baseURL + searchParam;
&nbsp;
    var isCustomLookup = false;
&nbsp;
    // Following &quot;001&quot; is the lookup type for Account object so change this as per your standard or custom object
    if(lookupType == &quot;001&quot;){
&nbsp;
      var urlArr = baseURL.split(&quot;&amp;&quot;);
      var txtId = '';
      if(urlArr.length &gt; 2) {
        urlArr = urlArr[1].split('=');
        txtId = urlArr[1];
      }
&nbsp;
      // Following is the url of Custom Lookup page. You need to change that accordingly
      baseURL = &quot;/apex/CustomAccountLookup?txt=&quot; + txtId;
&nbsp;
      // Following is the id of apex:form control &quot;myForm&quot;. You need to change that accordingly
      baseURL = baseURL + &quot;&amp;frm=&quot; + escapeUTF(&quot;{!$Component.myForm}&quot;);
      if (modified == '1') {
        baseURL = baseURL + &quot;&amp;lksearch=&quot; + searchParam;
      }
&nbsp;
      // Following is the ID of inputField that is the lookup to be customized as custom lookup
      if(txtId.indexOf('Account') &gt; -1 ){
        isCustomLookup = true;
      }
    }
&nbsp;
&nbsp;
    if(isCustomLookup == true){
      openPopup(baseURL, &quot;lookup&quot;, 350, 480, &quot;width=&quot;+width+&quot;,height=480,toolbar=no,status=no,directories=no,menubar=no,resizable=yes,scrollable=no&quot;, true);
    }
    else {
      if (modified == '1') originalbaseURL = originalbaseURL + originalsearchParam;
      openPopup(originalbaseURL, &quot;lookup&quot;, 350, 480, &quot;width=&quot;+originalwidth+&quot;,height=480,toolbar=no,status=no,directories=no,menubar=no,resizable=yes,scrollable=no&quot;, true);
    } 
  }
&lt;/script&gt;
&nbsp;
&lt;apex:sectionHeader title=&quot;Demo&quot;  subtitle=&quot;Custom Lookup&quot; /&gt;
&nbsp;
  &lt;apex:form id=&quot;myForm&quot;&gt;  
    &lt;apex:PageBlock id=&quot;PageBlock&quot;&gt;    
      &lt;apex:pageBlockSection columns=&quot;1&quot; title=&quot;Custom Lookup&quot;&gt;
        &lt;apex:inputField id=&quot;Account&quot; value=&quot;{!contact.AccountId}&quot;  /&gt;
      &lt;/apex:pageBlockSection&gt;
    &lt;/apex:PageBlock&gt;
  &lt;/apex:form&gt;
&nbsp;
&lt;/apex:page&gt;</pre></td></tr></table></div>

</p>
<p><strong>CustomAccountLookupController</strong> - <a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/classes/CustomAccountLookupController.cls">code at github</a></p>
<p>The Apex controller for the custom popup window is yours to customize. I know what you are thinking, &#8220;Free at last! Free at last! Thank God Almighty, we are free at last!&#8221; This class has all of your custom search functionality plus the method to create a new account. This is demo code so the search is very limited and does not prevent <a href="http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dynamic_soql.htm">soql injections</a>.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">public with sharing class CustomAccountLookupController {
&nbsp;
  public Account account {get;set;} // new account to create
  public List&lt;Account&gt; results{get;set;} // search results
  public string searchString{get;set;} // search keyword
&nbsp;
  public CustomAccountLookupController() {
    account = new Account();
    // get the current search string
    searchString = System.currentPageReference().getParameters().get('lksrch');
    runSearch();  
  }
&nbsp;
  // performs the keyword search
  public PageReference search() {
    runSearch();
    return null;
  }
&nbsp;
  // prepare the query and issue the search command
  private void runSearch() {
    // TODO prepare query string for complex serarches &amp; prevent injections
    results = performSearch(searchString);               
  } 
&nbsp;
  // run the search and return the records found. 
  private List&lt;Account&gt; performSearch(string searchString) {
&nbsp;
    String soql = 'select id, name from account';
    if(searchString != '' &amp;&amp; searchString != null)
      soql = soql +  ' where name LIKE \'%' + searchString +'%\'';
    soql = soql + ' limit 25';
    System.debug(soql);
    return database.query(soql); 
&nbsp;
  }
&nbsp;
  // save the new account record
  public PageReference saveAccount() {
    insert account;
    // reset the account
    account = new Account();
    return null;
  }
&nbsp;
  // used by the visualforce page to send the link to the right dom element
  public string getFormTag() {
    return System.currentPageReference().getParameters().get('frm');
  }
&nbsp;
  // used by the visualforce page to send the link to the right dom element for the text box
  public string getTextBox() {
    return System.currentPageReference().getParameters().get('txt');
  }
&nbsp;
}</pre></td></tr></table></div>

</p>
<p><strong>CustomAccountLookup</strong> - <a href="https://github.com/jeffdonthemic/Blog-Sample-Code/blob/master/salesforce/src/pages/CustomAccountLookup.page">code at github</a></p>
<p>Any finally the Visualforce page for the popup itself. It contains a tabbed interface easily allowing a user to search for records and create new ones. Make sure you look at the code for the second tab for creating a new record. I have better things to do than change the fields on the input form every time a new field is created or something is made required. The solution is to use <a href="http://www.salesforce.com/us/developer/docs/pages/Content/pages_dynamic_vf_field_sets.htm">field sets</a>! So when an administrator makes a change, they can simply update the field set and the popup reflects the change accordingly. Life is good.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">&lt;apex:page controller=&quot;CustomAccountLookupController&quot;
  title=&quot;Search&quot; 
  showHeader=&quot;false&quot; 
  sideBar=&quot;false&quot; 
  tabStyle=&quot;Account&quot; 
  id=&quot;pg&quot;&gt;
&nbsp;
  &lt;apex:form &gt;
  &lt;apex:outputPanel id=&quot;page&quot; layout=&quot;block&quot; style=&quot;margin:5px;padding:10px;padding-top:2px;&quot;&gt;
    &lt;apex:tabPanel switchType=&quot;client&quot; selectedTab=&quot;name1&quot; id=&quot;tabbedPanel&quot;&gt;
&nbsp;
      &lt;!-- SEARCH TAB --&gt;
      &lt;apex:tab label=&quot;Search&quot; name=&quot;tab1&quot; id=&quot;tabOne&quot;&gt;
&nbsp;
        &lt;apex:actionRegion &gt;  
          &lt;apex:outputPanel id=&quot;top&quot; layout=&quot;block&quot; style=&quot;margin:5px;padding:10px;padding-top:2px;&quot;&gt;
            &lt;apex:outputLabel value=&quot;Search&quot; style=&quot;font-weight:Bold;padding-right:10px;&quot; for=&quot;txtSearch&quot;/&gt;
            &lt;apex:inputText id=&quot;txtSearch&quot; value=&quot;{!searchString}&quot; /&gt;
              &lt;span style=&quot;padding-left:5px&quot;&gt;&lt;apex:commandButton id=&quot;btnGo&quot; value=&quot;Go&quot; action=&quot;{!Search}&quot; rerender=&quot;searchResults&quot;&gt;&lt;/apex:commandButton&gt;&lt;/span&gt;
          &lt;/apex:outputPanel&gt;
&nbsp;
          &lt;apex:outputPanel id=&quot;pnlSearchResults&quot; style=&quot;margin:10px;height:350px;overflow-Y:auto;&quot; layout=&quot;block&quot;&gt;
            &lt;apex:pageBlock id=&quot;searchResults&quot;&gt; 
              &lt;apex:pageBlockTable value=&quot;{!results}&quot; var=&quot;a&quot; id=&quot;tblResults&quot;&gt;
                &lt;apex:column &gt;
                  &lt;apex:facet name=&quot;header&quot;&gt;
                    &lt;apex:outputPanel &gt;Name&lt;/apex:outputPanel&gt;
                  &lt;/apex:facet&gt;
                   &lt;apex:outputLink value=&quot;javascript:top.window.opener.lookupPick2('{!FormTag}','{!TextBox}_lkid','{!TextBox}','{!a.Id}','{!a.Name}', false)&quot; rendered=&quot;{!NOT(ISNULL(a.Id))}&quot;&gt;{!a.Name}&lt;/apex:outputLink&gt;     
                &lt;/apex:column&gt;
              &lt;/apex:pageBlockTable&gt;
            &lt;/apex:pageBlock&gt;
          &lt;/apex:outputPanel&gt;
        &lt;/apex:actionRegion&gt;
&nbsp;
      &lt;/apex:tab&gt;
&nbsp;
      &lt;!-- NEW ACCOUNT TAB --&gt;
      &lt;apex:tab label=&quot;New Account&quot; name=&quot;tab2&quot; id=&quot;tabTwo&quot;&gt;
&nbsp;
        &lt;apex:pageBlock id=&quot;newAccount&quot; title=&quot;New Account&quot; &gt;
&nbsp;
          &lt;apex:pageBlockButtons &gt;
            &lt;apex:commandButton action=&quot;{!saveAccount}&quot; value=&quot;Save&quot;/&gt;
          &lt;/apex:pageBlockButtons&gt;
          &lt;apex:pageMessages /&gt;
&nbsp;
          &lt;apex:pageBlockSection columns=&quot;2&quot;&gt;
            &lt;apex:repeat value=&quot;{!$ObjectType.Account.FieldSets.CustomAccountLookup}&quot; var=&quot;f&quot;&gt;
              &lt;apex:inputField value=&quot;{!Account[f]}&quot;/&gt;
            &lt;/apex:repeat&gt;
          &lt;/apex:pageBlockSection&gt; 
        &lt;/apex:pageBlock&gt;
&nbsp;
      &lt;/apex:tab&gt;
    &lt;/apex:tabPanel&gt;
  &lt;/apex:outputPanel&gt;
  &lt;/apex:form&gt;
&lt;/apex:page&gt;</pre></td></tr></table></div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/08/12/roll-your-own-salesforce-lookup-popup-window/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>[INFOGRAPHIC] Evolution of Computer Languages</title>
		<link>http://blog.jeffdouglas.com/2011/07/28/infographic-evolution-of-computer-languages/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=infographic-evolution-of-computer-languages</link>
		<comments>http://blog.jeffdouglas.com/2011/07/28/infographic-evolution-of-computer-languages/#comments</comments>
		<pubDate>Thu, 28 Jul 2011 11:06:15 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=4054</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F07%2F28%2Finfographic-evolution-of-computer-languages%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F07%2F28%2Finfographic-evolution-of-computer-languages%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><img src="http://c179631.r31.cf0.rackcdn.com/Infographic_Programming_Rackspace_Final_Version.png" alt="Cloud applications" width="550" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/07/28/infographic-evolution-of-computer-languages/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>GitHub Releases Mac Client</title>
		<link>http://blog.jeffdouglas.com/2011/06/30/github-releases-mac-client/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=github-releases-mac-client</link>
		<comments>http://blog.jeffdouglas.com/2011/06/30/github-releases-mac-client/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 13:00:46 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=3992</guid>
		<description><![CDATA[Everyone loves GitHub but the CLI can be a little intimating for newcomers. A couple of days ago GitHub released a client for OS X. The setup walks you through the process of creating a GitHub account (if you don&#8217;t have one), uploading repositories and provides a slick little interface for cloning, browsing and managing [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F06%2F30%2Fgithub-releases-mac-client%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F06%2F30%2Fgithub-releases-mac-client%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://www.github.com"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/06/github-logo-150x150.png" alt="" title="github-logo" width="150" height="150" class="alignleft size-thumbnail wp-image-3993" /></a>Everyone loves GitHub but the CLI can be a little intimating for newcomers. A couple of days ago <a href="https://github.com/blog/878-announcing-github-for-mac">GitHub released a client for OS X</a>.  The setup walks you through the process of creating a GitHub account (if you don&#8217;t have one), uploading repositories and provides a slick little interface for cloning, browsing and managing repos.</p>
<p>If you are on Mac, be sure to download the app and give if a whirl. Salesforce.com is using GitHub more and more so starting getting up to speed on it.</p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2011/06/github-mac.png" rel="lightbox[3992]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/06/github-mac.png" alt="" title="github-mac" width="550" class="alignnone size-full wp-image-3996" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/06/30/github-releases-mac-client/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OpportunityAccessLevel Not Writable</title>
		<link>http://blog.jeffdouglas.com/2011/03/17/opportunityaccesslevel-not-writable/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=opportunityaccesslevel-not-writable</link>
		<comments>http://blog.jeffdouglas.com/2011/03/17/opportunityaccesslevel-not-writable/#comments</comments>
		<pubDate>Thu, 17 Mar 2011 10:40:44 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Apex]]></category>
		<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=3767</guid>
		<description><![CDATA[I was working on a project the other day where I needed to dynamically add users to an opportunity&#8217;s Sales Team (OpportunityTeamMember object) so that users who do not normally have access to an opportunity based upon Org-wide security settings can work on the opportunity with other team members. One of the advantages of Sales [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F03%2F17%2Fopportunityaccesslevel-not-writable%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F03%2F17%2Fopportunityaccesslevel-not-writable%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>I was working on a project the other day where I needed to dynamically add users to an opportunity&#8217;s Sales Team (OpportunityTeamMember object) so that users who do not normally have access to an opportunity based upon Org-wide security settings can work on the opportunity with other team members. One of the advantages of Sales Teams is that you can specify the level of access that each team member has for the opportunity. Some team members may need read/write access while others may just need read-only access.</p>
<p>From the opportunity page layout you can add a new team member and specify their access level and role.</p>
<p><img title="sales-team.png" src="http://blog.jeffdouglas.com/wp-content/uploads/2011/03/sales-team.png" border="0" alt="Sales team" width="500" height="186" /></p>
<p>However, by default when you create a new team member via Apex, the platform grants them read-only access. So I tried to specify grant &#8220;Edit&#8221; (read/write) access with the following code.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">OpportunityTeamMember member = new OpportunityTeamMember();
member.OpportunityId = SomeOpp.Id;
member.UserId = SomeUser.Id;
mmember.TeamMemberRole = 'Sales Rep';
member.OpportunityAccessLevel = 'Edit';</pre></td></tr></table></div>

</p>
<p>Specifying the OpportunityAccessLevel threw the following error when saving my class:</p>
<blockquote><p>Save error: Field is not writable: OpportunityTeamMember.OpportunityAccessLevel</p></blockquote>
<p>To be fair, <a href="http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_opportunityteammember.htm" target="_blank">the docs</a> state that OpportunityAccessLevel is not creatable but it used to be with earlier versions of the API so I <em><strong>really</strong></em> wanted this to work and it was screwing up my day.</p>
<p>So here&#8217;s the solution that I can up with in case anyone is looking for a answers. You need to add the team members to the opportunity and then update the sharing access to the opportunity for these users.</p>
<p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">OpportunityTeamMember member = new OpportunityTeamMember();
member.OpportunityId = SomeOpp.Id;
member.UserId = SomeUser.Id;
mmember.TeamMemberRole = 'Sales Rep';
&nbsp;
insert member;
&nbsp;
// get all of the team members' sharing records
List&lt;OpportunityShare&gt; shares = [select Id, OpportunityAccessLevel, 
  RowCause from OpportunityShare where OpportunityId IN :SomeSetOfOpptyIds 
  and RowCause = 'Team'];
&nbsp;
// set all team members access to read/write
for (OpportunityShare share : shares) 
  share.OpportunityAccessLevel = 'Edit';
&nbsp;
update shares;</pre></td></tr></table></div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/03/17/opportunityaccesslevel-not-writable/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Dynamically Group &amp; Display Query Results</title>
		<link>http://blog.jeffdouglas.com/2011/03/02/dynamically-group-display-query-results/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=dynamically-group-display-query-results</link>
		<comments>http://blog.jeffdouglas.com/2011/03/02/dynamically-group-display-query-results/#comments</comments>
		<pubDate>Wed, 02 Mar 2011 10:55:14 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Apex]]></category>
		<category><![CDATA[Code Sample]]></category>
		<category><![CDATA[Salesforce]]></category>
		<category><![CDATA[Visualforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=3737</guid>
		<description><![CDATA[I was working on a Visualforce page that displays the results of a query in separate PageBlock sections based upon a value in the query results. I ran into a small issue which took about an hour or so to solve, so I thought it might make descent blog fodder. The requirement for the page [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F03%2F02%2Fdynamically-group-display-query-results%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F03%2F02%2Fdynamically-group-display-query-results%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>I was working on a Visualforce page that displays the results of a query in separate PageBlock sections based upon a value in the query results. I ran into a small issue which took about an hour or so to solve, so I thought it might make descent blog fodder. </p>
<p>The requirement for the page was to query for records and then display them grouped in sections in a Visualforce page based upon whatever values (in this case BillingState) are returned in the results. If additional states were added, then the Visualforce page should be able to add those new sections without changes to the code. Here&#8217;s a screenshot of the sample solution that I came up with but you can also<a href="http://jeffdouglas-developer-edition.na5.force.com/examples/DisplaySections" target="_blank"> run this sample on my Developer Site</a>:</p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2011/03/group-by-value.png" rel="lightbox[3737]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/03/group-by-value-300x283.png" alt="" title="group-by-value" width="300" height="283" class="alignnone size-medium wp-image-3738" /></a></p>
<p>Here&#8217;s the code for the Visualforce page. I&#8217;ve made it as bare as possible but you can see that it iterates over the array of states to display the pageBlock sections and then displays the record if the state matches the current blockSection&#8217;s state.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">&lt;apex:page controller=&quot;DisplaySectionsController&quot; action=&quot;{!load}&quot; sidebar=&quot;false&quot;&gt;
  &lt;apex:sectionHeader title=&quot;My Sample Display Page&quot; subtitle=&quot;Group by States&quot; 
    description=&quot;This page shows how you can dynamically group results by field value.&quot;/&gt;
&nbsp;
  &lt;apex:repeat value=&quot;{!states}&quot; var=&quot;state&quot;&gt;
&nbsp;
    &lt;apex:pageBlock title=&quot;{!state}&quot;&gt;
&nbsp;
      &lt;apex:repeat value=&quot;{!accounts}&quot; var=&quot;account&quot;&gt; 
&nbsp;
        &lt;apex:outputPanel rendered=&quot;{!IF(state=account.BillingState,true,false)}&quot;&gt;
        {!account.Name} - {!account.BillingState}&lt;br/&gt;
        &lt;/apex:outputPanel&gt;
&nbsp;
      &lt;/apex:repeat&gt;
&nbsp;
    &lt;/apex:pageBlock&gt;
&nbsp;
  &lt;/apex:repeat&gt;
&nbsp;
&lt;/apex:page&gt;</pre></td></tr></table></div>

<p>The Controller exposes two collections to the Visualforce page: the list of Accounts and the array of States.  Here&#8217;s the issue that I ran into. Since I wanted to have a collection of unique state names, I originally added each state to a Set and simply returned the Set to the Visualforce page (instead of the array) to display the pageBlock sections. However, returning the Set gave me a compile error at line 11 in the Visualforce page:</p>
<blockquote><p>Save error: Incorrect parameter for operator &#8216;=&#8217;. Expected Text, received Object</p></blockquote>
<p>The problem is that even though the Set is a collection of Strings, it is actually an object underneath the covers and throws a comparison error. Therefore you have to return the states as an array of strings for the code to compile and run properly.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">public with sharing class DisplaySectionsController {
&nbsp;
  public List&lt;Account&gt; accounts {get;set;}  
  public String[] states {get;set;}
&nbsp;
  public void load() {
&nbsp;
    // for demo purposes limit the states  
    accounts = [Select ID, Name, BillingState From Account 
      Where BillingState IN ('CA','NY','FL')];
&nbsp;
    // dynamically create set of unique states from query
    Set&lt;String&gt; stateSet = new Set&lt;String&gt;();
    for (Account a : accounts)
      stateSet.add(a.BillingState);
&nbsp;
    // convert the set into a string array  
    states = new String[stateSet.size()];
    Integer i = 0;
    for (String state : stateSet) { 
      states[i] = state;
      i++;
    }
&nbsp;
  }
&nbsp;
}</pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/03/02/dynamically-group-display-query-results/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Document Apex Code with ApexDoc</title>
		<link>http://blog.jeffdouglas.com/2011/01/27/document-apex-code-with-apexdoc/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=document-apex-code-with-apexdoc</link>
		<comments>http://blog.jeffdouglas.com/2011/01/27/document-apex-code-with-apexdoc/#comments</comments>
		<pubDate>Thu, 27 Jan 2011 15:04:46 +0000</pubDate>
		<dc:creator>Jeff Douglas</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Salesforce]]></category>

		<guid isPermaLink="false">http://blog.jeffdouglas.com/?p=3583</guid>
		<description><![CDATA[My fellow Appirian and resident super-smart guy, Aslam Bari has created a super slick tool to document Apex code. ApexDoc is essentially JavaDocs for Apex. You add comments to your source code in the JavaDoc fashion (@author, @date, @param, etc) and ApexDoc reads these and generates a nice set of HTML files that allows you [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F01%2F27%2Fdocument-apex-code-with-apexdoc%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.jeffdouglas.com%2F2011%2F01%2F27%2Fdocument-apex-code-with-apexdoc%2F&amp;source=jeffdonthemic&amp;style=normal&amp;service=bit.ly&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><img style="float: left;padding-right:15px;padding-bottom:10px" title="apex_doc_logo.png" src="http://blog.jeffdouglas.com/wp-content/uploads/2011/01/apex_doc_logo.png" border="0" alt="apex_doc_logo.png" width="147" height="80" /></p>
<p>My fellow Appirian and resident super-smart guy, <a href="http://techsahre.blogspot.com/" target="_blank">Aslam Bari</a> has created a super slick tool to document Apex code. ApexDoc is essentially JavaDocs for Apex. You add comments to your source code in the JavaDoc fashion (@author, @date, @param, etc) and ApexDoc reads these and generates a nice set of HTML files that allows you to browse your class structure. <a href="http://www.aslambari.com/apexdoc.html" target="_blank">Here&#8217;s a short video</a> on the entire process.</p>
<p>Generating the ApexDocs is fairly simple. Just point to your source code, an option output file, an optional file containing the HMTL for the right Home frame (project name, description, etc) and an optional file containing author information. Sample command syntax is:</p>
<p><em>apexdoc &lt;source_directory&gt; [&lt;target_directory?&gt;] [&lt;homefile&gt;] [&lt;authorfile&gt;]</em></p>
<p><a href="http://techsahre.blogspot.com/2011/01/apexdoc-salesforce-code-documentation.html" target="_blank">Download ApexDoc here</a> along with more detailed info and feedback. </p>
<p><img title="apexdoc-screenshot.png" src="http://blog.jeffdouglas.com/wp-content/uploads/2011/01/apexdoc-screenshot.png" border="0" alt="apexdoc-screenshot.png" width="550" height="380" /></p>
<p><strong>Update</strong>: Aslam and I worked on a bug affecting Mac and Unix users. <a href="http://www.aslambari.com/apexdoc.html" target="_blank">Download the latest version</a> of the files to get the fix. Also, here are some screenshots that may help out Mac users.</p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2011/01/apexdoc-filesystem.png" rel="lightbox[3583]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/01/apexdoc-filesystem.png" alt="" title="apexdoc-filesystem" width="500" class="alignnone size-full wp-image-3594" /></a></p>
<p><a href="http://blog.jeffdouglas.com/wp-content/uploads/2011/01/apexdoc-terminal.png" rel="lightbox[3583]"><img src="http://blog.jeffdouglas.com/wp-content/uploads/2011/01/apexdoc-terminal.png" alt="" title="apexdoc-terminal" width="500" class="alignnone size-full wp-image-3595" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jeffdouglas.com/2011/01/27/document-apex-code-with-apexdoc/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

