Monday, October 19, 2009

VST - Amount in Words on SOP Entry window

Background

Just recently, I came across a Microsoft Dynamics GP Partners forum question, requesting the ability to add the amount in words to the SOP Entry window and possibly other windows throughout the system. Certain requirements may seem very strange to some of us, but are based on actual customer requests elsewhere on this planet.

The proposed solution

As I have been lately talking about hybrid integrating applications development, I thought it would be more than appropriate for this occassion to show how this customization could be achieved with the use of Modifier and Visual Studio Tools for Microsoft Dynamics GP. The idea? Pretty simple! Add a text field to the SOP Entry window with Modifier, then build a forms dictionary application assembly with the Dictionary Assembly Generator that can be accessed from Visual Studio Tools. In Visual Studio, I would then create a Dynamics GP project that would reference the Application.Dynamics.ModifiedForms.dll to set the document amount in words to the text field added with Modifier, by calling the Report Writer function RW_ConvertToWordsAndNumbers. If this sounds all too complicated, I will show you how to build this customization in 4 steps.

1. Modify the SOP Entry form to include a local text field. The following screenshot shows the modified window with the text field, '(L) Amount In Words'. Don't forget to grant yourself security to the modified window in Dynamics GP.





2. Use the Dictionary Assembly Generator (DAG.EXE) tool provided with Visual Studio Tools to generate the Application.Dynamics.ModifiedForms.dll application assembly for the forms dictionary. Since DAG.EXE is a command line utility, go to the command prompt then go to the Visual Studio Tools SDK folder (typically under Program Files\Microsoft Dynamics\GP10 VS Tools SDK) to execute it, as follows:

dag.exe 0 "C:\Program Files\Microsoft Dynamics\GP\Dynamics.set" /F /N:Dynamics

3. Open Visual Studio and create a new Dynamics GP solution, SOPAmountInWords.



Once the solution has been created, you can proceed to add a reference to the forms dictionary application assembly.



Now you can proceed to add the following code in the editor:


// Created by Mariano Gomez, MVP
// No warranties conferred, express or implied
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Dexterity.Bridge;
using Microsoft.Dexterity.Applications;
using Microsoft.Dexterity.Applications.DynamicsModifiedDictionary;

namespace SOPAmountInWords
{
public class GPAddIn : IDexterityAddIn
{
// IDexterityAddIn interface
const short FUNCTIONAL = 1;
const short ORIGINATING = 2;

SopEntryForm sopEntryMod;
Microsoft.Dexterity.Applications.DynamicsDictionary.SopEntryForm sopEntry;

public void Initialize()
{

// create overload method for changes in the document total field
sopEntry = Dynamics.Forms.SopEntry;
sopEntry.SopEntry.OriginatingDocumentAmount.Change += new EventHandler(OriginatingDocumentAmount_Change);

}

void OriginatingDocumentAmount_Change(object sender, EventArgs e)
{
string amountInWords;

// retrieve amount in words
if (sopEntry.SopEntry.CurrencyViewButton.Value == ORIGINATING)
{
amountInWords = Dynamics.Functions.RwConvertToWordsAndNumbers_.Invoke(
sopEntry.SopEntry.OriginatingDocumentAmount.Value,
sopEntry.SopEntry.CurrencyId.Value,
0
);
}
else
{
amountInWords = Dynamics.Functions.RwConvertToWordsAndNumbers_.Invoke(
sopEntry.SopEntry.DocumentAmount.Value,
sopEntry.SopEntry.CurrencyId.Value,
0
);
}


// assign value to custom text field on modified form
try
{
sopEntryMod = DynamicsModified.Forms.SopEntry;
sopEntryMod.SopEntry.LocalAmountInWords.Clear();

sopEntryMod.SopEntry.LocalAmountInWords.Value = amountInWords;
}
catch (Exception ex)
{
MessageBox.Show("Error attempting to set modified form field value: {0}", ex.ToString());
}

}
}
}



Code Explanation

The first aspect of the code is to reference the namespace of the modified form applciation assembly. This will allow us to access the modified form object, SOP Entry. As a best practice, and to avoid working with extremely long object namespaces, I created two variables that reference the objects I need to work with. In addition, I defined two constants that will check whether the amount is being displayed in functional or originating currency as the wording will need to change accordingly.


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Dexterity.Bridge;
using Microsoft.Dexterity.Applications;
using Microsoft.Dexterity.Applications.DynamicsModifiedDictionary;

namespace SOPAmountInWords
{
public class GPAddIn : IDexterityAddIn
{
// IDexterityAddIn interface
const short FUNCTIONAL = 1;
const short ORIGINATING = 2;

SopEntryForm sopEntryMod;
Microsoft.Dexterity.Applications.DynamicsDictionary.SopEntryForm sopEntry;


In the Initialize() method, we will register a change event on the Originating Document Amount field, in turn Visual Studio will create the proper overload method that we will use to add the code to manage the display of the amount in words.


public void Initialize()
{

// create overload method for changes in the document total field
sopEntry = Dynamics.Forms.SopEntry;
sopEntry.SopEntry.OriginatingDocumentAmount.Change += new EventHandler(OriginatingDocumentAmount_Change);

}


In the OriginatingDocumentAmount_Change() method, we now can add the code to manage the display of the amount in words by invoking the RwConvertToWordsAndNumbers_() function, exposed via the Microsoft.Dexterity.Applications namespace (Applications.Dynamics.dll application assembly)


void OriginatingDocumentAmount_Change(object sender, EventArgs e)
{
string amountInWords;

// retrieve amount in words
if (sopEntry.SopEntry.CurrencyViewButton.Value == ORIGINATING)
{
amountInWords = Dynamics.Functions.RwConvertToWordsAndNumbers_.Invoke(
sopEntry.SopEntry.OriginatingDocumentAmount.Value,
sopEntry.SopEntry.CurrencyId.Value,
0
);
}
else
{
amountInWords = Dynamics.Functions.RwConvertToWordsAndNumbers_.Invoke(
sopEntry.SopEntry.DocumentAmount.Value,
sopEntry.SopEntry.CurrencyId.Value,
0
);
}


// assign value to custom text field on modified form
try
{
sopEntryMod = DynamicsModified.Forms.SopEntry;
sopEntryMod.SopEntry.LocalAmountInWords.Clear();

sopEntryMod.SopEntry.LocalAmountInWords.Value = amountInWords;
}
catch (Exception ex)
{
MessageBox.Show("Error attempting to set modified form field value: {0}", ex.ToString());
}

}

Note that the value of the CurrencyViewButton is checked to establish whether to display the amount in functional or originating, but also use the correct currency wording (dollars/cents, pounds/pensks, etc).

The Report Writer function is then called with the required parameters. Then the result is assigned to our exposed text box field.

4. Now we can build and deploy the solution. Copy the resulting application assembly to the AddIns folder under the GP installation folder. Launch Dynamics GP and go to the SOP Entry screen. You can enter a new document or browse through existing ones as the customization will fill in the text box appropriately.



Hopefully you enjoyed this simple and useful customization and learned a bit more about developing hybrid applications.

Downloads
You may download the zip file containing the Visual Studio solution, application assembly and package file with the customization. To install, copy the Application.Dynamics.ModifiedForms.dll and the SOPAmountInWords.dll files to the AddIns folder under Dynamics GP. Import the package file and grant yourself security to the modified SOP Entry window.

SOPAmountInWords.zipx - Click here to download

Until next post!

MG.-
Mariano Gomez, MIS, MCP, MVP
Maximum Global Business, LLC
http://www.maximumglobalbusiness.com/

No comments: