<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Nico's CRM</title>
	
	<link>http://blog.nicocrm.com</link>
	<description>Programming, technology, and CRM - from a Belgian programmer exiled to Missouri</description>
	<lastBuildDate>Thu, 28 Jul 2011 22:02:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/chivinou" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="chivinou" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Parse CSV file in Salesforce Apex</title>
		<link>http://blog.nicocrm.com/2011/03/06/parse-csv-file-in-salesforce-apex/</link>
		<comments>http://blog.nicocrm.com/2011/03/06/parse-csv-file-in-salesforce-apex/#comments</comments>
		<pubDate>Mon, 07 Mar 2011 05:06:43 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Force.com]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=521</guid>
		<description><![CDATA[I could not find a CSV parser for Salesforce so implemented this one and decided to share it. It&#8217;s simple but it handles quotes, newlines and arbitrary delimiters (I&#8217;ve implemented a few CSV parsers over the years so hopefully I am getting the hang of it). One thing a bit special with this one is [...]]]></description>
			<content:encoded><![CDATA[<p>I could not find a CSV parser for Salesforce so implemented this one and decided to share it.  It&#8217;s simple but it handles quotes, newlines and arbitrary delimiters (I&#8217;ve implemented a few CSV parsers over the years so hopefully I am getting the hang of it).  One thing a bit special with this one is instead of &#8220;tokenizing&#8221; the string as one might usually do in an optimized parser I went with a regex approach, basically this means the string may have to get read twice in a worst case scenario, but the way Apex calculates the complexity of your code is essentially the number of statements that get run.  So the higher level approach, even if they are a bit less efficient overall, score better with Apex (less likely to hit the governor limit).</p>
<p><script src="https://gist.github.com/858086.js?file=gistfile1.java"></script></p>
<p>Here is the associated test class.  One thing I really dig about the SF development model is the integration with unit tests.  This almost makes up for the suckiness of the IDE.</p>
<p><script src="https://gist.github.com/858089.js?file=gistfile1.java"></script></p>
<p>I might as well make a few comments about the development process.  First of all, the unit test integration is rather nice.  They will automatically &#8220;sandbox&#8221; your database for the unit test and give you a coverage report.  A few things to watch out for:</p>
<ul>
<li>Keep your eye on the &#8220;Problems&#8221; tab.  If there is an error, maybe in some other file, the IDE will still happily run the previous version of your tests and you&#8217;ll be left wondering why your changes are not taking effect.  Happened to me more than once.</li>
<li>Use a sandbox for development &#8211; very little can be done in a production environment because you need test coverage to deploy the code, and you can&#8217;t test the code until it&#8217;s deployed.</li>
<li>The Force.com IDE sucks really, really bad.  I don&#8217;t have anything against Eclipse &#8211; I love Eclipse for Java code!  But writing Apex code is very, very primitive.  The build operations are quite slow (not &#8220;SalesLogix App Architect&#8221; slow, mind you, but still slow) and the errors reported are not clear.  Intellisense very rarely works.  Stuff occasionally gets out of sync and has to be blown away and resynced from server.  Also, only a few items can actually be done from the IDE, the rest has to be configured using the web interface which is very cluttered and confusing.  The only redeeming factors are the documentation which is top notch (both the reference guide and the community) and the unit test integration.</li>
</ul>
<p>An alternative to be aware of is that the processing can be done remotely and use the bulk update API to do the communication with the database.  In retrospect it might have been the way to go in this scenario, since I already had to do some processing in a remote app, but this was a good project to tour the Apex facilities with so I am glad I got the chance to do that.</p>
<p>I also used <a href="http://www.heroku.com">Heroku</a> for the remote processing part, this was my first non-toy app on that platform, and a very positive experience so far.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2011/03/06/parse-csv-file-in-salesforce-apex/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scripts are usually safe</title>
		<link>http://blog.nicocrm.com/2011/02/24/scripts-are-usually-safe/</link>
		<comments>http://blog.nicocrm.com/2011/02/24/scripts-are-usually-safe/#comments</comments>
		<pubDate>Thu, 24 Feb 2011 17:28:11 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=513</guid>
		<description><![CDATA[I think I just found the most awesome warning message ever. I am going to write all my dialogs like this too now. &#8220;Deleting an account is usually safe. Are you sure you wish to delete this account?&#8221;]]></description>
			<content:encoded><![CDATA[<p>I think I just found the most awesome warning message ever.  I am going to write all my dialogs like this too now.  &#8220;Deleting an account is usually safe.  Are you sure you wish to delete this account?&#8221;</p>
<p><img src="/wp-content/uploads/2011/02/scripts_are_usually_safe.png" alt="Scripts are usually safe"/></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2011/02/24/scripts-are-usually-safe/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cross browser “mailto” function</title>
		<link>http://blog.nicocrm.com/2011/02/15/cross-browser-mailto-function/</link>
		<comments>http://blog.nicocrm.com/2011/02/15/cross-browser-mailto-function/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 04:27:43 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=504</guid>
		<description><![CDATA[Sending an email from a web page (via the user&#8217;s client) is surprisingly tricky. A mailto: url can do the trick but it has some severe length limitations. Sending it via a background script does not have any such limitation but the user does not get a chance to edit the email, record it to [...]]]></description>
			<content:encoded><![CDATA[<p>Sending an email from a web page (via the user&#8217;s client) is surprisingly tricky.  A mailto: url can do the trick but it has some severe length limitations.  Sending it via a background script does not have any such limitation but the user does not get a chance to edit the email, record it to their Sent Items, etc.  Using Outlook automation allows for the most flexibility but it has some bad implications: only works on IE, requires some pretty specific security setting (trusted site + &#8220;enable activex controls not marked as safe&#8221;).</p>
<p>For an intranet scenario, where we can be certain that most users will be using Outlook and IE, I came up with the following solution.  It will attempt to send the mail using Outlook automation and fall back to a &#8220;mailto&#8221; method if not available (i.e. either they are using another browser / OS, or they don&#8217;t have the correct security settings).  It is a <a href="http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition">CommonJS</a> module, I have started using <a href="http://RequireJS.org">RequireJS</a> for custom modules to prevent namespace clashes.</p>
<p><script src="https://gist.github.com/828850.js"> </script></p>
<p>The tricky part was making sure the URL stayed short enough &#8211; if it gets over a certain length, Firefox will just ignore it altogether (other browser will truncate it).  This is the job of the addUrlComponents function.  I call it with the recipient, subject and body parameters until the length is exhausted, but each is limited &#8211; this way if there is a ton of recipients, rather than trying to keep them all and getting a blank email, it limits the total address length to 900 characters and saves the rest for the email itself.  It&#8217;s not ideal either way but I figured this was preferable.</p>
<p>I went ahead and created a test page for it since the addUrlComponents function was not trivial&#8230; this also gave me a good occasion to use qunit &#8211; very, very easy to get running with that test framework.</p>
<p><script src="https://gist.github.com/828858.js"> </script></p>
<p>PS &#8211; this gist thing is a great way to get syntax highlighting on the cheap hah!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2011/02/15/cross-browser-mailto-function/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Enhancing a lengthy process with a progress bar</title>
		<link>http://blog.nicocrm.com/2011/01/29/enhancing-a-lengthy-process-with-a-progress-bar/</link>
		<comments>http://blog.nicocrm.com/2011/01/29/enhancing-a-lengthy-process-with-a-progress-bar/#comments</comments>
		<pubDate>Sat, 29 Jan 2011 23:00:29 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Saleslogix]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=472</guid>
		<description><![CDATA[At any time we need to perform a lengthy process such as an import or a batch update, one of the elements necessary to provide a good user experience will be to give them a feedback on the progress. I have experimented with a few of them and wanted to show the one that I [...]]]></description>
			<content:encoded><![CDATA[<p>At any time we need to perform a lengthy process such as an import or a batch update, one of the elements necessary to provide a good user experience will be to give them a feedback on the progress.  I have experimented with a few of them and wanted to show the one that I have found the most versatile and easy to implement.</p>
<p>First of all note that if you have a lengthy process you will need to configure the request timeout in the web.config.  It would be something like (assuming your page is called Import.aspx):</p>
<pre>
&lt;location path="Import.aspx"&gt;
  &lt;system.web&gt;
    &lt;httpRuntime executionTimeout="3600" /&gt;
  &lt;/system.web&gt;
&lt;/location&gt;
</pre>
<p>Also, do take a look at the note on potential performance problems, at the end of this post.</p>
<p>Now, a quick review of the options:</p>
<ul>
<li>There is a progress bar control called RadProgressManager which is actually included as part of SalesLogix (they use it in the lead import screen).  It works relatively well once you have it configured properly but I have found a few challenges when trying to use it.  First of all, it works by polling, which means it makes repeated requests to the page to find out the progress &#8211; this is relatively inefficient, though usually not a big concern.  Secondly, the control takes some work to properly configure &#8211; it is rather sensitive to the order in which components are loaded, where it is placed respectively to the update panels, whether the postback is asynchronous or not, etc.  If everything is not &#8220;just right&#8221; it will fail, often with an obscure error message (or no message at all).  Thirdly, the default look is absolutely hideous, so you usually have to replace the whole thing with a custom template &#8211; quite a bit of work.  Finally it gives little options other than just reporting a progress percentage and a step description, so if you want to for example report errors as they happen you may be out of luck.  For these reasons I have not used it very often.</li>
<li>One other way is doing repeated refresh of the page (or just the update panel that contains the progress bar) to refresh the status.  This works pretty well if the processing happens on a separate service (other than being inefficient as it requires a reload every time) but not if it is done on the same page of course as it would not be able to reload itself until the process was finished!  Note that you can&#8217;t do the process on a handler and refresh the page either, as a page in SalesLogix always requires an exclusive access to the session.</li>
<li>Finally there is an option recently called &#8220;pushlet&#8221; but which was already used years ago before Javascript even came of age.  The idea is to post the data to the page which does the process, but instead of reporting the process &#8220;out of band&#8221; it just writes it out as it happens.  Now, the idea is that instead of just writing the process to a blank screen, this page outputs a snippet of Javascript which gets executed and (via the method of your choosing) reports a progress or an error.  The advantages are that it uses only one connection unlike the previous 2, reports the progress in real-time (unlike the other ones which will have a lag imposed by the polling rate), offers complete control of the UI, and is rather easy to implement, even more so if the UI is driven mostly from Javascript.</li>
</ul>
<p>So, the basic concept of the &#8220;pushlet&#8221; is to post the form&#8217;s data into a hidden iframe.  This can be done either by setting the SRC of the iframe (if no post data is required), by stuffing the form&#8217;s data into a form on the iframe itself and posting it, or by setting the TARGET of the current page&#8217;s form and posting it.  The last one is most powerful as it will let you post files, but unfortunately also a bit more complex as you have to fight with ASP.NET to obtain a reference to the form and make sure you don&#8217;t interfere with the rest of the page.  Here is a post that describes it though, and by a happy coincidence was posted right after I finished this one: <a href="http://west-wind.com/Weblog/posts/904750.aspx">Changing an HTML Form&#8217;s Target with jQuery</a> &#8211; it&#8217;s for a vanilla ASP.NET scenario but should mostly apply to SalesLogix as well.  An example of the second method, which works well enough as long as there is no need to upload a file:</p>
<pre>
var root = document.getElementById("bulkRequestSubmitFrame");
var rootDoc = root.contentDocument || root.contentWindow.document;
var baseUrl = location.href.replace(new RegExp("/[^/]*$"), "");
var url =  baseUrl + "/SmartParts/LitRequest/LitRequestBulkSubmit.ashx";
var scriptParts = [];
var doc = rootDoc.createDocumentFragment();
function createElement(tagName, attrs) {
	var elem = document.createElement(tagName);
	for (var a in attrs) {
		elem[a] = attrs[a];
	}
	return elem;
}

// this is the actual form data
doc.appendChild(createElement("input", { name: 'submission', value: Ext.util.JSON.encode(submission) }));
doc.appendChild(createElement("input", { name: 'itemSelection', value: Ext.util.JSON.encode(itemSelection) }));

rootDoc.body.innerHTML = "&lt;form id='theform' action='" + url + "' method='POST'&gt;&lt;/form&gt;";
var form = rootDoc.getElementById('theform');
form.appendChild(doc);
form.submit();
</pre>
<p>As the handler for the form processes the data, it will output snippets of javascript, such as:</p>
<pre>
&lt;script type="text/javascript"&gt;
parent.reportSubmissionProgress(50);
&lt;/script&gt;
</pre>
<p>Or to report an error:</p>
<pre>
&lt;script type="text/javascript&gt;
parent.reportSubmissionError("Unable to process contact id XYZ");
&lt;/script&gt;
</pre>
<p>And the final piece on the client side is how to report the progress &#8211; this is made easy by the fact that ExtJS includes a decent-looking progress bar:</p>
<ul>
<li>To initialize it:</li>
<pre>
_percent = 0;
_errorText = "";
_progressText = "Contacting server...";
_progress = Ext.MessageBox.show({
  title: "Sync Progress",
  width: $(window).width() * .6,
  progress: true,
  progressText: _progressText
});
</pre>
<li>To report progress:</li>
<pre>
function reportSubmissionProgress(percent, description){
  _percent = percent / 100;  // Ext % goes from 0 to 1
  _progressText = description;
  Ext.MessageBox.updateProgress(percent, description);
}
</pre>
<li>To report an error:</li>
<pre>
function reportSubmissionError(error){
  _errorText += (error + "");
  Ext.MessageBox.updateProgress(_percent, _progressText, _errorText);
}
</pre>
<li>And finally to hide it:</li>
<pre>
function reportSubmissionComplete() {
  Ext.MessageBox.hide();
}
// this will ensure the progress bar gets hidden once the iframe finishes loading
document.getElementById("bulkRequestSubmitFrame").onload = reportSubmissionComplete;
</pre>
<p>It looks like this:</p>
<p><img src="http://img405.imageshack.us/img405/8184/progressbarcx.png" alt="Progress Bar"/></p>
<p>The last piece of the puzzle is the handler on the server side, but this is also the easiest one.  You can use a generic ASP.NET handler (ASHX) and just make sure you turn off buffering (context.Response.Buffer = false) and set an HTML content type (context.Response.ContentType = &#8220;text/html&#8221;) then use context.Response.Write to report the progress&#8230; to test it out, try something like:</p>
<pre>
public class TestHandler : IHttpHandler, IReadOnlySessionState
{
  public bool IsReusable { get { return false; } }
  public void ProcessRequest(HttpContext context) {
    context.Response.ContentType = "text/html";
    context.Response.Buffer = false;
    for(int i=0; i < 100; i++){
      context.Response.Write(String.Format(@"&lt;script type='text/javascript'&gt;
          parent.reportSubmissionProgress({0}, 'Reporting progress {0}...');
      &lt;/script&gt;", i));
      Thread.Sleep(300);
    }
    context.Response.Write(@"&lt;script type='text/javascript'&gt;
         parent.reportSubmissionComplete();
      &lt;/script&gt;");
  }
}
</pre>
<p>That's about it.  It ends up being a good fit if you already have some javascript to drive some of the UI on your page.  It's quite flexible and the way it works makes it easy to understand and troubleshoot using a tool like Fiddler or Firebug.</p>
<p>Remember that if the process is <b>really</b> lengthy, or if it is likely that many people will be doing it at the same time, you'll want to do that <b>outside of the web client</b>, because it will consume an ASP.NET thread and a connection handle as long as that connection is open.  Then you have to use a separate service and use a polling mechanism to check on the progress, otherwise your server will grind to a halt as all its processes are stuck serving users - FYI, yes, this is based on first-hand experience.  I recommend reading <a href="http://msdn.microsoft.com/en-us/library/ff647787.aspx">Improving ASP.NET Performance</a> on the Microsoft P&#038;P site, especially the section on threading (the whole thing is worth a read though). </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2011/01/29/enhancing-a-lengthy-process-with-a-progress-bar/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tracking changes in related SalesLogix entities</title>
		<link>http://blog.nicocrm.com/2011/01/19/tracking-changes-in-related-saleslogix-entities/</link>
		<comments>http://blog.nicocrm.com/2011/01/19/tracking-changes-in-related-saleslogix-entities/#comments</comments>
		<pubDate>Thu, 20 Jan 2011 04:42:48 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Saleslogix]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=459</guid>
		<description><![CDATA[I have been doing a bit of exploration via trial and error and wanted to post my findings here. Note all of those were found on SLX 7.5.2. Say you want to audit changes in an entity related to the main entity of your form&#8230; for example in my case ticket.Contact (the customer can edit [...]]]></description>
			<content:encoded><![CDATA[<p>I have been doing a bit of exploration via trial and error and wanted to post my findings here.  Note all of those were found on SLX 7.5.2.</p>
<p>Say you want to audit changes in an entity related to the main entity of your form&#8230; for example in my case ticket.Contact (the customer can edit the contact&#8217;s first name from the ticket screen), or this would probably work the same with the address control on the account main view.  You may run in the following issues:</p>
<ul>
<li>If you don&#8217;t make any change to the main entity itself, its Update event will not get called.</li>
<li>The Update event of the related entity will not get called</li>
<li>When you try to retrieve the changes for the related entity, you can&#8217;t simply do &#8220;<i>((IChangedState)ticket.Contact).GetChangedState()</i>&#8221; &#8211; this will return an empty change set.  Instead you have to go through the member changes of the main entity.</li>
</ul>
<p>Not much can be done about the first 2 items unfortunately &#8211; the event is just not getting triggered.  This means you have to call the method to track the changes from the application code unfortunately for the time being (hopefully it will get fixed soon since it creates a pretty big hole in sdata applications &#8211; I have not tested to see if it was on 7.5.3).  In the meantime let me elaborate on the last point.  The main entity (e.g. ticket) keeps tracks of changes to related entities in its own ChangeSet.  To retrieve changes on one of those linked entity you can use the Find() method of the ChangeSet to retrieve an EntityChange object.  For some reason it does not allow one to retrieve this EntityChange using the property name (such as what you might use for <i>FindPropertyChange</i> or <i>FindMemberChange </i>), but since you already know the id and it will be unique you can just use something like</p>
<pre>
EntityChange customerChange = changes.Find<EntityChange>(x =>
          (String)x.ChangedEntity.EntityId == (String)ticket.Contact.Id);
if (customerChange == null)
    return;
</pre>
<p>From there, retrieve a ChangeSet using <i>customerChange.ChangedEntity.EntityChanges</i>, and you can manipulate that one like a regular ChangeSet:</p>
<pre>
ChangeSet changes = customerChange.ChangedEntity.EntityChanges;
PropertyChange nameChange = changes.FindPropertyChange("FirstName");
</pre>
<p>For a more deeply linked entity like <i>ticket.Contact.Address</i> it is also retrieved from the ticket entity&#8217;s ChangeSet:</p>
<pre>
EntityChange addressChange = changes.Find<EntityChange>(x =>
    (String)x.ChangedEntity.EntityId == (String)ticket.Contact.Address.Id);
</pre>
<p>Hope this helps!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2011/01/19/tracking-changes-in-related-saleslogix-entities/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Confirmation prompt in SalesLogix Web</title>
		<link>http://blog.nicocrm.com/2011/01/06/confirmation-prompt-in-saleslogix-web/</link>
		<comments>http://blog.nicocrm.com/2011/01/06/confirmation-prompt-in-saleslogix-web/#comments</comments>
		<pubDate>Thu, 06 Jan 2011 19:30:32 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=448</guid>
		<description><![CDATA[A lot of time in the LAN client I have some logic similar to this snippet (which updates the account manager to match the region selected by user in a picklist): sUser = GetField("userid", "userinfo", "region = '" &#038; Sender.Text &#038; "'") If sUser lueAccMgr.LookupID Then If MsgBox("Would you like to change the account manager [...]]]></description>
			<content:encoded><![CDATA[<p>A lot of time in the LAN client I have some logic similar to this snippet (which updates the account manager to match the region selected by user in a picklist):</p>
<pre>
sUser = GetField("userid", "userinfo", "region = '" &#038; Sender.Text &#038; "'")
If sUser <> lueAccMgr.LookupID Then
  If MsgBox("Would you like to change the account manager to match selected region?", vbOkCancel) = vbOk Then
   lueAccMgr.LookupID = sUser
  End If
End If
</pre>
<p>In the web client you would want to do something like this:</p>
<pre>
IUser user = GetUserByRegion(CurrentEntity.Region);
if(user != CurrentEntity.AccountManager){
  if(PromptUserForConfirmation()){
    CurrentEntity.AccountManager = user;
  }
}
</pre>
<p>But how to implement the &#8220;PromptUserForConfirmation&#8221; method?  You can&#8217;t do a modal dialog box from server-side code.</p>
<p>One method would be to implement all of the logic from client side.  You can use an ajax call (maybe using sdata) to implement the &#8220;GetUserByRegion&#8221; in Javascript, and probably in this particular case it would be simple enough to be very feasible.</p>
<p>Sometimes there is a bit too much logic on the server side to be ported over to javascript, or you just don&#8217;t want to have to load too much logic on the client (which is often harder to maintain).  In that case you can use what I call the &#8220;hidden button&#8221; trick.  This keeps most of the logic on the server and separate the process in 2 steps, using a non-displayed button on the client to allow the script to &#8220;resume&#8221;.  The button on the page would be something like (make sure you do &#8220;display: none&#8221;, not &#8220;Visible=false&#8221;, as the latter would prevent the button from being output on the page at all):</p>
<pre>
&lt;asp:Button style="display:none" runat="server" id="btnConfirmRegionManagerChange" OnClick="btnConfirmRegionManagerChange_Click"/&gt;
</pre>
<p>The code on the picklist change event would become:</p>
<pre>
// first postback, executes when the user has just made the picklist change
// (assuming the picklist is set up to autopostback)
// here we run the first part of the logic
IUser user = GetUserByRegion(CurrentEntity.Region);
if(user != CurrentEntity.AccountManager){
  // register a client script to show confirmation prompt and simulate a button click
  ScriptManager.RegisterStartupScript(this, GetType(), Guid.NewGuid().ToString(),
   "if(confirm('Would you like to change the account manager to match selected region?')) " +
     "$('#" + btnConfirmRegionManagerChange.ClientID + "').click();", true);
}
</pre>
<p>And finally the handler for the btnConfirmRegionManagerChange click would take care of the second part of the process:</p>
<pre>
// Here we just call the GetUserByRegion method again...
// If there was a lot of processing involved you could cache the result from the previous postback
// into a hidden field or a ViewState variable
IUser user = GetUserByRegion(CurrentEntity.Region);
CurrentEntity.AccountManager = user;
</pre>
<p>This way you have a bit of extra work, but the basic structure of the code remains the same so it is still easy to follow.  I should mention I have not actually tried the code snippets above so if you copy / paste and find any typo please let me know.</p>
<p>Hope this helps!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2011/01/06/confirmation-prompt-in-saleslogix-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ad-hoc REST services on the force.com platform</title>
		<link>http://blog.nicocrm.com/2010/12/05/ad-hoc-rest-services-on-the-force-com-platform/</link>
		<comments>http://blog.nicocrm.com/2010/12/05/ad-hoc-rest-services-on-the-force-com-platform/#comments</comments>
		<pubDate>Sun, 05 Dec 2010 20:31:49 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Force.com]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=428</guid>
		<description><![CDATA[Note &#8211; as of Summer &#8217;11 there is a much better solution in the form of Javascript Remoting. I am leaving the information below for reference but do not recommend using it. Force.com is coming up with a REST style api to access the data from 3rd party applications, widgets etc. While this is great [...]]]></description>
			<content:encoded><![CDATA[<p><b>Note &#8211; as of Summer &#8217;11 there is a much better solution in the form of Javascript Remoting.  I am leaving the information below for reference but do not recommend using it.</b><br />
<br/><br/></p>
<p><a href="http://developer.force.com/REST">Force.com</a> is coming up with a REST style api to access the data from 3rd party applications, widgets etc.  While this is great news as this type of web services is a lot easier to access than traditional SOAP calls from many programming languages (including obviously the important Javascript), it should not be forgotten that it has been possible for a while already to create your own, custom REST-style services &#8211; very useful when trying to make a page more responsive by coding certain areas in Javascript with AJAX calls.  These don&#8217;t benefit from the OAuth authentication so they are more useful for pages that are accessed by already authenticated users.  One advantage is that as they are very specialized you can make the payload as lean as necessary.  One drawback is that as the facilities of the native Force.com programming environment are a bit rudimentary there is a certain amount of boiler-plate code involved.</p>
<p>The controller side looks like a usual controller, typically using the query-string or form parameters in the constructor to build a result which is then available to the view.  The view can loop over that result and output it in JSON format using the built-in JsEncode function.  For example here is a simple contact search service:</p>
<pre>
public with sharing class SearchServiceController {
	/**
	 * Array containing the results.
	 */
	public Contact[] Matches { get; private set; }

        /*
         * grab the parameter from the page's and run the search.
         */
        public void executeSearch() {
		String name = ApexPages.currentPage().getParameters().get('name');
		executeSearch(name);
        }

	/**
	 * Run the search with the specified parameters, populating the Matches variable.
	 */
	public void executeSearch(String name){
		Matches = [select Id, Name, MailingStreet, MailingCity, Mailing State from Contact where LastName=:name];
        }
}
</pre>
<p>Then the view could look something like this&#8230; most modern programming languages have constructs for automatically serializing to JSON nowadays, but not Apex &#8211; still, it&#8217;s not that hard to get the same result on the view:</p>
<pre>
&lt;apex:page contentType=&quot;text/javascript&quot; controller=&quot;ProximitySearchServiceController&quot; action=&quot;{!executeSearch}&quot; &gt;
&lt;apex:variable var=&quot;rowIndex&quot; value=&quot;{!0}&quot;/&gt;
{&quot;result&quot;:[
    &lt;apex:repeat value=&quot;{!Matches}&quot; var=&quot;contact&quot; &gt;
        &lt;apex:outputText rendered=&quot;{!rowIndex != 0}&quot; value=&quot;,&quot;/&gt;
        {&quot;name&quot;:&quot;{!JsEncode(contact.Name)}&quot;,
         &quot;address1&quot;:&quot;{!JsEncode(contact.MailingStreet)}&quot;,
         &quot;city&quot;:&quot;{!JsEncode(contact.MailingCity)}&quot;,
         &quot;state&quot;:&quot;{!JsEncode(contact.MailingState)}&quot; }
         &lt;apex:variable var=&quot;rowIndex&quot; value=&quot;{!rowIndex+1}&quot;/&gt;
    &lt;/apex:repeat&gt;
]}
&lt;/apex:page&gt;
</pre>
<p>Not exactly rocket science, but that&#8217;s kind of the point: the beauty of REST is that it simply leverages the existing HTTP protocol without the added baggage (both in payload and complexity) of an RPC protocol.  Perhaps the only tricky part in the force.com version is the output of the comma in the right position (remember a trailing comma in a list works fine in FireFox but not in IE).  There is no out of the box facility for getting the row index in the repeater.  Also, don&#8217;t forget to set the contentType so that the default page headers don&#8217;t get included.  And don&#8217;t forget to disable the development mode on the page&#8230;  other, the HTML for the page editor will still get sent and mess with the JSON output!</p>
<p>Lastly a little security note&#8230; such services are not wide open because they require the user to be logged into Salesforce.  However, it is possible for an attacker who controls a web site that is visited by a Salesforce user to submit a request on their behalf (including their authentication cookies).  They won&#8217;t be able to retrieve the results, but if the service causes an update or an insert that could happen.  If it&#8217;s a concern (e.g. for an ordering system) you can check the HTTP referer using ApexPages.currentPage().getHeaders().get(&#8216;Referer&#8217;), and make sure it comes from an expected site / page.  Some good notes about that on the <a href="http://blog.sforce.com/sforce/2011/06/csrf-and-apexpage.html?utm_source=feedburner&#038;utm_medium=feed&#038;utm_campaign=Feed%3A+SforceBlog+%28Force.com+Blog%29">force.com blog</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2010/12/05/ad-hoc-rest-services-on-the-force-com-platform/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>(mis)adventures with the Dojo build system</title>
		<link>http://blog.nicocrm.com/2010/12/05/misadventures-with-the-dojo-build-system/</link>
		<comments>http://blog.nicocrm.com/2010/12/05/misadventures-with-the-dojo-build-system/#comments</comments>
		<pubDate>Sun, 05 Dec 2010 16:00:05 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Dojo]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=419</guid>
		<description><![CDATA[Dojo has this amazing tool as part of their framework which is kind of a all-in-one shop for all your Javascript and CSS optimization needs. It&#8217;s called the Dojo Build System. It uses the dojo.require statements that are part of the module definition to figure out the combination of Javascript files that will include everything [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://dojotoolkit.org">Dojo</a> has this amazing tool as part of their framework which is kind of a all-in-one shop for all your Javascript and CSS optimization needs.  It&#8217;s called the Dojo Build System.  It uses the <b>dojo.require</b> statements that are part of the module definition to figure out the combination of Javascript files that will include everything needed, but not more, to minimize both the total size of data transferred and the number of connections necessary to do so.</p>
<p>Overall it works great and there are a few good examples that show how to use it as part of their documentation.  I did run into a few pitfalls mostly due to the assumption it makes about the directory layout which I thought I should document here for the benefit of Google and Nick-from-the-future.</p>
<ol>
<li>Although not mentioned explicitly, if you specify a CSS optimization level, the tool will optimize all CSS files it finds in the folder.  I spent a while looking for a switch that would let me specify which CSS files to pick up before realizing that.</li>
<li>A little catch: the output of the Javascript optimization is to be found under the &#8220;release/dojo&#8221; folder, <b>not</b> &#8220;release/yourmodule&#8221; as you might expect.</li>
<li>It is quite sensitive to syntax errors and the error messages are really not very good&#8230; so make sure the Javascript in the files is all good&#8230; especially when you also take into account the fact that the tool takes a while to run because it re-processes the whole Dojo distribution every time (I wish there was a way to do an incremental build but I have not figured out how).</li>
<li>The tool <b>must</b> be run from within the correct folder (util/buildscripts in the dojo source distro).  Most of the examples in the documentation have you place your module folder (or create a symlink to it) within the dojo source folder&#8230; this is pretty messy and confusing, and makes the upgrade of dojo harder because if you pick up a new release you have to remember to create the appropriate symlinks.  There is however an example directory layout that works well and keeps things separated on <a href="http://docs.dojocampus.org/build/simpleExample">DojoCampus</a>.  They also provide a sample shell script there that makes invoking the tool a lot easier.  It is also good to show the various <b>important</b> parameters for the build.</li>
<li>Along the same lines: be careful with symlink, as the tool does a lot of &#8220;..&#8221; to get to the various files&#8230; so if the folder is a symlink the tool might walk itself out of the directory structure.</li>
<li>Even once the Javascript file is flattened, one thing to remember is the localization messages are still loaded separately (the assumption is that the system won&#8217;t know what language to load until runtime).  If desired (if only one language is needed) it can be concatenated to the output file, and then the locale can be fixed in the djConfig parameter.</li>
<li>Finally, an error that I spent quite a while to debug: if the &#8220;releaseDir&#8221; contains a &#8220;..&#8221; in its path, then the build errors out with:
<pre>
js: "./jslib/i18nUtil.js#61(eval)", line 1: uncaught JavaScript runtime exception: SyntaxError: missing name after . operator

js: dijit..var.www.nicocrm.test.spx....spxRelease.release.dijit._editor
</pre>
<p>Oh well, now I know.  Apparently there is a similar <strike>bug</strike> misfeature if you include a backslash on the path name (if you do the build on Windows).  I can&#8217;t speak for that one for sure as I only tried it on Linux so far.
</li>
</ol>
<p>Once I got past those problems all was good &#8211; inline CSS and Javascript, inline templates, all comments stripped, and the Javascript is compressed.  You should only need 2 scripts included per page: the &#8220;base&#8221; dojo.js which is normally included on every page thus will be cached, and the &#8220;layer&#8221; script which is created based on the modules that are needed on that specific page.  For CSS you might have 3 files: the base dojo.css, the theme, and the layer file (I suppose you might combine the theme and base dojo stylesheets, for an even more optimized build).  Unfortunately however the tool does not appear to do CSS sprite optimization yet.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2010/12/05/misadventures-with-the-dojo-build-system/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Free Amazon EC2 instance</title>
		<link>http://blog.nicocrm.com/2010/11/21/free-amazon-ec2-instance/</link>
		<comments>http://blog.nicocrm.com/2010/11/21/free-amazon-ec2-instance/#comments</comments>
		<pubDate>Sun, 21 Nov 2010 18:38:11 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/?p=412</guid>
		<description><![CDATA[Throwing it out there as I did not know about it &#8211; Amazon is offering a free tier for its Elastic Cloud services. It&#8217;s available at http://aws.amazon.com/free. Only for the Linux &#8220;micro&#8221; instance, and only for a year, but it&#8217;s still very nice for me (mainly so I can avoid problems like waiting for 2 [...]]]></description>
			<content:encoded><![CDATA[<p>Throwing it out there as I did not know about it &#8211; Amazon is offering a free tier for its Elastic Cloud services.  It&#8217;s available at <a href="http://aws.amazon.com/free">http://aws.amazon.com/free</a>.  Only for the Linux &#8220;micro&#8221; instance, and only for a year, but it&#8217;s still very nice for me (mainly so I can avoid problems like <a href="http://twitter.com/#!/NicoGaller/status/23200370096">waiting for 2 weeks for a new fan</a>).  The one thing that I found was rather dumb is I had to create a new account for it as it was reserved to new users and I had previously used Amazon S3 on my main account (why ever do people make these &#8220;new customers only&#8221; offers &#8211; are they really trying to alienate the existing customer base?).  Also be careful not to make the same mistake I made &#8211; this pricing only applies to the &#8220;basic&#8221; Linux install, not the Suse or CentOS builds.</p>
<p>Also not sure when they added the Windows &#8220;Micro&#8221; instance &#8211; not part of this free tier but at $.03/hr that would be very economic way to run a small site if you need a bit more control than with an ASP.NET host (no, I very much doubt you can run SalesLogix on it, hah).  It comes off quite a bit cheaper than MS Azure and I am not too sure what Azure buys you for the extra cost.  Will be an interesting competition to watch in the coming months.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2010/11/21/free-amazon-ec2-instance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Check Your Relations</title>
		<link>http://blog.nicocrm.com/2010/10/17/check-your-relations/</link>
		<comments>http://blog.nicocrm.com/2010/10/17/check-your-relations/#comments</comments>
		<pubDate>Sun, 17 Oct 2010 19:44:39 +0000</pubDate>
		<dc:creator>Nicolas Galler</dc:creator>
				<category><![CDATA[Saleslogix]]></category>

		<guid isPermaLink="false">http://blog.nicocrm.com/2010/10/17/check-your-relations/</guid>
		<description><![CDATA[A familiar problem with upgrades from SalesLogix LAN to Web is many of the foreign keys may have some invalid values.&#160; The legacy LAN client allowed one to put basically anything in there without much validation since we were playing with raw SQL, but the NHibernate platform used in the new client is not as [...]]]></description>
			<content:encoded><![CDATA[<p>A familiar problem with upgrades from SalesLogix LAN to Web is many of the foreign keys may have some invalid values.&#160; The legacy LAN client allowed one to put basically anything in there without much validation since we were playing with raw SQL, but the NHibernate platform used in the new client is not as forgiving.&#160; Therefore you may find yourself with this type of errors:</p>
<blockquote><p><font face="Courier New">System.Web.HttpUnhandledException: Exception of type &#8216;System.Web.HttpUnhandledException&#8217; was thrown. &#8212;&gt; System.Reflection.TargetInvocationException: Property accessor &#8216;Ticket&#8217; on object &#8216;Sage.SalesLogix.Entities.TLXProjectExpense&#8217; threw the following exception:&#8217;No row with the given identifier exists[Sage.SalesLogix.Entities.Ticket#&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ]&#8216; &#8212;&gt; NHibernate.ObjectNotFoundException: No row with the given identifier exists[Sage.SalesLogix.Entities.Ticket#&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ]</font></p>
</blockquote>
<p>What happened here is the original developer chose an empty string instead of a NULL to indicate the absence of a value – it works fine on the LAN client but the web client tries to actually load a ticket with an id of “&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; “.&#160; The solution recommended so far is to clean out those values as you find them… obviously not very practical in an upgrade where you could have dozens of foreign key relationships to check one by one.</p>
<p>Thankfully all the information we need to get around the problem is already stored by SalesLogix and collected in the entity model – so all we have to do in theory is crawl through the relationships defined in the App Architect and run an update for each one of them.&#160; It is actually quite easy as Sage prepared some neat (albeit undocumented) API to examine the model metadata.&#160; For example this is the code I used to load the project model and iterate through the relationships:</p>
<pre class="csharpcode">IProject project = ProjectUtility.InitProject(ModelPath);
OrmModel model = project.Models.Get&lt;OrmModel&gt;();
<span class="kwrd">foreach</span> (OrmRelationship relationship <span class="kwrd">in</span> model.Relationships)
{
  <span class="rem">// ...</span>
}</pre>
<p><font face="Calibri">It took me a few hours to write the app, mostly because I had set out to learn a few more things about WPF at the same time – the logic for the check and update itself was pretty easy.  The one caveat is there are a few relationships that are a bit “odd” and can’t get fixed right (for example the M:1 relationship from targetresponse to MKTGSVC_RECIPIENT is on TargetResponseId which we can’t null out)</font></p>
<p><font face="Calibri">For now it is usable as a standalone app… Eventually I would like to make it as an App Architect extension and add a few features (most importantly the ability to drill down to see the actual data for the invalid records)</font></p>
<p><a href="http://blog.nicocrm.com/wp-content/uploads/2010/10/image2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.nicocrm.com/wp-content/uploads/2010/10/image_thumb2.png" width="551" height="520" /></a></p>
<p><font face="Calibri">For the source code I made it available as part of the <a href="http://github.com/nicocrm/OpenSlx">OpenSlx</a> project on GitHub, but the binaries can be downloaded <a href="http://blog.nicocrm.com/wp-content/uploads/2010/10/OpenSlx.RelationCheck.zip">here</a> if you want to give it a try (obviously be sure to backup the DB beforehand etc &#8211; the &#8220;no warranty&#8221; disclaimer is there for a reason!)  One big caveat there before I forget &#8211; if you have problems with invalid Seccodeid in the Secrights table, etc, you may have to do some cleanup before and/or after running the script as it will null them out which will crash the client.</font></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nicocrm.com/2010/10/17/check-your-relations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

