tag:blogger.com,1999:blog-60795132487164655842024-03-14T09:44:40.958+02:00Brainstorming on Dynamics xRMSome thoughts and ideas we came across while implementing Microsoft Dynamics CRM based solutions.Adrian Alexanhttp://www.blogger.com/profile/17317209225153263239noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-6079513248716465584.post-39468067021422984032009-12-12T20:31:00.022+02:002009-12-26T17:34:53.125+02:00Customize Dynamics CRM 4.0 entities print preview forms<span style="font-size:x-small;color:#b45f06;"><em><strong>(Changing the entity’s default print preview to a custom implementation)</strong></em></span><br /><br />One of the most annoying drawback which was raised by my clients ever since CRM 3.0, was the dull and inflexible print preview form of CRM entities. Needing to print out every day several types of records on such print previews and file them, turned out to be a real burden using the default print preview.<br /><br />The main complaints were about:<br />- the layout of the print preview form is not customizable (layout, position of fields, adding or removing fields etc)<br />- the look (the design) cannot be customized (e.g. adding a company logo, colors, fonts, etc)<br />- the child collections’ information cannot be added to the print preview screen<br /><br />One of the most efficient approaches to implement your own print preview page for any entity form is to perform the following steps:<br />1. create a custom CRM / SSRS report to be used as print preview for that entity<br />2. update the <span style="font-family:'Courier New', Courier, monospace;">form.crm.htc</span> file with a code which checks if there is a custom report defined for the current entity to be loaded instead of the default print preview. In case there is one, the customization will load that report page instead of running the default print preview page.<br /><br />- Add in <span style="font-family:'Courier New', Courier, monospace;">Global.js</span> file an array with the entities supporting custom reports for print preview:<br /><br /><pre class="brush: js">var PrintPreviewReports = new Array(); PrintPreviewReports[Lead] = "Print Leads"; //This is the report name</pre><br /><br />- Add the following code in the <span style="font-family:'Courier New', Courier, monospace;">form.crm.htc</span> at the beginning of <span style="font-family:'Courier New', Courier, monospace;">Print()</span> function:<br /><br /><pre class="brush: js">if(PrintPreviewReports!=null && PrintPreviewReports[_oSubmitForm.crmFormSubmitObjectType.value]!=null) { RunReport(true, PrintPreviewReports[_oSubmitForm.crmFormSubmitObjectType.value], "", _oSubmitForm.crmFormSubmitObjectType.value, PrintPreviewReports[_oSubmitForm.crmFormSubmitObjectType.value]+".rdl", 1);}</pre><br /><br /><br />The approach is rather simple for a developer; once the customization has been set in place and you have a first model for a report, then it should take about 30 minutes per each new report to implement in order to be used as entity print preview.<br /><br />Here’s the sample screen for this solution in production:<br /><br /><div style="TEXT-ALIGN: center; CLEAR: both" class="separator"><a style="MARGIN-BOTTOM: 1em; FLOAT: left; CLEAR: left; MARGIN-RIGHT: 1em; cssfloat: left" title="The default print preview page" href="http://sites.google.com/site/adrianalexanblog/img/PrintPreview-Default.gif" rel="lightbox[5.print]" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcBOnwzDNv0tYXl2C-Bevf9eKZyqvdcvqtnUSD8Od1K09lilReGXITs6xEjOys8Po8g9-he5YD8uuXeWSg0V15sD-pVWZD4WAWLVmHIR6H_zovWh4MvrQyUTPo_L-kMARS0gxwdBbNLfo/s320/PrintPreview-Custom.gif" ps="true" /></a><br /></div><a title="The custom 'Print preview' report being loaded when the Print button of the form is clicked." href="http://sites.google.com/site/adrianalexanblog/img/PrintPreview-Custom.gif" rel="lightbox[5.print]"></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />That’s it. Let me know if you find this useful.<br /><br />A+Adrian Alexanhttp://www.blogger.com/profile/17317209225153263239noreply@blogger.com6tag:blogger.com,1999:blog-6079513248716465584.post-77311751592409527482009-12-12T00:08:00.026+02:002009-12-12T14:36:38.151+02:00Manage email campaigns efficiently from CRM<span style="color: #b45f06; font-size: x-small;"><em><strong>(A low-cost but more powerful solution for handling email campaigns from CRM by integrating an external emailing tool)</strong></em></span><br />
<br />
There are several good solutions out there which come as CRM extensions designed to manage the emailing campaigns in CRM. However, none of them seem to offer the same range of functionalities (managing, tracking, reporting etc) as a dedicated mailing tool would.<br />
<br />
Given this reasoning, I’ve concluded that the most satisfying approach to handle this case is to integrate / automate an external dedicated tool designed to handle mailing campaigns.<br />
<br />
A brief list of advantages for using an external mailing tool are:<br />
- The price of a campaign mailing tool is in the same range (sometimes even lower) with a CRM extension’s price<br />
- The list of features (especially editing, tracking and reporting) of a mailing tool is generally far wider then the features list of a 3rd party CRM extension.<br />
- The mailing tools follow generally an evolution roadmap from its producer so that upgrading your application instance on a regular basis could get you a new set of improvements & fixes.<br />
<br />
The custom integration of an external mailing tool should consider the following points:<br />
- pick a mailing tool having a web-based UI <br />
- the domain model of the chosen tool should be similar to the one of CRM’s (e.g. have the same notions of campaign, mailing list, subscribers etc)<br />
- the campaign in CRM should have a customization (e.g. a button) to export it towards the external tool<br />
- the campaign in CRM should be automatically updated every time when a change of its counterpart in the external tool occurs (e.g. status of the campaign, recipients unsubscriptions, campaign stats etc.)<br />
<br />
This list of integration points above should be kept small and should not take more than 3...5 man-days to implement for a CRM developer.<br />
Once the bidirectional integration between the two systems is up, you could benefit from all the feature of your mailing tool and have direct access to each external campaign screen from the CRM campaign editing form.<br />
<br />
Here are some screenshots of such an integration in production. I used here a good money-for-value tool called <a target="Oempro" href="http://octeth.com/oempro" title="OemPro website">OemPro</a> which managed to cover a wide range of my client's requirements.<br />
<br />
<div align="left" class="separator" style="clear: both; text-align: center;"><a href="http://sites.google.com/site/adrianalexanblog/img/CampaignToOemPro.gif" imageanchor="1" rel="lightbox[4.Campaign]" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;" title="Export the CRM campaign to OemPro"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKwA29SghPRu0fmBI88RptkCDyzdUWxay3wsYdmgpx5uUD2RXs2re9wOBX8wWlpbfBL8ZPpUAgJCKU3YrMSpd636xra7Tp6f0vd-gPY24_hLBcmSu8lK3nBsIm-Ulsnuo_YOuzS_xc_os/s400/CampaignToOemPro.gif" yr="true" /></a><br />
</div><a href="http://sites.google.com/site/adrianalexanblog/img/CampaignToOemPro2.gif" rel="lightbox[4.Campaign]" title="Export the CRM campaign to OemPro"></a><br />
<a href="http://sites.google.com/site/adrianalexanblog/img/CampaignToOemPro3.gif" rel="lightbox[4.Campaign]" title="CRM campaign is synchronized with OemPro and can be configured."></a><br />
<a href="http://sites.google.com/site/adrianalexanblog/img/OemPro.gif" rel="lightbox[4.Campaign]" title="Take advantage of the extensive capabilities of OemPro"></a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
That’s it. Let me know if you find this useful.<br />
<br />
A+Adrian Alexanhttp://www.blogger.com/profile/17317209225153263239noreply@blogger.com3tag:blogger.com,1999:blog-6079513248716465584.post-22272437204655278832009-12-01T16:10:00.008+02:002009-12-01T16:33:29.139+02:00HTML WYSIWYG editors in CRM Forms: A non-intrusive approach<span style="color: #b45f06; font-size: x-small;"><em><strong>(Transforming a text area field of a Dynamics CRM form into a HTML editor, using a non-intrusive way)</strong></em></span><br />
<br />
<br />
You might have already came across the need to have some of your text fields in the CRM forms support HTML code. There are several solutions out there on how to handle this point, but in this article I’d like to focus on the approach I prefer: the most non-intrusive approach.<br />
<br />
The main idea is to define my CRM text fields to be displayed as text areas (from the entity’s customizations section) and at runtime - on form load - have some of these fields (the ones which need to store HTML strings) get decorated with a WYSIWYG HTML editor. Consequently, no server side code or other special handling of these fields would be required, but, unlike other solutions you might find, no further client-side code to be executed on form save event is required either.<br />
<br />
Here are the steps to implement it:<br />
<br />
1. Take a JS-based HMTL editor with the capability to render itself around an existing text area control (instead of letting the control creating a new element in the document).<br />
I used for this purpose the <a href="http://www.openwebware.com/" target="openWYSIWYG">openWYSIWYG</a> editor.<br />
Download the code and include a reference to the editor's JS file from your <span style="font-family: "Courier New", Courier, monospace;">Global.js</span> file.<br />
<br />
2. Have the OnLoad events of the forms execute the initiation code for each text area which needs to be transformed into HTML editors.<br />
<br />
That's it.<br />
<br />
<br />
Here’s a screenshot of this implementation in production:<br />
<br />
<div align="left" class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNv1jZKYcq5kBqP7VdWmJS2BFyfg-f4IA19QarhRFdVODw9_OYzGHDi_A5QQHPnfSkpxyuhc46wniqJiGfXwudbQpzoTeBLSaDvk4kee5r5TVNz-vlZKzzX3tf7Fm_3mndtP45xc6DxkY/s1600/HTMLEditor.gif" imageanchor="1" rel="lightbox[3.HTML]" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;" title="A non-intrusive HTML editor on top of a textarea field in CRM form"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNv1jZKYcq5kBqP7VdWmJS2BFyfg-f4IA19QarhRFdVODw9_OYzGHDi_A5QQHPnfSkpxyuhc46wniqJiGfXwudbQpzoTeBLSaDvk4kee5r5TVNz-vlZKzzX3tf7Fm_3mndtP45xc6DxkY/s400/HTMLEditor.gif" yr="true" /></a><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Let me know if you find this useful.<br />
<br />
A+Adrian Alexanhttp://www.blogger.com/profile/17317209225153263239noreply@blogger.com2tag:blogger.com,1999:blog-6079513248716465584.post-13501098303495705432009-11-28T23:40:00.025+02:002009-12-01T15:32:30.657+02:00Dynamics CRM Grid customizations - virtually anything possible<span style="color: #b45f06; font-size: x-small;"><em><strong>(A quick guide on how to dynamically modify the look and content of a Dynamics CRM Grid)</strong></em></span><br />
<br />
<br />
<strong>Intro</strong><br />
<br />
For each project based on the CRM framework which I dealt with, I had plenty of customer requirements around the grids’ look & behaviors. I’m planning to briefly describe hereby some easy ways to implement some of the most requested customizations. Note that all these customizations are not supported nor compliant with MSCRM SDK.<br />
<br />
One core functionality you’ll need to address in order to be able to implement my samples below and any others you might need around the grid, is to catch the load event of the grid control. Once you’re able to execute your custom function on grid loading event, you can then browse the document’s DOM and dynamically change the look and behavior of any document element including the grid itself.<br />
<br />
<br />
<strong>The code</strong><br />
<br />
A simple way (not the cleanest, I admit) is to define in the <span style="font-family: "Courier New", Courier, monospace;"><strong>/_static/_common/scripts/Globaj.js</strong></span> file an array of functions to be called when the appropriate grid loads:<br />
<br />
<pre class="brush: js">var grid_onGridLoadDelegates = new Array();
grid_onGridLoadDelegates[New_invoice_line] = new_invoice_line_onBeforeGridLoad;
</pre><br />
This code defines the array of functions and then have the function <span style="font-family: "Courier New", Courier, monospace;">new_invoice_line_onBeforeGridLoad(...)</span> called when a grid displaying entities of type “new_invoice_line” gets loaded.<br />
<br />
Then, you’ll need to add several lines in the <span style="font-family: "Courier New", Courier, monospace;">/_static/_grid/AppGrid_DefaultData.htc</span> file, at the end of <span style="font-family: "Courier New", Courier, monospace;">init()</span> function:<br />
<br />
<pre class="brush: js">if(grid_onGridLoadDelegates!=null && grid_onGridLoadDelegates[this.element.oname]!=null)
{
grid_onGridLoadDelegates[this.element.oname].call(this, window, this.element);
}
</pre><br />
Thus, you can already define like this your custom function to be executed when the grid is loaded:<br />
<br />
<pre class="brush: js">function new_invoice_line_onBeforeGridLoad(parentWindow, grid)
{
...
}
</pre><br />
That’s pretty much it! Here are below some examples based on this approach.<br />
<br />
<br />
<strong>Examples</strong><br />
<br />
Have particular column for a boolean field replaced by checkboxes when the grid loads.<br />
<div class="separator" style="clear: both; text-align: center;"><a title="Have particular column for a boolean field replaced by checkboxes when the grid loads." rel="lightbox[2.chk]" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP_Vzv9DfPBHqFQ2ZI9MFdzJTKjFagVuoC8BZJHVsnEmhVjWVmrZ74lnovoyUhjPwizd4tkL2w0apQstsg8cxVqDw9YyzP3L2tD-HP6Pvqvi9xSVlt4Mr4Ncbb_V0dXR02YNBToiPJpKI/s1600/gridcustomizations-checkbox.gif" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" rel="lightbox[2.bool]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP_Vzv9DfPBHqFQ2ZI9MFdzJTKjFagVuoC8BZJHVsnEmhVjWVmrZ74lnovoyUhjPwizd4tkL2w0apQstsg8cxVqDw9YyzP3L2tD-HP6Pvqvi9xSVlt4Mr4Ncbb_V0dXR02YNBToiPJpKI/s400/gridcustomizations-checkbox.gif" yr="true" /></a><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Implement a “Position” column where the numeric value is replaced by Up/Down arrows having actions which perform server side call for recomputing the line’s position and refresh the grid afterwards.<br />
<div class="separator" style="clear: both; text-align: center;"><a rel="lightbox[2.updown]" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjopWwu086Ph12PVkoa9RowHwZGWXihScYhqanB8pmGP-Y_e_2F6S7CFRudsWz_LvGiiOnGLmwXkY8eQxATlI7z2A25wgSw2DBcZi81BiAZwMvEb7SGF1pLwkjP77cF5KX-dGm9YO12R7Y/s1600/gridcustomizations-up-down.gif" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;" title="Implement a 'Position' column where the numeric value is replaced by Up/Down arrows having actions which perform server side call for recomputing the line’s position and refresh the grid afterwards."><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjopWwu086Ph12PVkoa9RowHwZGWXihScYhqanB8pmGP-Y_e_2F6S7CFRudsWz_LvGiiOnGLmwXkY8eQxATlI7z2A25wgSw2DBcZi81BiAZwMvEb7SGF1pLwkjP77cF5KX-dGm9YO12R7Y/s400/gridcustomizations-up-down.gif" yr="true" /></a><br />
</div><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Have some fields in a column displayed in a variable look, depending on the cell value.<br />
<a title="Customize cells content dynamically, depending on the cell value." rel="lightbox[2.format]" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhecqNDgjG4w2EAwauLEorNlwGPGJqv_SIIgn_lxzODg-lEyFBkfg4MLtL-NK2W7OXC4ocEgKni18_eciS5DpLfTgGvMbbzMTqSnqqr5JiEPnJpegOeK36p57USQ0Sawqkd35TnIe9LxJU/s1600/gridcustomizations-formatting.gif" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhecqNDgjG4w2EAwauLEorNlwGPGJqv_SIIgn_lxzODg-lEyFBkfg4MLtL-NK2W7OXC4ocEgKni18_eciS5DpLfTgGvMbbzMTqSnqqr5JiEPnJpegOeK36p57USQ0Sawqkd35TnIe9LxJU/s400/gridcustomizations-formatting.gif" yr="true" /></a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
There you go. Let me know if you find this useful.<br />
<br />
A+Adrian Alexanhttp://www.blogger.com/profile/17317209225153263239noreply@blogger.com3tag:blogger.com,1999:blog-6079513248716465584.post-40190593636774924682009-11-22T15:11:00.003+02:002009-11-23T10:34:21.800+02:00It's time to start listing out what we’ve learned for the past yearsFor the past 4 years I’ve spent most of my time along with my team architecting and delivering small to mid-size solutions based on Microsoft Dynamics CRM 3.0 and 4.0. I had plenty of challenges but also interesting breakthroughs on this road, most of them raised by the clients themselves. Once the license purchased, the clients tended to ask us for more custom business features, going far beyond the original scope of CRM. This is in fact how we ended up delivering real ERPs built on top of the CRM framework rather than CRM solutions. And this was all due to the framework’s flexibility which we ended up exploiting at fullest. We were for sure not the only ones doing this so, at some point along the road, the xRM idea came up...<br />
<br />
I will focus in the next articles describing various techniques and ideas we learned in this process.<br />
<br />
A+Adrian Alexanhttp://www.blogger.com/profile/17317209225153263239noreply@blogger.com0