<?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>JeffDonovan : IPragmaticCoder</title>
	<atom:link href="http://ipragmaticcoder.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://ipragmaticcoder.com</link>
	<description>An account of the trials and tribulations of a pragmatic coder.</description>
	<lastBuildDate>Tue, 01 Jun 2010 17:50:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Posting Cash Receipts to Dynamics GP 10.0 using eConnect</title>
		<link>http://ipragmaticcoder.com/2010/06/01/posting-cash-receipts-to-dynamics-gp-10-0-using-econnect/</link>
		<comments>http://ipragmaticcoder.com/2010/06/01/posting-cash-receipts-to-dynamics-gp-10-0-using-econnect/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 17:50:24 +0000</pubDate>
		<dc:creator>Jey</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Dynamics GP 10.0]]></category>
		<category><![CDATA[eConnect]]></category>

		<guid isPermaLink="false">http://ipragmaticcoder.com/?p=7</guid>
		<description><![CDATA[A little over a year ago, I worked on a project for the company I was with to create an interface between the new billing and invoicing application and the accounting package they use, Dynamics GP 10.0, in order to allow the A/R team to post cash receipts to GP.  The project was to be [...]]]></description>
			<content:encoded><![CDATA[<p><img style="float: left; margin: 0.5em;" title="Microsoft Dynamics GP Logo" src="http://ipragmaticcoder.com/wp-content/uploads/2010/06/microsoft-dynamics-gp-logo.jpg" alt="" width="180" height="145" />A little over a year ago, I worked on a project for the company I was with to create an interface between the new billing and invoicing application and the accounting package they use, Dynamics GP 10.0, in order to allow the A/R team to post cash receipts to GP.  The project was to be done in ASP.Net 3.5 with some fancy Ajax and had to call WCF services for access to the data.  We also had to use the MVP design pattern implementing the Supervising Controller version.</p>
<p>All of this seems very easy with the exception of using the available APIs to talk to GP.  There is a lot of information out there with regards to GP, assuming you have access to Microsoft&#8217;s customer/partner source, otherwise, there is not a lot of information on the internet regarding this topic.  So, with that in mind, my goal is to help others learn how to use GP&#8217;s eConnect components.</p>
<p>As a little background, in our line-of-business (LOB) application that the company uses for billing and invoicing, we store information about services rendered to our clients, pricing structures each client uses, and the invoices generated from these services and billings.  Once an invoice is generated, the users then post this invoice data to GP using the web services API.  I will leave that discussion for another post.</p>
<p>When a check or wire transfer arrives from one of our clients, the A/R team uses the LOB application to search for the invoice the payment is being applied to.  Because our client may not send the pertinent information we would like from them, i.e. &#8211; invoice number, we have to be able to search on various pieces of information.  The company that uses this exists in the worker&#8217;s compensation domain and, therefore, needs to be able to search for an invoice based on information like invoice number, invoice date, client, patient name, claim number, SSN, service type, invoice amount, etc.  The A/R team also needs to be able to verify the services billed on the invoice and must be able to see detailed line item information which would be difficult, if not impossible, to setup in GP, hence, our external data store and business applications.  For this search capability, we used full-text indexed views and also allow for advanced searches.<br />
<span id="more-7"></span></p>
<p>The A/R team also does not perform this work once check at-a-time but works in batches of checks and since GP understands the idea of a batch of work, we mock-up the idea of a batch in the LOB application.  So, once a user creates a new batch, they then create a new payment, whether it be a check or a wire transfer with an identifier that we will call a check number.  The user then applies invoices to the check to be paid and the amount being applied to the invoice.  Once the batch has been entered with all of the checks and all of the invoices the checks are applied to, the user then posts the batch to GP.</p>
<p>So, in order to post a batch of cash receivables, let&#8217;s look at some code:</p>
<pre class="brush: c-sharp; ruler: true;">
        private string getNextPaymentNumber()
        {
            string paymentNumber = string.Empty;
            GetNextDocNumbers docNumbers = null;
            try
            {
                docNumbers = new GetNextDocNumbers();
                paymentNumber =
                        docNumbers.GetNextRMNumber(
                                GetNextDocNumbers.IncrementDecrement.Increment,
                                GetNextDocNumbers.RMPaymentType.RMPayments,
                                ConfigurationManager.ConnectionStrings[
                                                Settings.GPConnectionName].
                                                ConnectionString); // The ConnectionString to the GP database
            }
            finally
            {
                if( docNumbers != null )
                    docNumbers.Dispose();
            }
            return paymentNumber;
        }

        private void sendBatchToGreatPlains(IBatch batch, List&lt;ICashEntryCheck&gt; batchChecks)
        {
            CashEntryCheckManager manager = new CashEntryCheckManager
                        {
                                CheckPrototype = this.CheckPrototype,
                                CreditReasonPrototype = this.CreditReasonPrototype,
                                InvoicePrototype = this.InvoicePrototype
                        };
            foreach (ICashEntryCheck check in batchChecks)
            {
                if (string.IsNullOrEmpty(check.PaymentNumber))
                {
                    var cashReceiptProcessInfo = new eConnectProcessInfo();
                    var eConnect = new eConnectMethods();
                    var cashReceiptInsert = new taRMCashReceiptInsert();
                    var cashReceiptType = new RMCashReceiptsType();

                    var eConnectType = new eConnectType();

                    cashReceiptProcessInfo.ConnectionString = String.Empty;
                    cashReceiptType.eConnectProcessInfo = cashReceiptProcessInfo;

                    // the Cash Receipt (check, wire transfer, cash, credit card payment)
                    cashReceiptInsert.CUSTNMBR = check.ClientCode;
                    string paymentNumber = this.getNextPaymentNumber();
                    check.PaymentNumber = paymentNumber;
                    cashReceiptInsert.DOCNUMBR = paymentNumber;
                    cashReceiptInsert.DOCDATE = batch.BatchDate.ToString();
                    cashReceiptInsert.ORTRXAMT = check.Amount; // the amount of the check or wire transfer in our case
                    cashReceiptInsert.GLPOSTDT = batch.BatchDate.ToString();
                    cashReceiptInsert.BACHNUMB = batch.BatchNumber; // the externally generated batch number
                    cashReceiptInsert.BatchCHEKBKID = String.Empty;
                    cashReceiptInsert.CSHRCTYP = 0; // 0 is Check, 1 is Cash, 2 is CC
                    cashReceiptInsert.CHEKNMBR = check.CheckNumber; // the number of the client's check or wire transfers
                    cashReceiptInsert.LSTUSRED = batch.UpdatedBy;

                    cashReceiptType.taRMCashReceiptInsert = cashReceiptInsert;
                    Array.Resize(ref eConnectType.RMCashReceiptsType, 1);
                    eConnectType.RMCashReceiptsType[0] = cashReceiptType;

                    int index = 0;
                    // Resize the array to the number of invoices the payment applies
                    Array.Resize(ref eConnectType.RMApplyType, check.InvoiceList.Count);
                    foreach (ICashEntryInvoice invoice in check.InvoiceList)
                    {
                        // create the payment record
                        var paymentApply = new taRMApply();
                        paymentApply.APTODCNM = invoice.InvoiceNumber; // the document the payment is applied to, in this case, an invoice
                        paymentApply.APFRDCNM = cashReceiptInsert.DOCNUMBR; // the document of the payment
                        paymentApply.APPTOAMT = invoice.AmountToPay; // the amount of the payment to apply to the invoice, this cannot be more that the balance of the invoice or more than the amount recieved
                        paymentApply.APFRDCTY = 9; // Apply From Document Type =  Cash Receipt
                        paymentApply.APTODCTY = 1; // Apply To Document Type = Sales Invoice
                        paymentApply.APPLYDATE = batch.BatchDate.ToString();
                        paymentApply.GLPOSTDT = batch.BatchDate.ToString();

                        var payment = new RMApplyType {taRMApply = paymentApply};
                        eConnectType.RMApplyType[index] = payment;
                        index++;
                    }

                    // Serialize the object to XML
                    // the eConnect object calls the GP stored procedures which
                    // take XML documents as parameters
                    var stringWriter = new StringWriter();
                    var serializer = new XmlSerializer(typeof (eConnectType));
                    serializer.Serialize(stringWriter, eConnectType);

                    var cashReceiptDocument = stringWriter.ToString();

                    try
                    {
                        //Create the payment in GreatPlains
                        var success =
                            eConnect.eConnect_EntryPoint(
                                ConfigurationManager.ConnectionStrings[Settings.GPConnectionName].
                                    ConnectionString, // ConnectionString to the GP database
                                EnumTypes.ConnectionStringType.SqlClient,
                                cashReceiptDocument, EnumTypes.SchemaValidationType.None,
                                String.Empty);
                    }
                    finally
                    {
                        eConnect.Dispose();
                    }

                    // update our data store with the payment number, update date and updated by
                    check.UpdatedBy = batch.UpdatedBy;
                    manager.SaveCheck(check);
                }
            }
        }</pre>
<p>The getNextPaymentNumber method just calls the GetNextRMNumber method of the GetNextDocNumbers class to retrieve a receivables management payment number that is generated by GP.  You could also use GPs auto-incrementing batch number for the batches you create, but you will see that in my example, we generate our own batch identifiers.</p>
<p>Now, the sendBatchToGreatPlains method is where the fun and interesting stuff comes in.  You have to create various eConnect objects, the most important being the eConnectMethods.  This is the class that contains the facade method that inspects the data being sent into the method and understands the transaction being performed in order to call the appropriate stored procedures.  The next object to create is the eConnectType.  This is the class that contains all the arrays of the different transaction types that can be sent to GP and in the receivable management arena, we have cash receipts, RMCashReceiptsType, and applies or the document the receivable is applied to, taRMApply.  Once all the documents are created and associated, we then need to serialize the eConnectType to XML before calling the eConnect_EntryPoint method on the eConnect object.  We are serializing the objects to XML because the stored procedures in GP accept XML documents.</p>
<p>Lastly, you don&#8217;t see any error handling in the method because this method is used by a WCF service, using the Service Software Factory, and the implementation of the WCF service method catches any unhandled exception and returns it to the caller as a Success property of the Response object along with a MessageList which is just a List&lt;string&gt; property to be displayed to the user.  We are transmitting the payments to GP one-at-a-time so that we can update the check data in our external data store so that we know what checks to resubmit to GP once the user fixes the issue.  If we transmitted all checks in the batch at once, there would need to be some complicated logic to determine what payments actually were applied, if any, as the whole batch may be rolled back in the stored procedure.</p>
<p>If you have any questions, please feel free to contact me.  For a discussion of the Service Software Factory, please see the Pete Shearer&#8217;s <a href="http://www.peteonsoftware.com/index.php/category/web-services-software-factory/">posts</a>.</p>
<div align="right" style="float:right;padding:5px 0xp 0px 5px;"><a name="fb_share" type="button_count" share_url="http://ipragmaticcoder.com/2010/06/01/posting-cash-receipts-to-dynamics-gp-10-0-using-econnect/"></a></div>]]></content:encoded>
			<wfw:commentRss>http://ipragmaticcoder.com/2010/06/01/posting-cash-receipts-to-dynamics-gp-10-0-using-econnect/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

