<?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>Realisable</title>
	<atom:link href="http://www.realisable.co.uk/feed" rel="self" type="application/rss+xml" />
	<link>http://www.realisable.co.uk</link>
	<description>Realisable Software - Data Integration Made Simple</description>
	<lastBuildDate>Tue, 18 Jun 2013 17:45:31 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Integrating WMSs or 3PL with your ERP</title>
		<link>http://www.realisable.co.uk/integrating-wmss-or-3pl-with-erp</link>
		<comments>http://www.realisable.co.uk/integrating-wmss-or-3pl-with-erp#comments</comments>
		<pubDate>Mon, 25 Feb 2013 22:21:35 +0000</pubDate>
		<dc:creator>adrian</dc:creator>
				<category><![CDATA[3PL]]></category>
		<category><![CDATA[Integration]]></category>
		<category><![CDATA[WMS]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1733</guid>
		<description><![CDATA[Introduction Integrating any Warehouse Management System (WMS) or Third Party Logistics (3PL) with an ERP product such as Sage300, Sage200 or X3 is a complex task. Consideration needs to be given to a variety of issues such as: Synchronisation of &#8230; <a href="http://www.realisable.co.uk/integrating-wmss-or-3pl-with-erp">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<h3>Introduction</h3>
<p>Integrating any Warehouse Management System (WMS) or Third Party Logistics (3PL) with an ERP product such as Sage300, Sage200 or X3 is a complex task. Consideration needs to be given to a variety of issues such as:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Synchronisation of stock systems</li>
<li>Integration touch points</li>
<li>Volume &#038; frequency</li>
</ul>
</div>
<p>This blog post draws on our experience of integrating a number of WMS systems with ERP products, and while not necessarily offering any definitive answers, hopes to highlight the potential questions and issues affecting most WMS integrations.</p>
<h3>Stock system</h3>
<p>Unless a WMS has been purpose built to utilise the ERP’s stock system, most WMSs maintain their own stock system, each affected by transactions. The transactional nature of the interaction means the two systems will have natural and unnatural differences brought about by the latency in processing transactions and processing errors.</p>
<p>The integrator&#8217;s job is to make the ERP and WMS stock systems as synchronised as possible, or at least highlight the possible points of difference.</p>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-9-ERP-WMS-Stock.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-9-ERP-WMS-Stock.png" alt="ERP WMS Stock" title="ERP WMS Stock" width="478" height="220" class="aligncenter size-full wp-image-1734" /></a></p>
<h4>Logical partitioning</h4>
<p>Segmenting a warehouse (or ERP) into areas such as the receipt dock, quarantine and pick face makes perfect sense in both the WMS and the ERP. There are two key integration questions which need answering:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Mapping: how do the locations in the ERP and WMS map to each? How does this mapping affect the stock position and availability of stock in the ERP?</li>
<li>Stock movements: when stock is moved in the WMS from one logical area to another, does the movement also need to be reflected on the ERP? Typically, ERPs treat a location as a boundary for sales and purchase order purposes, thus a movement from quarantine to the pick face will need to trigger a corresponding movement in the ERP.</li>
</ul>
</div>
<h3>Time sensitive</h3>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Transactions should be processed in the order they were processed on the WMS. If batching groups of transactions for processing, an alternative is to process all the transactions that add stock to the ERP system before those that decrement stock which limits the scenario where a transaction removes stock required by another operation.</li>
<li>Transactions such as P/O receipts can affect the available to sell value in your ERP, and thus affecting potential sales.</li>
</ul>
</div>
<h3>Decide the integration points</h3>
<p>The obvious candidates for integration are:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Item Master download to the WMS.</li>
<li>Sales Order download, followed by the upload of picking information creating a shipment/invoice in the ERP. Consideration should also be given to the way back orders will be handled.</li>
<li>Purchase Order download, followed by upload of receipt confirmation creating a purchase receipt in the ERP.</li>
<li>Adjustment upload from the WMS to the ERP. Adjustments can take several from write-offs of damaged or end-of-life stock to adjustments made through cycle counts. Be prepared for some heavy debate around the ‘should cycle count adjustments be immediately uploaded/treated as gospel’ question. (They should, but some warehouse managers/business owners seem to have other ideas).</li>
</ul>
</div>
<p>Less obvious or more exotic transactions need some thought:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Transfers: if there are multiple warehouse(s) or the warehouse is partitioned (see logical locations above) a corresponding transfer in the ERP solution will need to be performed.</li>
<li>Customer and supplier returns: typically these are handled manually as the volume and workflow complexity usually means the cost for integration outweighs the benefit.</li>
<li>Kitting: kitting, or light manufacturing, can involve workflow, and the frequency may be too low to warrant integration.</li>
<li>Packaging operations: anything to do with packaging is usually met with a degree of complexity. The purchasing process involves a PO, receiving is done typically at the warehouse door, but thereafter it becomes complex: the receipted goods are consumables, so they cannot be booked into stock, and because of this stock control and management can become more difficult.</li>
</ul>
</div>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-9-WMS-Transaction-Flow.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-9-WMS-Transaction-Flow.png" alt="WMS Transaction Flow" title="WMS Transaction Flow" width="451" height="500" class="aligncenter size-full wp-image-1735" /></a></p>
<h4>Locking and recall</h4>
<p>Consideration may be given to both the workflow of the WMS and ERP products. If for example a sales order starts to be picked in the WMS, does the change in status also need to affect the ERP preventing it from being modified?</p>
<p>Similar considerations need to be given to modifications made to, or deletions of sales and purchase orders in the ERP.</p>
<h4>Inventory transactions</h4>
<p>Inventory transactions by their very nature are more difficult to handle.</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Stock is sensitive: invalid stock levels can trigger exceptions, stock costs particularly for adjustments need to be considered.</li>
<li>Shipments and receipt transactions need to be mapped back to their original order documents. That is, when a line is picked, the same line on the sales order needs to be affected.</li>
</ul>
</div>
<h3>Volume</h3>
<p>Due to the volume and different types of the transactions, the integration must work! Attempting to unpick issues when things go wrong is time consuming, costly and sometimes impossible.</p>
<h3>Batch and serial numbers</h3>
<p>Batch and serial number integration adds complexity as they increase the number of reconciliation points between the WMS and the ERP solution, where each batch or serial number in the WMS must also be present in the ERP. For example, a warehouse managing 200 batch controlled items may be made of a 1000 discrete batches.</p>
<p>There are some variants on batch and serial number processing which can reduce complexity:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Record batches and serials only on the WMS.</li>
<li>Record only batches and serials only on some operations i.e. picking or goods out.</li>
</ul>
</div>
<h3>Methods to integrate</h3>
<p>As described in a <a href="http://www.realisable.co.uk/integration-synchronisation-data-exchange" title="Integration synchronisation data exchange" target="_blank">previous post</a>, we recommend staging tables for data exchange. However, when integrating a 3PL, your method for exchange will be file exchange via FTP/SSH.</p>
<p>When using a staging table, you have the option of using a single table for all transactions or a table for each transaction type. A single table does introduce some degree of abstraction (each field needs to be named FIELD1, FIELD2, etc. which is then logically mapped depending on the transaction type), but it has the major advantage that it can be reconciled more easily and transactions can be easily ordered by date/time.</p>
<h3>Reconciliation</h3>
<p>The ability to reconcile the ERP and WMS stock systems is paramount. We would recommend creating a report which can be run daily, at a time when no-one is using either the WMS or the ERP, comparing the WMS &#038; ERP stock levels.</p>
<h3>Test, test, test</h3>
<p>It goes without saying that all integrations should be tested, but WMS integrations more so. The number of transactions, the time sensitive nature, and the variety of transactions makes it a difficult beast. Try to cover the following when testing:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Performance: try to mimic the load and volume of transactions performed throughout the day.</li>
<li>Concurrency and multi-user environment: test for scenarios where transactions may be locked by the ERP or the WMS.</li>
<li>Check your audit points and controls: if you need to unpick an error, ensure you’re capturing all the necessary data from the outset.</li>
</ul>
</div>
<h3>Conclusion</h3>
<p>Integrating any WMS is not simple. Consideration needs to be given to a wide variety of issues and integration points where cost is often a factor. With careful planning however, it can be very rewarding: seeing all the transactions tick through is quite nice!
</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/integrating-wmss-or-3pl-with-erp/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Effective use of RVSpy in Sage300 development</title>
		<link>http://www.realisable.co.uk/effective-rvspy-sage300-development</link>
		<comments>http://www.realisable.co.uk/effective-rvspy-sage300-development#comments</comments>
		<pubDate>Tue, 19 Feb 2013 15:43:28 +0000</pubDate>
		<dc:creator>adrian</dc:creator>
				<category><![CDATA[Sage300]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1690</guid>
		<description><![CDATA[Introduction Last week there was a post on the Sage300/Accpac VBA forum asking how to automate the Reversals function in Bank Services. In short the responses were: macro recording didn’t work; the view was clumsy and difficult; and the best &#8230; <a href="http://www.realisable.co.uk/effective-rvspy-sage300-development">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<h3>Introduction</h3>
<p>Last week there was a post on the Sage300/Accpac VBA forum asking how to automate the Reversals function in Bank Services. In short the responses were: macro recording didn’t work; the view was clumsy and difficult; and the best method to automate would be to mimic the entry via SendKeys.</p>
<p>Given that macro recording is not supported by the bank reversals function, it is necessary to use RVSpy to understand the view calls. This post will describe the various tips and tricks we use when we have to use RVSpy, using the reversals example as per the forum post.</p>
<p>A copy of the final source code and the RVSpy log can be found at the bottom of the post.</p>
<h3>Filter the view calls</h3>
<p>By default RVSPY captures all calls which leads to an extremely verbose and sometimes incomprehensible log file. Filtering the view calls to remove all the metadata and get requests will significantly trim the log file to the calls which are most important.</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Filter view calls: Fields, Field, Attribs, Type, Get, Name, Presents, FieldName &#038; FieldExists<br />
<a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-FilterCalls.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-FilterCalls.png" alt="RVSpy FilterCalls" title="RVSpy FilterCalls" width="232" height="318" class="aligncenter size-full wp-image-1694" /></a></li>
<li>Turn off ‘Show Nesting’: Typically you are only interested in calls the UI makes, and not calls views made to other views.<br />
<a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-DisableNesting.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-DisableNesting.png" alt="RVSpy DisableNesting" title="RVSpy DisableNesting" width="336" height="312" class="aligncenter size-full wp-image-1695" /></a></li>
</ul>
</div>
<p>In our example the size of the generated log went from 1.8MB unfiltered to 427KB filtered.</p>
<h3>Recording the entry</h3>
<h4>Finder Fields</h4>
<p>Try to enter the values into each field. Using the finder will significantly add to the log and can make it difficult to understand (see below, for exceptions).</p>
<h4>Use comments</h4>
<p>Before you do something major such as posting, or adding an entry, insert a comment into the log. It will help you later on to identify the event in the log file and will also provide you with a cutoff where major processing is performed by the view.</p>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-Comments.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-Comments.png" alt="RVSpy Comments" title="RVSpy Comments" width="494" height="411" class="aligncenter size-full wp-image-1696" /></a></p>
<h3>The oogily-boogily nature of the Bank Reversals View</h3>
<p>If you look at the Bank Reversals view, you can easily understand the trepidation as it appears to have several purposes:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>As a history, where posted reversals can be queried and retrieved.</li>
<li>The screen supports the ability to select multiple documents to reverse, so there are a range of fields to support the selection process.</li>
<li>Posting of reversals where there are several fields with conflicting names such as BANK/PBANK and SRCEAPP/PSRCEAPP.</li>
</ul>
</div>
<p>The other major issue is around the view protocol: ‘Flat, Ordered Revisions’.</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Flat Protocol: Flat is simply a list or table of records with no hierarchical element; a lot of the setup views such as Account Sets are flat.</li>
<li>Ordered Revision: Ordered Revisions means that an internal list of changes are maintained in memory until a Process or Post command is given. In our example an Insert is performed prior to the Process. If processing multiple reversals, each reversal would be Inserted before the Process performs the reversals as a batch operation.</li>
</ul>
</div>
<h3>Understanding Your Log File</h3>
<p>After recording is complete, you need to now understand the log file.</p>
<p>In our example the two major issues were the fields we needed to set, and the calls required to post the reversal.</p>
<p>To understand the fields which need to be set, search for ‘Put’. In our example the first put is to PBANK to set the bank code. One thing to note is that RVSpy uses field numbers as opposed to names, so you will need to translate these into names using the Accpac Object Model.</p>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-BankPut.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-BankPut.png" alt="RVSpy BankPut" title="RVSpy BankPut" width="560" height="42" class="aligncenter size-full wp-image-1697" /></a></p>
<p>Continue searching and you will find Puts to PAYORID, TRANDATE, and REASON fields.</p>
<p>Next you will find Puts to two key fields SERIAL and LINENO. </p>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-SerialLinePut.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-SerialLinePut.png" alt="RVSpy SerialLinePut" title="RVSpy SerialLinePut" width="560" height="64" class="aligncenter size-full wp-image-1698" /></a></p>
<p>These two fields were a little confusing at first but we know they had to do with the transaction being reversed. In both recordings we made we actually used the finder to select the transaction we were to reverse. Prior to the two Put statements we could see the finder searching BKTRANH &#038; BKTRAND, thus the two values corresponded to the keys in these tables.</p>
<p>The final step was to search for the comment we made before we posted the reversal.</p>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-Insert.png"><img src="http://www.realisable.co.uk/wp-content/uploads/2013/02/Blog-8-RVSpy-Insert.png" alt="RVSpy Insert" title="RVSpy Insert" width="560" height="114" class="aligncenter size-full wp-image-1699" /></a></p>
<p>Three actions were performed:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Inserting the record into the view.</li>
<li>Switching the view mode to ‘Process Reversal Selections’.</li>
<li>Issuing Process to process the reversal.</li>
</ul>
</div>
<h3>Finally</h3>
<p>It may be necessary to record something more than once. You may enter something incorrectly, or you may need to repeat an action to understand each call; but with effective use, RVSpy is the best or only tool to understand those Sage300 views/screens which do not support macro recording.</p>
<p><a href='http://www.realisable.co.uk/wp-content/uploads/2013/02/008-BankServicesReversals.zip'>Download Bank Services Reversals source code</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/effective-rvspy-sage300-development/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Creating prepayments for O/E transactions in Sage300</title>
		<link>http://www.realisable.co.uk/creating-prepayments-oe-transactions-sage300</link>
		<comments>http://www.realisable.co.uk/creating-prepayments-oe-transactions-sage300#comments</comments>
		<pubDate>Thu, 31 Jan 2013 16:02:52 +0000</pubDate>
		<dc:creator>adrian</dc:creator>
				<category><![CDATA[Sage300]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1667</guid>
		<description><![CDATA[This blog uncovers the mystery of how to create A/R prepayments that are associated to their O/E documents and can be accessed via the drill down button on the A/R receipt entry screen. The logic described and presented in the &#8230; <a href="http://www.realisable.co.uk/creating-prepayments-oe-transactions-sage300">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
This blog uncovers the mystery of how to create A/R prepayments that are associated to their O/E documents and can be accessed via the drill down button on the A/R receipt entry screen. The logic described and presented in the blog applies equally to O/E orders, shipments and invoices.</p>
<p>Creating a prepayment with an O/E document is difficult for a few reasons:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Macro recording does not work; you need to use RVSPY to understand view calls.</li>
<li>Creating a prepayment requires manipulation of three separate, un-composed views and due to the lack of composition each view requires each field to be set individually.</li>
</ul>
</div>
<p>There are three rough steps to creating a prepayment:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Create an A/R receipt batch</li>
<li>Create an O/E prepayment record.</li>
<li>Update the O/E transaction header view.</li>
</ul>
</div>
<p style="text-align: center;"><a href="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-7-OE-Prepayment-Entry.png"><img class="aligncenter  wp-image-1668" title="OE Prepayment Entry" src="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-7-OE-Prepayment-Entry.png" alt="OE Prepayment Entry" width="502" height="303" /></a></p>
<p>Full source code is available for download at the bottom of this post.</p>
<h3>A/R Receipt Batch</h3>
<p>Firstly, it is necessary to either create a new A/R receipt batch or use a currently open batch. Creating the batch is relatively straight forward and really only requires you to set the bank account. Note that you do not need to compose each of the receipt views since you are not creating any receipt entries directly.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li>&nbsp;</li><li><span style="color: #666666;">'Open the A/R Receipt Batch View</span></li><li><span style="color: #666666;">Dim ARReceiptBatch As AccpacView</span></li><li><span style="color: #666666;">mDBLinkCmpRW.OpenView &quot;AR0041&quot;, ARReceiptBatch</span></li><li>&nbsp;</li><li><span style="color: #666666;">'</span>Create a <span style="color: #008000;">new</span> batch</li><li>ARReceiptBatch<span style="color: #008000;">.</span><span style="color: #0000FF;">Fields</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;CODEPYMTYP&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">PutWithoutVerification</span> <span style="color: #666666;">&quot;CA&quot;</span></li><li>ARReceiptBatch<span style="color: #008000;">.</span><span style="color: #0000FF;">Fields</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;CNTBTCH&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">PutWithoutVerification</span> <span style="color: #FF0000;">0</span></li><li>ARReceiptBatch<span style="color: #008000;">.</span><span style="color: #0000FF;">Init</span></li><li>&nbsp;</li><li><span style="color: #666666;">'Set the bank to which the receipt will be entered.</span></li><li><span style="color: #666666;">ARReceiptBatch.Fields(&quot;IDBANK&quot;).PutWithoutVerification sBank</span></li><li>&nbsp;</li><li><span style="color: #666666;">'</span>Set the bank currency<span style="color: #008000;">...</span><span style="color: #0600FF; font-weight: bold;">if</span> you weren<span style="color: #666666;">'t setting this and were using the default</span></li><li><span style="color: #666666;">'</span>bank account currency you can obtain it <span style="color: #0600FF; font-weight: bold;">from</span> the view<span style="color: #008000;">.</span></li><li><span style="color: #0600FF; font-weight: bold;">If</span> sBankCur <span style="color: #008000;">&lt;&gt;</span> vbNullString Then</li><li>ARReceiptBatch<span style="color: #008000;">.</span><span style="color: #0000FF;">Fields</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;CODECURN&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Value</span> <span style="color: #008000;">=</span> sBankCur</li><li><span style="color: #0600FF; font-weight: bold;">Else</span></li><li>sBankCur <span style="color: #008000;">=</span> ARReceiptBatch<span style="color: #008000;">.</span><span style="color: #0000FF;">Fields</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;CODECURN&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Value</span></li><li>End <span style="color: #0600FF; font-weight: bold;">If</span></li><li>&nbsp;</li><li><span style="color: #666666;">'Set a batch description</span></li><li><span style="color: #666666;">ARReceiptBatch.Fields(&quot;BATCHDESC&quot;).Value = &quot;Prepayment Batch from O/E&quot;</span></li><li><span style="color: #666666;">'</span>Update the batch</li><li>ARReceiptBatch<span style="color: #008000;">.</span><span style="color: #0000FF;">Update</span></li><li></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<h3>Update the O/E Prepayment View</h3>
<p>The second step is to create the O/E prepayment record. The prepayment record is responsible for creating A/R receipt entry and it also associates the receipt to the O/E order so that there is a drill down against the prepayment.</p>
<p>Each O/E transaction (Order, Shipment &amp; Invoice) has a separate prepayment view where each is identical with the exception of the view id. Therefore the logic used here is applicable to each.</p>
<p>If you are familiar with Sage300 development, most of the views are nicely programmed where a lot of hard work is performed behind the scenes by the view. Unfortunately, the prepayment views are the complete opposite! They do not have any default values either from the customer or order, so it is necessary to explicitly set each field.</p>
<p>The code sample below illustrates this, where it’s necessary to set the Customer, Customer Name &amp; Customer Currency all individually despite setting the Customer Id.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li>&nbsp;</li><li>Dim OrdPrepayments <span style="color: #0600FF; font-weight: bold;">As</span> AccpacView</li><li>mDBLinkCmpRW<span style="color: #008000;">.</span><span style="color: #0000FF;">OpenView</span> <span style="color: #666666;">&quot;OE0530&quot;</span>, OrdPrepayments</li><li>&nbsp;</li><li>OrdPrepayments<span style="color: #008000;">.</span><span style="color: #0000FF;">Init</span></li><li><span style="color: #666666;">'Associate the prepayment with order</span></li><li><span style="color: #666666;">OrdPrepayments.Fields(&quot;ORDUNIQ&quot;) = OEOrdHeaderFields(&quot;ORDUNIQ&quot;).Value</span></li><li><span style="color: #666666;">OrdPrepayments.Fields(&quot;CUSTOMER&quot;).Value = OEOrdHeaderFields(&quot;CUSTOMER&quot;).Value</span></li><li><span style="color: #666666;">OrdPrepayments.Fields(&quot;CUSTDESC&quot;).Value = OEOrdHeaderFields(&quot;BILNAME&quot;).Value</span></li><li><span style="color: #666666;">OrdPrepayments.Fields(&quot;CUSTCURN&quot;).Value = OEOrdHeaderFields(&quot;ORSOURCURR&quot;).Value</span></li><li><span style="color: #666666;"></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<h3>Update O/E Header View</h3>
<p>The final step is to update the prepayment fields on the O/E transaction header view, which update the Total Prepayments field on the order&#8217;s Totals Tab.</p>
<p style="text-align: center;"><a href="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-7-OE-Order-Header-Prepayment.png"><img class="aligncenter  wp-image-1669" title="OE Order Header Prepayment" src="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-7-OE-Order-Header-Prepayment.png" alt="OE Order Header Prepayment" width="552" height="432" /></a></p>
<p>The attached code is a full working sample illustrating how to create and attach a prepayment and should work for Sage300 versions 5.6 and above.</p>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/01/Sage300OEPrepayment.zip">Download Sage 300 OE Prepayment source code</a>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/creating-prepayments-oe-transactions-sage300/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dreaming for errors – integrations, error handling &amp; logging</title>
		<link>http://www.realisable.co.uk/integrations-error-handling-logging</link>
		<comments>http://www.realisable.co.uk/integrations-error-handling-logging#comments</comments>
		<pubDate>Fri, 25 Jan 2013 22:27:00 +0000</pubDate>
		<dc:creator>adrian</dc:creator>
				<category><![CDATA[data auditing]]></category>
		<category><![CDATA[data Integration]]></category>
		<category><![CDATA[design patterns]]></category>
		<category><![CDATA[error handling]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1649</guid>
		<description><![CDATA[Don’t think that all of your data is going to import every time, if you’re lucky some of it might some of the time. When designing or writing your integration application it is essential that you expect errors and, as &#8230; <a href="http://www.realisable.co.uk/integrations-error-handling-logging">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<p>Don’t think that all of your data is going to import every time, if you’re lucky some of it might some of the time.</p>
<p>When designing or writing your integration application it is essential that you expect errors and, as a result, design your program with the possibility for errors at the forefront of what you’re trying to achieve. In fact errors are probably just as critical as the data itself, if not more so.</p>
<p>This blog describes our best practices for designing error handling and logging within an integration.</p>
<h3>Design Pattern – The Layered Approach to Error Handling</h3>
<p>In a previous position I had the unenviable task of having to maintain several of a colleague’s poorly written import programs. Each time I made a modification I would re-factor a certain part of the program just for my own sanity and in conjunction I maintained several integrations I’d written myself. Over time each import converged to a similar structure, all based upon the way the integration handled errors.</p>
<p>The resulting pattern was a 3, sometimes 4, layer structure where each layer had its own error handling responsibilities.</p>
<p style="text-align: center;"><a href="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-6-Exception-Handling.png"><img class="size-full wp-image-1650 aligncenter" title="Layered approach to handling exceptions" src="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-6-Exception-Handling.png" alt="Layered approach to handling exceptions" width="505" height="431" /></a></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Atomic transaction: This is the inner most layer of your integration and is responsible for managing a single ‘atomic’ transaction. On failure it is this layer which cancels or rolls-back any half written transaction.</li>
<li>Transaction handler: The transaction handler is essentially a loop which calls into the ‘atomic’ transaction handler. When the atomic handler raises an error, this layer needs to decide how to proceed: whether to move to the next transaction or abort.</li>
<li>Task handler (optional): When your integration interfaces with anything more than a single end-point the task handler manages the handling of exceptional and non-exceptional data. Where a transaction succeeds, it needs to be submitted to the next end-point, whereas a failure usually means that it should not be processed at the next.</li>
<li>Entry point: The outermost layer to your application. It is responsible for:
<ul>
<li>Generation of the end user log or processing report.</li>
<li>Catching and logging any unexpected or catastrophic errors.</li>
</ul>
</li>
</ul>
</div>
<h3>Atomic transactions</h3>
<p>It goes without saying that whenever an error occurs in your automated integration it shouldn’t leave half written, partial transactions, database records, or files.</p>
<p>Sometimes however the concept of a transaction needs some thought, and requires input from business requirements, the technology of the platform and the ability to re-process data.</p>
<p>For example, should a batch of cash transactions into an accounting system be imported in an all-or-nothing approach, or should the integration import the ones it can, omitting the erroneous transactions? This scenario has implications on where the batch is posted; without the erroneous transactions, it may affect the bank reconciliation function at a later point.</p>
<h3>Logging types</h3>
<p>In our experience there are two audiences for the logs of any integration: end-users and technical staff. Users will want something they can understand, and technical people want something they can use to debug or understand a problem.</p>
<h4>End-user reports</h4>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Are sent to the people responsible for monitoring any integration/data feed.</li>
<li>Should be in readable, easily digested format.</li>
<li>Should allow the user to be able to quickly reconcile data passed between applications.</li>
<li>Should provide the user enough information to allow them to identify and/or resolve the issue, or at least identify any erroneous data.</li>
</ul>
</div>
<p><a href="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-6-Process-Report.png"><img class="aligncenter size-full wp-image-1651" title="Process Report" src="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-6-Process-Report.png" alt="Process Report" width="431" height="521" /></a></p>
<h4>Catch all &amp; Catastrophic error logging</h4>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Used to catch unexpected errors and exceptions, useful for technical staff to help identify isolated issues.<br />
Catastrophic errors are simply those you didn’t plan; for example, a loss of network connection; a corrupted file; a sudden disconnection from a database; an untimely permissions change; or out of memory exception.<br />
In contrast, an invalid item code on a sales order import is not catastrophic; it should be handled by your standard logging mechanism and reported on your end-user reports.</li>
<li>These errors should be logged locally to either a local file or local database, windows event log. Don’t rely on remote resources such as remote databases or email as network availability could be limited or the cause.</li>
</ul>
</div>
<h3>Runtime logging</h3>
<p>Errors, warnings &amp; messages should be persisted as early as possible, which means writing to a database or file as and when they occur. Should a catastrophic error occur you have a process log, a trace, which would otherwise be lost if they were held in memory and persisted at the end of the process.</p>
<h4>Log libraries</h4>
<p>It is worth mentioning that there are a number of open source logging and tracing libraries available such as <a title="nlog" href="http://nlog-project.org/" target="_blank">nlog</a>, <a title="log4net" href="http://logging.apache.org/log4net/" target="_blank">log4net</a>, the <a title=".net trace libraries" href="http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.aspx" target="_blank">.net trace libraries</a> and <a title="Microsoft's Enterprise framework" href="http://msdn.microsoft.com/en-us/library/ff664569(v=pandp.50).aspx" target="_blank">Microsoft’s Enterprise framework</a> which can provide you with a robust and feature rich way for persisting errors and warnings to a number of mediums. If you decide to use these, as opposed to rolling-your-own log scheme, the libraries can require some understanding to configure &amp; setup and their outputs are not suited for end users.</p>
<h3>Generating the end user process report</h3>
<p>At the conclusion of processing it is necessary to generate the process report for the end users. If you’ve followed our recommendations, this should mean re-querying the medium to which the errors were persisted during processing and re-formatting them into an easy to read format.</p>
<p>The best and easiest format to send the end users a process report is email for the following reasons:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Everyone has email.</li>
<li>Portable and amendable: Annotations can be made and forwarded to others if remedial action needs to be made by another person.</li>
<li>Logs can be easily formatted with html and presented nicely.</li>
</ul>
</div>
<h3>Summary</h3>
<p>Error handling and logging is a key component of any application, more so with integration! Without proper error logging and reporting, your organisation will at best spend needless time resolving and reconciling data between applications and at worst lose customers because of poor service and lost transactions.</p>
<p>We hope this has been of use to some of you and if you ask us nicely, we may just provide you with some samples and template code illustrating the best practices we’ve described.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/integrations-error-handling-logging/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Printing and multi-thread issues with Sage200</title>
		<link>http://www.realisable.co.uk/printing-multi-thread-issues-sage200</link>
		<comments>http://www.realisable.co.uk/printing-multi-thread-issues-sage200#comments</comments>
		<pubDate>Thu, 17 Jan 2013 09:00:01 +0000</pubDate>
		<dc:creator>appiah</dc:creator>
				<category><![CDATA[multithreading]]></category>
		<category><![CDATA[Sage ReportEngine]]></category>
		<category><![CDATA[Sage200]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1608</guid>
		<description><![CDATA[In this blog we take a deep dive into the mechanics of using the Sage reporting engine in an external application using the Sage200 SDK for both single and multi-threaded applications. Topics covered: Correctly referencing the Sage reporting engine Using &#8230; <a href="http://www.realisable.co.uk/printing-multi-thread-issues-sage200">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
In this blog we take a deep dive into the mechanics of using the Sage reporting engine in an external application using the Sage200 SDK for both single and multi-threaded applications. Topics covered:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Correctly referencing the Sage reporting engine</li>
<li>Using the Sage reporting engine within a service</li>
<li>Use the Sage reporting engine in a multi-threaded application</li>
<li>The Sage200 Security Context</li>
<li>Multi-threaded use of the Sage200 Application object</li>
</ul>
</div>
<p>Full source code is available at the bottom of the blog.</p>
<h3>Background</h3>
<p>When we added to IMan functionality to print various Sage200 forms we encountered a number of issues during development, deployment and use in a production environment.</p>
<p>This blog will attempt to uncover and present the solution to these issues. We hope that this will help other Sage developers who are grappling with the reporting engine complexities.</p>
<h3>External printing with Sage Report Engine</h3>
<p>The first phase to adding print support to our application was to provide support for printing forms such as invoices, picking lists, etc.</p>
<p>The biggest hurdle we faced was the correct referencing of various Sage libraries and dependencies.</p>
<h4>References</h4>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Copy \Program Files\Sage200\ Unity.config to your local bin directory.</li>
<li>Reference the following assemblies and ensure that NONE are copied to your local bin directory.
<ul>
<li>Sage.Reporting.Services</li>
<li>Sage.Reporting.Model</li>
<li>Sage.Reporting.Engine.Integration</li>
<li>Sage.Query.Engine.Model</li>
<li>Sage.Query.Engine</li>
<p>        These assemblies are located in various places on a workstation with Sage200 installed; some are in the SDK, some are in the GAC, some are in the Sage installation directory.</p>
<p>        For those assemblies stored in the GAC we extract them using <a href="http://www.nirsoft.net/dot_net_tools/gac_viewer.html" target="_blank">GAC View</a>.</li>
</ul>
</ul>
</div>
<h4>Setting the Printer at Runtime</h4>
<p>At the time of writing (an enhancement request has been logged with Sage) the Sage Reporting Engine does not have any facility to set the printer at runtime. It can however be set by traversing the internal object structure of the ReportEngine object.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li><span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// Prints a report to a specific printer or exports a report to a file.</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;exportFilePath&quot;&gt;The file to export the report to, can be empty or</span></li><li><span style="color: #008080; font-style: italic;">/// null if the report is being printed.&lt;/param&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;exportService&quot;&gt;The IExportService i.e. this object.&lt;/param&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;flags&quot;&gt;Should always be set to SuppressUserInteraction.&lt;/param&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;exportType&quot;&gt;The type of file if the report is being exported or</span></li><li><span style="color: #008080; font-style: italic;">/// prn if being printed.&lt;/param&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;printerName&quot;&gt;The local printer name if the report is being</span></li><li><span style="color: #008080; font-style: italic;">/// printed.&lt;/param&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;returns&gt;True...not sure of the signifigance as it's undocumented.&lt;/returns&gt;</span></li><li><span style="color: #0600FF; font-weight: bold;">private</span> <span style="color: #6666cc; font-weight: bold;">bool</span> PrintReport<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">string</span> exportFilePath, IExportService exportService, ExportFlags flags, ExportType exportType, <span style="color: #6666cc; font-weight: bold;">string</span> printerName<span style="color: #008000;">&#41;</span></li><li><span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;Type exporterType <span style="color: #008000;">=</span> exportService<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;PropertyInfo reportsPropertyInfo <span style="color: #008000;">=</span> exporterType<span style="color: #008000;">.</span><span style="color: #0000FF;">GetProperty</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;Reports&quot;</span>, <span style="color: #000000;">System.<span style="color: #0000FF;">Reflection</span></span><span style="color: #008000;">.</span><span style="color: #0000FF;">BindingFlags</span><span style="color: #008000;">.</span><span style="color: #0600FF; font-weight: bold;">Public</span> <span style="color: #008000;">|</span> <span style="color: #000000;">System.<span style="color: #0000FF;">Reflection</span></span><span style="color: #008000;">.</span><span style="color: #0000FF;">BindingFlags</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Instance</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;IList reports <span style="color: #008000;">=</span> reportsPropertyInfo<span style="color: #008000;">.</span><span style="color: #0000FF;">GetValue</span><span style="color: #008000;">&#40;</span>exportService, <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span> <span style="color: #0600FF; font-weight: bold;">as</span> IList<span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Should never be zero, but just in case.</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>reports<span style="color: #008000;">.</span><span style="color: #0000FF;">Count</span> <span style="color: #008000;">==</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">throw</span> <span style="color: #008000;">new</span> Exception<span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;No reports in the layout file&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Get the ReportBatchItem</span></li><li>&nbsp;&nbsp;var batchItem <span style="color: #008000;">=</span> reports<span style="color: #008000;">&#91;</span><span style="color: #FF0000;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Get the report.</span></li><li>&nbsp;&nbsp;var reportPropertyInfo <span style="color: #008000;">=</span> batchItem<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">GetProperty</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;Report&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Get the actual report object.</span></li><li>&nbsp;&nbsp;Sage<span style="color: #008000;">.</span><span style="color: #0000FF;">Reporting</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Model</span><span style="color: #008000;">.</span><span style="color: #0000FF;">IReport</span> report <span style="color: #008000;">=</span> reportPropertyInfo<span style="color: #008000;">.</span><span style="color: #0000FF;">GetValue</span><span style="color: #008000;">&#40;</span>batchItem, <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span> <span style="color: #0600FF; font-weight: bold;">as</span> Sage<span style="color: #008000;">.</span><span style="color: #0000FF;">Reporting</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Model</span><span style="color: #008000;">.</span><span style="color: #0000FF;">IReport</span><span style="color: #008000;">;</span></li><li>&nbsp;</li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Set the printer.</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Sometimes the PrinterSettings can be null (usually when the report is</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// saved with a printer which is not installed/available under the user</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// profile which the report is being run.</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>report<span style="color: #008000;">.</span><span style="color: #0000FF;">PaperLayout</span><span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterSettings</span> <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000;">System.<span style="color: #0000FF;">Drawing</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Printing</span></span><span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterSettings</span> printSettings <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> <span style="color: #000000;">System.<span style="color: #0000FF;">Drawing</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Printing</span></span><span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterSettings</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Set the printer name before setting the object to the PrinterSettings</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// property. </span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Setting the object to the property fails, with the property remaining</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// null.</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;printSettings<span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterName</span> <span style="color: #008000;">=</span> printerName<span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;report<span style="color: #008000;">.</span><span style="color: #0000FF;">PaperLayout</span><span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterSettings</span> <span style="color: #008000;">=</span> printSettings<span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">else</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000;">System.<span style="color: #0000FF;">Drawing</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Printing</span></span><span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterSettings</span> printerSettings <span style="color: #008000;">=</span>&nbsp;&nbsp;report<span style="color: #008000;">.</span><span style="color: #0000FF;">PaperLayout</span><span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterSettings</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;printerSettings<span style="color: #008000;">.</span><span style="color: #0000FF;">PrinterName</span> <span style="color: #008000;">=</span> printerName<span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li><span style="color: #008000;">&#125;</span></li><li></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<h3>Using the Sage Reporting Engine within a service</h3>
<p>Using any library within a windows service deserves special attention due to the various restrictions of the running environment, the Sage reporting engine is no different.</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>ExportFlags.SuppressUserInteraction: Everything in a service needs to run attended therefore it is necessary to instruct the reporting engine not to display prompts or message boxes. Further, service security in Vista and Server2008 was tightened so that any service attempting to display any UI element is terminated by Windows.</li>
<li>Sage.Accounting.DataModel.dll : Copy Sage.Accounting.DataModel.dll located in C:\Users\&lt;userid&gt;\AppData\Local\Sage\Sage200\AssemblyCache to your service’s bin directory. As the name suggests, the Sage.Accounting.DataModel.dll assembly contains the Sage200 data model that is dynamically built by the Sage server whenever a model extension is installed (for instance when you add a new view or table to the database and run through the Custom Model Builder).</li>
<li>Use locally installed printers: Services don’t load user profiles (irrespective of the service’s user); therefore they don’t have access to network printers (which are loaded dynamically as part of the user profile).</li>
</ul>
</div>
<h3>Using the Sage Reporting Engine in a multi-threaded application</h3>
<p>This section deals with the threading issues experienced when our application attempted to run multiple instances of the Sage reporting engine concurrently.</p>
<p>Having completed the initial report printing development we deployed this to a couple of sites which were running without issue.</p>
<p>Our problem came on a new site where each time our application attempted to print Sage200 forms concurrently we would encounter a range of exceptions. These exceptions would essentially terminate the execution of one of the concurrently running integrations.</p>
<h4>Background</h4>
<p>Our IMan application is multi-threaded, meaning that each time integration runs within a separate thread of a single multi-threaded apartment (MTA) executable.</p>
<p>To this point we had not experienced any threading related problems with IMan. Multiple integrations could be run concurrently without issue. Further, we could successfully run multiple integrations or threads concurrently where each could create transactions within Sage200.</p>
<h4>Problem</h4>
<p>Under the hood the first thing Sage does when creating a ReportingEngine object is make a call to DoEvents (this infers the Sage reporting engine is written in VB.Net).</p>
<p>Because this ultimately makes a call to the Windows messaging queue, any interactions with the UI or Messaging queue should come from a single thread (marked as a Single Threaded Apartment (STA)) from within an application.</p>
<p>Windows does not permit multiple threads within an application to access the messaging queue, with an exception being raised by windows where multiple threads attempt to do so.</p>
<p>Why is an STA Thread Required? (Simplified)<br />
<a href="http://blogs.msdn.com/b/jfoscoding/archive/2005/04/07/406341.aspx" target="_blank">http://blogs.msdn.com/b/jfoscoding/archive/2005/04/07/406341.aspx</a></p>
<p>A fuller discussion of COM and threading models.<br />
<a href="http://msdn.microsoft.com/en-us/library/ms693344(VS.85).aspx" target="_blank">http://msdn.microsoft.com/en-us/library/ms693344(VS.85).aspx</a></p>
<p>The error below is the one generated when multiple threads of the same application attempt to create ReportingEngine objects at the same time.</p>
<p>The error is pretty misleading, and at the time we thought that we were dealing with a linking or referencing issue with some Office components.</p>
<p>Given that we hadn’t had a threading issue previously and that we had suppressed user interaction (above), we were left scratching our heads for a while.</p>
<p>The clue came when we looked at the callstack more closely: DoEvents and FPushMessageLoop both indicate some UI interaction is occurring.<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size:0.9em"><br />
System.InvalidCastException: Unable to cast COM object of type &#8216;System.__ComObject&#8217; to interface type &#8216;IMsoComponentManager&#8217;. This operation failed because the QueryInterface call on the COM component for the interface with IID &#8216;{000C0601-0000-0000-C000-000000000046}&#8217; failed due to the following error: No such interface supported (Exception from HRESULT: 0&#215;80004002 (E_NOINTERFACE)).<br />
at System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 uReason, Int32 pvLoopData)<br />
at System.Windows.Forms.ComponentManagerProxy.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)<br />
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)<br />
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)<br />
at System.Windows.Forms.Application.DoEvents()<br />
at Sage.Reporting.Engine.Integration.ReportingEngine..ctor()<br />
at Realisable.Connectors.Sage200.ReportExporter..ctor(String reportFileName, Dictionary`2 criteria, String exportFilePath, Boolean print, String printerName)<br />
</span></p>
<h3>Our requirements</h3>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Retain the multi-threadedness of Iman: Changing our architecture to single threaded was a non-starter.</li>
<li>In-process: We did consider writing a separate print spool application, but this suffered from two problems:
<ul>
<li>Marshalling the print requests and response between two applications was considered too fragile and difficult.</li>
<li>Sage200 permits only a single login per user at a time. A separate process would have required a second login and Sage user.</li>
</ul>
</li>
</ul>
</div>
<h4>Solution</h4>
<p>The solution is a variant of the <a href="http://wiki.osuosl.org/development/deprecated/synchronized_singleton_pattern" target="_blank">synchronised singleton pattern</a> (this is in Java, but the pattern applies), where a single thread (print thread) processes report requests singularly, one at a time. Each subsequent print request is blocked until the print thread completes the executing print request.</p>
<p><img class="aligncenter size-full wp-image-1613" title="Image of Multi-threaded printing in Sage200" src="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-5-ReportQueueManager.png" alt="Image of Multi-threaded printing in Sage200" width="579" height="463" /></p>
<h3>Implementation</h3>
<h4>ReportQueueManager</h4>
<p>The ReportQueueManager marshals the print requests to the Sage reporting engine and is also responsible for printer thread running state. It contains 4 methods:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>RunReport: Called by the worker threads to process a print request.</li>
<li>ProcessReport: The internal method which de-queues and processes each request.</li>
<li>Start &amp; Shutdown: Respectively manage the startup and shutdown of the printer thread.</li>
</ul>
</div>
<h4>Printer thread</h4>
<p>Internal to the ReportQueueManager class is a single threaded apartment (STA) thread which is responsible for processing each print request.</p>
<h3>Inter-thread communication/synchronisation</h3>
<p>To communicate between the calling/worker thread and the printer thread are two blocking queues:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Request Queue: Accepts print requests from the worker thread.</li>
<li>Reply Queue: Returns the success/failure of a print request from the printer thread back to the calling/worker thread.</li>
</ul>
</div>
<p>The request queue is the key component for synchronising calls between the worker and printer threads. The queue is set to permit only a single request at a time i.e. its maximum length is set to one. When the queue is full (it has a request), all further requests are blocked; i.e. their execution is halted, thus permitting only a single request to be processed at a time.</p>
<p>To achieve the blocking queue we used a pattern as described <a href="#530228" target="_blank">here</a>.</p>
<h4>ReportRequest</h4>
<p>The ReportRequest object encapsulates all the criteria such as report name, report criteria/parameters, printer name, etc. for a print job.</p>
<p>A ReportRequest object is created by a worker thread for each print request. The worker thread calls ReportQueueManager.RunReport, if the queue is empty, the request is processed immediately. However, if the queue is not empty (meaning a report is being printed), the calling thread is blocked.</p>
<h4>Communicating success/failure to the caller</h4>
<p>To communicate back to the calling thread if the print operation has succeeded or failed, a ReportReply object is created and placed onto the reply queue.</p>
<p>Execution is returned when the ReportQueueManager de-queues the reply object from the reply queue. The reply is checked for success or failure, and where there is failure, it re-throws the exception.</p>
<h3>Understanding the Sage200 logon context</h3>
<p>Our solution meant that each print request could be run against different Sage companies/databases, so a critical component in our solution was to get ReportEngine to target the correct Sage company.</p>
<p>If you have ever dealt with the Sage reporting engine, you would have noticed that there are no properties or methods for authentication or for targeting a specific company/database. This is because the reporting engine uses the current thread’s security context/principal (System.Threading.Thread.CurrentPrincipal).</p>
<p>Per MSDN, a principal object represents the security context of the user on whose behalf the code is running, including that user&#8217;s identity (<a href="http://msdn.microsoft.com/en-us/library/system.security.principal.iidentity.aspx" target="_blank">IIdentity</a>) and any roles to which they belong.</p>
<p>Sage200 sets the CurrentPrincipal as part of the set operation of the Application.ActiveCompany property.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li><span style="color: #008080; font-style: italic;">// Authenticate to Sage200</span></li><li>_application<span style="color: #008000;">.</span><span style="color: #0000FF;">Connect</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;admin&quot;</span>, <span style="color: #666666;">&quot;admin&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span> </li><li><span style="color: #008080; font-style: italic;">// Set the active company.</span></li><li><span style="color: #0600FF; font-weight: bold;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i <span style="color: #008000;">&lt;</span> _application<span style="color: #008000;">.</span><span style="color: #0000FF;">Companies</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Count</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #008000;">&#41;</span></li><li><span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>_application<span style="color: #008000;">.</span><span style="color: #0000FF;">Companies</span><span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Name</span> <span style="color: #008000;">==</span> <span style="color: #666666;">&quot;Sage200_2010_DemoData&quot;</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// When the ActiveCompany property is set Sage sets the </span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// current thread's CurrentPrincipal property with logon</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// context.</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;_application<span style="color: #008000;">.</span><span style="color: #0000FF;">ActiveCompany</span> <span style="color: #008000;">=</span> _application<span style="color: #008000;">.</span><span style="color: #0000FF;">Companies</span><span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">break</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li><span style="color: #008000;">&#125;</span></li><li></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p>The solution requires that the print thread’s CurrentPrincipal is set to the principal of the thread.</p>
<p>Since the reporting and print threads are separate it is necessary to pass the print thread to the worker’s thread’s principal for each print request.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li><span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">public</span> ReportRequest<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">//Capture the Principal of the calling thread</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;Principal <span style="color: #008000;">=</span> Thread<span style="color: #008000;">.</span><span style="color: #0000FF;">CurrentPrincipal</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">//Used for debug and tracing purposes.</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;ThreadId <span style="color: #008000;">=</span> Thread<span style="color: #008000;">.</span><span style="color: #0000FF;">CurrentThread</span><span style="color: #008000;">.</span><span style="color: #0000FF;">ManagedThreadId</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li><span style="color: #008000;">....</span></li><li></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p>We do this by capturing the principal in the constructor of the ReportRequest class. When the ReportQueueManager de-queues the request it sets the printer thread’s CurrentPrincipal to the Principal of the request object.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li><span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span></li><li><span style="color: #008080; font-style: italic;">/// Worker method to process ReportRequests</span></li><li><span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span></li><li><span style="color: #0600FF; font-weight: bold;">private</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">void</span> ProcessReport<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></li><li><span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Run forever!</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">while</span> <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// This method will block until a request is placed onto the queue.</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;ReportRequest request <span style="color: #008000;">=</span> _requestQueue<span style="color: #008000;">.</span><span style="color: #0000FF;">Dequeue</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Set this thread's principal to the principal of the request, </span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// which the reporting engine then uses.</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;Thread<span style="color: #008000;">.</span><span style="color: #0000FF;">CurrentPrincipal</span> <span style="color: #008000;">=</span> request<span style="color: #008000;">.</span><span style="color: #0000FF;">Principal</span><span style="color: #008000;">;</span></li><li></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p>The result allows each calling/worker thread to target a separate Sage200 company e.g. worker thread ‘A’ targets company ‘Y’ and worker thread ‘B’, company Z.</p>
<p>It is worth noting that without this the Sage ReportingEngine object will raise an exception when CurrentPrincipal is not set (ref 1).</p>
<h3>Sage.Accounting.Application objects are not threadsafe</h3>
<p>During testing we kept encountering a DuplicateKeyFound exception when setting the ActiveCompany property whenever two threads entered the method simultaneously. Our solution was to wrap the code for the connect and disconnect in a lock statement.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="C#"><div class="devcodeoverflow"><ol><li></li><li><span style="color: #008080; font-style: italic;">// The ActiveCompany property setter is not threadsafe, </span></li><li><span style="color: #008080; font-style: italic;">// wrap the code around a lock to prevent 'DuplicateKeyFound' exception.</span></li><li><span style="color: #008080; font-style: italic;">// _syncLock is a static object declared at class level.</span></li><li><span style="color: #0600FF; font-weight: bold;">lock</span> <span style="color: #008000;">&#40;</span>_syncLock<span style="color: #008000;">&#41;</span></li><li><span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Authenticate to Sage200</span></li><li>&nbsp;&nbsp;_application<span style="color: #008000;">.</span><span style="color: #0000FF;">Connect</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;admin&quot;</span>, <span style="color: #666666;">&quot;admin&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span> </li><li>&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// Set the active company.</span></li><li>&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i <span style="color: #008000;">&lt;</span> _application<span style="color: #008000;">.</span><span style="color: #0000FF;">Companies</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Count</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>_application<span style="color: #008000;">.</span><span style="color: #0000FF;">Companies</span><span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Name</span> <span style="color: #008000;">==</span> <span style="color: #666666;">&quot;Sage200_2010_DemoData&quot;</span><span style="color: #008000;">&#41;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000;">&#123;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// When the ActiveCompany property is set Sage sets the </span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// current thread's CurrentPrincipal property with logon</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008080; font-style: italic;">// context.</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_application<span style="color: #008000;">.</span><span style="color: #0000FF;">ActiveCompany</span> <span style="color: #008000;">=</span> _application<span style="color: #008000;">.</span><span style="color: #0000FF;">Companies</span><span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0600FF; font-weight: bold;">break</span><span style="color: #008000;">;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li>&nbsp;&nbsp;<span style="color: #008000;">&#125;</span></li><li></li></ol></div></pre><!--END_DEVFMTCODE--></p>
<h3>Summary</h3>
<p>We would like to thank the Sage200 development support for all their assistance, and ESPI and the client for their patience.</p>
<p><a href='http://www.realisable.co.uk/wp-content/uploads/2013/01/Sage200-Report-Manager.zip'>Download Sage200 Report Manager source code</a></p>
<p>(Ref. 1) This is not entirely true! We found during testing that if we had Sage200 open and did not set the printer thread’s current principal the ReportEngine would somehow use the SAAPrincipal of the open application. An exception was thrown when Sage200 was not open.
</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/printing-multi-thread-issues-sage200/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integration and Synchronisation Data Exchange</title>
		<link>http://www.realisable.co.uk/integration-synchronisation-data-exchange</link>
		<comments>http://www.realisable.co.uk/integration-synchronisation-data-exchange#comments</comments>
		<pubDate>Fri, 11 Jan 2013 10:00:31 +0000</pubDate>
		<dc:creator>appiah</dc:creator>
				<category><![CDATA[data Integration]]></category>
		<category><![CDATA[synchronisation]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1566</guid>
		<description><![CDATA[In this final part of our multi-part post (see part 1 and part 2), I will discuss the various transports which can be used to synchronise data between applications. As opposed to the previous two parts, the strategies in this &#8230; <a href="http://www.realisable.co.uk/integration-synchronisation-data-exchange">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<p>In this final part of our multi-part post (see <a href="http://www.realisable.co.uk/common-issues-synchronising-data-applications">part 1</a> and <a href="http://www.realisable.co.uk/synchronisation-strategy">part 2</a>), I will discuss the various transports which can be used to synchronise data between applications.</p>
<p>As opposed to the previous two parts, the strategies in this post are not limited to synchronisation and apply equally to integration.</p>
<h4>File transfer</h4>
<p>The old school method for data exchange has existed for as long as computers have interchanged data. File transfer involves one application creating a file and putting it in an agreed location, whilst the receiving application reads, processes and then does something with the file.</p>
<p><strong>Pros</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Secure: File transfer can be easily locked down, making it a relatively secure means to exchange data. FTP and SSH are both solid protocols meaning remote exchange over the internet is secure.</li>
</ul>
</div>
<p><strong>Cons</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Difficult to audit: Compared with other mechanisms files typically don’t have any natural means to audit or to trace audit.</li>
<li>Remote servers require an FTP/SSH solution to exchange files, adding another chink in the chain of events.</li>
<li>Fragile: Easy to get out of sync where a failure can require significant manual intervention to re-establish normal operation.</li>
<li>CSV and other column based formats such as fixed width text and Excel suffer from brittleness, where file schema modifications (field additions and deletions) require significant re-configuration on the receiving end.</li>
</ul>
</div>
<p><strong>Tips for use</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>One transaction per file: It’s much easier to identify a particular transaction, and re-processing is easy should something go awry.</li>
<li>For CSV and other column based formats, always add new fields to the end of the file; never remove existing ones, better still don’t use these formats!</li>
<li>Use a resilient API based data format such as Xml or JSON. Do not go overboard however.</li>
<li>Try to avoid Xml schema where possible. We feel schemas add unnecessary constraints to the format, where a substantial amount of the inherent flexibility of the format is lost. They add a level of complexity not required in the SME space.</li>
<li>Always use a recognised API/library when consuming and producing Xml/JSON data. This will at minimum ensure the format is standard compliant. We’ve seen several instances where organisations (that should know better) provide us with improperly escaped Xml, simply because they weren’t using an API to produce the Xml.</li>
<li>After files are processed move them to an archive directory; don’t delete.</li>
</ul>
</div>
<h4>Database &amp; staging tables</h4>
<p>Our preferred means for both integration and synchronisation, the use of databases &amp; staging tables providing a much more robust transport as compared to file exchange.</p>
<p>Staging tables are an intermediate set of database tables where the sender records pending data for the recipient(s) to later process.</p>
<p><strong>Pros</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>SQL: Provides vendor and format independence to query and update a database and table schema(s) changes are usually non-breaking.</li>
<li>Audit and Traceability: SQL/Databases provide an easy means to record and query any key data required for auditing purposes e.g. timestamps, error &amp; warning messages.</li>
<li>Durability and Recoverability: Databases are naturally durable and far less vulnerable to corruption. In the event of a failure recovery can be made quickly assuming a backup is available.</li>
</ul>
</div>
<p><strong>Cons</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Security: Where interchange take place over the internet the database needs to be open to the outside world leading to potential attacks. These can be mitigated by restricting the connecting IP addresses, use of complex passwords, amongst others.</li>
</ul>
</div>
<p><strong>Tips for Use</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Always have the following fields in a staging table:
<ul>
<li>Status: Used to record whether a record is pending or processed. Always include an error status which allows you to identify erroneous transactions quickly. It is recommended that an index is setup on the status field to help speed querying.</li>
<li>Last Modified Date: A timestamp to record when the last update was made.</li>
<li>Last Update By: Used to record which application made the last update.</li>
<li>Reason/error/message: Where there’s an error or a warning generated as part of the integration or synchronisation it should be recorded against the original record. This then gives you a robust audit trail which can be used later to trace problems.</li>
<li>Foreign Record Id: Where a recipient application generates a transaction or record id (such as an Order, Invoice, or even Customer number) update the staging table with this reference.</li>
</ul>
</li>
<li>Backup frequently: Depending on the volume of data or the location of the database i.e. for high volume sites or where the database is publicly accessible this may be several times a day.</li>
<li>Always update the staging table immediately after writing to the destination application.</li>
<li>Where processing takes a long time, consider setting the status field to an intermediate value to prohibit other integration processes from processing the same data.</li>
</ul>
</div>
<h4>Message queue</h4>
<p>A message queue is a transport level asynchronous protocol where a sender places a message into a queue until the receiver removes the message to process it. One of the key attributes of a message queue, especially for data synchronisation, is that messages are guaranteed to be delivered in FIFO order.</p>
<p><img class="aligncenter size-full wp-image-1568" title="Message Queue" src="http://www.realisable.co.uk/wp-content/uploads/2013/01/Blog-4-Message-Queue.png" alt="Message Queue" width="537" height="200" /></p>
<p>Message queues have traditionally been limited to larger scale integration and synchronisation and where both sender and receiver exist on the same network. However, with the explosion of cloud computing and an agreed standard (AMQP), there is an increasing prevalence of low cost services:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li><a href="http://www.windowsazure.com/en-us/home/features/messaging/" target="_blank">Windows Azure Service Bus</a></li>
<li><a href="http://aws.amazon.com/sqs/" target="_blank">Amazon SQS</a></li>
<li><a href="http://stormmq.com/" target="_blank">Storm MQ</a>: Currrently in-beta this ‘free’ service looks promising.</li>
</ul>
</div>
<p><strong>Pros</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>FIFO: Messages are guaranteed to be delivered in order.</li>
<li>Robust and Transactional: Message queues can be backed up, and are naturally transactional.</li>
</ul>
</div>
<p><strong>Cons</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Message Queues are a Transport: The data format of the message still needs to be agreed between sender and recipient.</li>
</ul>
</div>
<p><strong>Tips for use</strong></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Use a flexible data format such as Xml.</li>
<li>File and database recovery is well known, message queues less so. Understand how to administer your message queue technology and how to recover on the event of a failure.</li>
<li>Prevent message build up by having an application which is constantly listening for incoming messages.</li>
<li>Use different queues for each data flow; don’t try to multiplex multiple message types onto a single queue.</li>
</ul>
</div>
<h4>No interchange</h4>
<p>In this scenario there is no intermediate data form, instead each application holds its pending data until the recipient application retrieves it.</p>
<p>Unless an application specifically integrates with another this style of interchange requires some form of middleware to mediate the interaction since:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Each application has its own interface i.e. webservice or a COM/Java/.Net API.</li>
<li>The data usually requires some transformation for it to ‘fit’ with the other.</li>
</ul>
</div>
<h4>Summary</h4>
<p>If a choice can be made, use databases/staging tables as they are by far the easiest and most robust strategy.</p>
<p>We expect an increased use of message queues, especially with hosted infrastructure environments such as Azure and Amazon.</p>
<p>CSV: Dear oh dear! It may be easy to produce and simple to read, interpret and load into Excel. But it&#8217;s 2013! And there are more sophisticated and better means for exchanging data, so why are we still using this archaic format?</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/integration-synchronisation-data-exchange/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Synchronisation strategy</title>
		<link>http://www.realisable.co.uk/synchronisation-strategy</link>
		<comments>http://www.realisable.co.uk/synchronisation-strategy#comments</comments>
		<pubDate>Fri, 30 Nov 2012 09:00:42 +0000</pubDate>
		<dc:creator>appiah</dc:creator>
				<category><![CDATA[synchronisation]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1459</guid>
		<description><![CDATA[In Part I of this multi-part blog some of the most common issues for synchronisation were discussed. This second post will describe the strategies available for synchronising data between applications, their advantages and pitfalls. The strategy is the means to &#8230; <a href="http://www.realisable.co.uk/synchronisation-strategy">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<p>In <a href="./common-issues-synchronising-data-applications">Part I</a> of this multi-part blog some of the most common issues for synchronisation were discussed.</p>
<p>This second post will describe the strategies available for synchronising data between applications, their advantages and pitfalls.</p>
<p>The strategy is the means to determine when a record should be inserted, updated, or deleted.</p>
<h4>Data Structures</h4>
<p>It is necessary to first understand the issues surrounding more complex data structures.</p>
<p>Simple single level data structures, such as customer records, can be readily synchronised. However, as data structures become more complex so does the strategy.</p>
<p><img class="size-full wp-image-1461 aligncenter" title="Illustration of Hierarchical Structure" src="http://www.realisable.co.uk/wp-content/uploads/2012/11/Blog3-Hierarchical-Structure.png" alt="Illustration of Hierarchical Structure" width="489" height="349" /></p>
<p>The above example is illustrative, both order and order lines must be synchronised; an order without lines is not an order. However, the third level of data – the serial–numbers add several complications:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Is it necessary to synchronise them? If they are used for transactional purposes, yes, but a view-only application may not require them.</li>
<li>What do the serial numbers mean when an order line is updated? Are they a fresh set of serials, or just additions? While this question applies also to lines, the deeper the structure the more pronounced the issue becomes. This is due to the feedback of how the update is made on each level of data.</li>
</ul>
</div>
<h4>Means of Identifying Updates</h4>
<p><strong>Inserting &amp; Updating Records</strong></p>
<p>Inserts and updates follow a simple pattern where the destination application is queried to identify if it contains an existing record. An update is performed where a match is found; otherwise when no matches are found, an insert is performed.</p>
<p><strong>Deleted Records</strong></p>
<p>Handling deletions is a much harder issue, primarily as the delete needs to be identified. There are three approaches:</p>
<p><em><strong>Tombstoning</strong></em></p>
<p>Tombstoning is a technique which instead of actually deleting the record, marks it as deleted, via a field within the record’s table. What makes this a preferred method for handling deletes is that the tombstone makes the delete operation explicit and in turn reduces complexity around synchronisation.</p>
<p><img class="aligncenter size-full wp-image-1462" title="SageCRM Tombstone" src="http://www.realisable.co.uk/wp-content/uploads/2012/11/Blog3-SageCRM-Tombstone.png" alt="SageCRM Tombstone" width="489" height="97" /></p>
<p>Tombstoning however requires the source application to provide such functionality (usually only a feature when data synchronisation/integration is integral to the application e.g. CRM).</p>
<p>For applications that don’t support tombstoning, it is necessary to record the record deletion(s) in a separate interface table or file, usually by way of a trigger (to be discussed in part 3 of this blog).</p>
<p><em><strong>Record Comparison</strong></em></p>
<p>Record comparison involves comparing a set of data from the source application to the set of data in the destination application. A delete is performed when a record is found in the destination but not in the source.</p>
<p><img class="aligncenter size-full wp-image-1463" title="Delete By Comparison" src="http://www.realisable.co.uk/wp-content/uploads/2012/11/Blog3-Delete-By-Comparison.png" alt="Delete By Comparison" width="489" height="349" /></p>
<p>In contrast to ‘Tombstoning’ this suffers from three primary problems:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Complex: Record comparison is implicit; it requires the ‘data synchroniser’ to determine if a record has been deleted.</li>
<li>Auditing: There is a lack of an audit trail where records just disappear, with no facility to check why/when a deletion occurred.</li>
<li>OK for child records not for the primary entity: Using comparison for child records in hierarchical structure, e.g. order lines within an order, can be appropriate where there are limited records and the detection of deleted records is cheap and relatively straight forward.</li>
</ul>
</div>
<p>Using comparison for a primary entity (e.g. the order) requires the examination of a large set of data to determine whether a delete is required.</p>
<p><em><strong>Re-create Everything</strong></em></p>
<p>A third alternative is to delete and re-create all records on each ‘sync’. This strategy is easiest to implement, covering inserts, updates and deletes, since it doesn’t require any logic to detect and handle changes. However, its use is only limited to the following scenarios:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Data is loaded at a database level e.g. reporting &amp; data warehouses and CRMs. Applications with a sophisticated data structure and/or API usually frown on this approach as business logic and data validation is side-stepped and can lead to integrity issues.</li>
<li>The destination application is view only and non-transactional.</li>
<li>There are no (or very limited) foreign-key constraints: Foreign keys enforce relationships between records. When a record is deleted so must all the associated records. For example, deleting a customer record also requires deleting all the customer’s associated order &amp; invoice records.</li>
<li>Data size: Deleting and re-inserting all records in a large dataset may take a long time to complete and can be expensive in terms of computing power, particularly with hosted environments where there can be CPU cycle costs. Pruning the dataset, usually by date, is an effective strategy to limit the load size.</li>
</ul>
</div>
<h4>Handling Application Logic</h4>
<p>When synchronising data between applications it is necessary to negotiate and handle the restrictions or logic the API applies to the data.</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Business logic is much stricter than any database enforcement.</li>
<li>Transactional data moves through a process, where the status of the transaction (or line) dictates whether modifications can be made.</li>
<li>Deletes are never easy &#8211; Particularly with ERP applications, deletes are handled in a number of ways: master items may need to be marked as inactive (a form of tombstoning); transactions can either be deleted or cancelled.</li>
</ul>
</div>
<p><em><strong>Strategies for handling application logic</strong></em></p>
<div class="bulletedtext">
<ul class="bulletedtext">
<ul>
<li>Atomicity: An update should be all or nothing; never have a situation where some updates to a single transaction or master item fail and some succeed. Whilst this should apply whether synchronising at data level or application level, it’s easier to fall into a situation where a partial update is made due to lack of understanding of the API.</li>
<li>Is your synchronisation dumb or smart: You will need to make a choice as to how much logic you embed into your synchronisation, and often they start dumb and evolve to smart. What this means is the amount of logic required to cover certain scenarios or use cases. At the stupid end, there is no logic and a simply try/catch block is placed around your processing to catch any exceptions. Conversely, at the smart end you may check for an entity’s existence, raise workflow events, or handle specific edge cases.</li>
</ul>
</div>
<h4>Summary</h4>
<p>This post hopefully has helped to explain the most common synchronisation strategies and pitfalls. It is by no means complete and we would like to hear your opinions.</p>
<p>The next post will discuss the various means i.e. file transfer, database, etc. available for data synchronisation.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/synchronisation-strategy/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Common issues when synchronising data between applications</title>
		<link>http://www.realisable.co.uk/common-issues-synchronising-data-applications</link>
		<comments>http://www.realisable.co.uk/common-issues-synchronising-data-applications#comments</comments>
		<pubDate>Fri, 16 Nov 2012 10:00:00 +0000</pubDate>
		<dc:creator>appiah</dc:creator>
				<category><![CDATA[master data]]></category>
		<category><![CDATA[synchronisation]]></category>
		<category><![CDATA[Transactions]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1416</guid>
		<description><![CDATA[In this first of a series of posts, I will layout some of the common issues encountered specifically when synchronising data between applications. Synchronisation is the replication of data between two or more applications. It is usually more than a &#8230; <a href="http://www.realisable.co.uk/common-issues-synchronising-data-applications">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<p>In this first of a series of posts, I will layout some of the common issues encountered specifically when synchronising data between applications.</p>
<p>Synchronisation is the replication of data between two or more applications. It is usually more than a one-way push. Synchronisation is the continued updating of data to keep all applications reflecting the same view.</p>
<p>Firstly, there are two broad categories, each with its own set of properties, that data falls into:</p>
<h4>Master Data</h4>
<p>Master Data is conceptualised as key entities used within an organisation. Customers, Employees, Items &amp; Suppliers are all considered master data. At the simple end of synchronising, Master Data records involve a single record of data per entity. However, Master Data often has a number of child attributes such as addresses for customers, bank details for employees, and a range of attributes such as locations, suppliers and units of measure for items.</p>
<p><img class="aligncenter size-full wp-image-1417" title="Child Attributes" src="http://www.realisable.co.uk/wp-content/uploads/2012/11/Child-Attributes.jpg" alt="Child Attributes" width="600" height="344" /></p>
<p>It is increasingly expected that Master Data be updatable from multiple applications where each application holds its own copy of a common ‘truth’.</p>
<h4>Transactional Data</h4>
<p>Whilst sometimes more complex due to their header/detail structure transactions, they are usually easier to synchronise due to the following characteristics:</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Simple direction/flow – One application is the master and the other(s) are slaves thus eliminating issues such as conflicts.</li>
<li>Transactions are less likely to be updated – Once a transaction is posted it has reached its final state and requires only a single push to the target application. There are however a couple of notable exceptions: Sales &amp; Purchase Orders often need to be synchronised to reflect their current ‘state’ and because of their more complex structure and heavy business logic require careful attention. Further, Customer &amp; Supplier Payments can have a complex many-to-many interaction with their corresponding invoice documents.</li>
</ul>
</div>
<p>There is a third category: Master Data with transactional properties. An example of this is a project structure, where the project goes through several stages throughout its life and where each stage has different business rules affecting its behaviour.</p>
<h3>Issues Surrounding Synchronisation</h3>
<p>Data Structure Complexity – More complex data involving header, details, sub-details, etc need strategies which address changes for each ‘level’ of data.</p>
<p>Synchronisation &amp; Conflict Resolution</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Synchronisation needs to be considered at each level of data.</li>
<li>Deciding which application, if any, is the master or whether bi-directional integration will be supported.</li>
<li>Conflict Resolution – What rules should be followed where there is a conflict and is there sufficient data available to resolve a conflict and/or data storage to mediate conflicts?</li>
</ul>
</div>
<p>Data Impedance &amp; Mismatch – The higher the resistance or more transformation required the less able you are to synchronise it.</p>
<div class="bulletedtext">
<ul class="bulletedtext">
<li>Field Level Transformation – Destructive transformation, where the result of a derived or calculated field cannot be applied in reverse or accurately reversed can prevent bi-directional synchronisation.</li>
<li>Field Lengths and Type Differences – Two common issues arise: truncation of textual fields such as name, addresses &amp; comments, and the mapping of enumerated fields i.e. drop down fields, where the choice is identified as an integer value within the source or target application.</li>
<li>Data Structure Mapping – Cases where the structure of the source data does not match the target and where transformation is required to massage the data into the required shape.</li>
</ul>
</div>
<p>Data Interchange – As the sophistication, complexity and/or frequency of the synchronisation increases so does the requirement for more sophisticated means for transferring data.</p>
<p>Data Take On – Finally, issues around the amount of historical data, whether the load time for data is significant and whether data cleansing for old or historical data needs to take place.</p>
<p>In subsequent posts I will describe the various strategies available to resolve these issues.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/common-issues-synchronising-data-applications/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Achieving the original aim?</title>
		<link>http://www.realisable.co.uk/achieving-original-aim</link>
		<comments>http://www.realisable.co.uk/achieving-original-aim#comments</comments>
		<pubDate>Fri, 02 Nov 2012 10:00:20 +0000</pubDate>
		<dc:creator>appiah</dc:creator>
				<category><![CDATA[IMan]]></category>

		<guid isPermaLink="false">http://www.realisable.co.uk/?p=1359</guid>
		<description><![CDATA[If you’re working with a single product day-in day-out for three and a half years you can sometimes lose sight of what you’re trying to achieve: tunnel vision! My aim in creating IMan is to create a general purpose integration &#8230; <a href="http://www.realisable.co.uk/achieving-original-aim">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="contenttext">
<p>If you’re working with a single product day-in day-out for three and a half years you can sometimes lose sight of what you’re trying to achieve: tunnel vision! My aim in creating IMan is to create a general purpose integration platform with a strong focus on usability and one which is flexible enough to cover 95% of all integration requirements.</p>
<p>Have these been achieved? I would like to share some insights on the development process, the goals, and some of the problems I encountered along the way.</p>
<h3>Five favourite parts of IMan</h3>
<h4>The Preview</h4>
<p>The preview grid, situated at the right half of each transform setup interface, is populated with the results of the transformation each time the ‘Refresh’ button is pressed. It is one of the key pieces to facilitate easy and rapid integration design and, as one user put it, with the preview area ‘you’re not working blind’. Development, however, was not easy! Several weeks were spent, several calls made to Microsoft developer support, and many grey hairs grew! The end product involves a multi-threaded WCF windows service with out-of-process COM Interop (I learnt a lot)! The end result is that multiple designers can be working simultaneously on a single instance of IMan.</p>
<h4>Common Connector Interface</h4>
<p>The same interface is used for mapping Sage300 as Sage200 as SageCRM. This has been an evolutionary development, but it results in a common interface for every application, especially helping those consultants working with multiple products.</p>
<h4>Hierarchical Support &amp; Associated Transforms:</h4>
<p>There was no point in producing another integration product where hierarchical data support was shoe-horned, so IMan has been built from the ground up to support hierarchical data. The goal is to make the design process as intuitive as possible, whilst increasing the software’s flexibility.</p>
<h4>Free Form Designer</h4>
<p>To achieve the ‘95% integration coverage’ IMan is designed so that each transform/node within the integration can be linked to the previous transform ad infinitum, permitting multiple transforms to be linked or branched to build complex integration logic.</p>
<p>The major challenge was to provide a design surface which allowed interactive diagram creation similar to that of a flowchart i.e. to visualise the underlying implementation. Also, it needed to be in a web environment.</p>
<p>To achieve this, the only real choice was to use an off-the-shelf diagramming component (not an easy task as it needed to conform to web 2.0; it was 3.5 years ago). In-house development of such a component would have been sheer lunacy.</p>
<p>The result is the design surface we have today. We believe it facilitates everything from simple dataflows through to more complex integrations. Further, due to the flexibility, we’ve seen several of our customers use IMan for complex process automation, far beyond my original intention of IMan as a general integration tool.</p>
<h4>Drop In Connectors &amp; SDK</h4>
<p>As a general integration tool, IMan required a means to connect other applications through their APIs, particularly with the marked increase of hosted applications where a webservice connection is the only choice. The initial thought was to create a generic webservice connector, but the different protocols, implementation and necessary logic, plus a UI to configure it was just too complex (just look at <a href="http://sdata.sage.com/">SData</a> for example), and out-of-step with IMan’s focus on usability.</p>
<p>To facilitate this, we’ve taken a low level approach and added the ability for third parties to develop their own connectors for external applications, web services, etc.</p>
<p>I believe we’ve taken the correct approach as IMan gives you the ability to connect to any application, not just webservices; further, it enables the developer to add ‘smarts’ into any connector.</p>
<p>From a developer’s perspective, I think the thought of connector add-ins is awesome!</p>
<p>Our partner, EC Internet, has already developed the Magento connector, with two more on the way for Vortex ASP.Net Storefront eCommerce platform and Sage Pro.</p>
<h3>Least Favourite</h3>
<p>It’s only fair to share this, so here’s the hall of shame! Needless to say each of the points below are on the enhancement list:</p>
<h4>The Diagram Component</h4>
<p>It’s not that bad, but it can be slow, clunky, and connectors can be difficult to manipulate, especially on large graphs.</p>
<h4>Setting Up Hierarchical Datasources</h4>
<p>Field names aren’t inferred for file based datasources, so you need to enter them manually, and the screen handling could be better!</p>
<h4>Setup Tab Load</h4>
<p>Why does it take so long to click on the setup tab?</p>
<h4>Load Time</h4>
<p>Not our fault, but I am pretty sure we could do better!</p>
<p>We’d like to know your thoughts: have we achieved our design goals? Are there other clunky features which need improving?</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/achieving-original-aim/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Main Page Image 5</title>
		<link>http://www.realisable.co.uk/main-page-image-5</link>
		<comments>http://www.realisable.co.uk/main-page-image-5#comments</comments>
		<pubDate>Mon, 12 Oct 2009 10:27:57 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Featured]]></category>

		<guid isPermaLink="false">http://picturetype.com/realisable/?p=315</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://www.realisable.co.uk/main-page-image-5/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
