VST – Amount in Words on SOP Entry window

October 19, 2009

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 impliedusing 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/


RW – Working with POSTNET barcodes for US zip codes

September 13, 2009

The Postal Numeric Encoding Technique (POSTNET) is a barcoding system developed by the United States Postal Service to assist with automatic mail sorting and routing. The POSTNET barcode uses a combination of half-bars and full-bars to encode the zip code that appears on a mail piece. The barcode starts and ends with a full bar (often called a guard rail or frame bar and represented as the letter “S” in the USPS TrueType Font).

In the United States, zip codes can be of 5 digits, 9 digits (also known as Zip+4), or 11 digits in the case of a specific delivery point. Each digit in the zip code is represented by 5 bars. Therefore a 5-digit zip code is represented by 25 bars. In addition, to ensurePOSTNET accuracy during mail processing, a check digit, which is five bars, is calculated and added to the zip code. Hence a 5-digit zip code would render a total of 32 bars: 25 bars for the 5-digit zip code + 5 bars for the check digit + the 2 enclosing guard rail bars. Hence, Zip+4 uses 52 bars, and a delivery point uses 62 bars.

To calculate the check digit, each digit in the zip code is added. The result is then subtracted from the nearest multiple of 10. For example, if each digit in the zip code 33076 is added, 3+3+0+7+6 = 19, and we subtract from the nearest multiple of 10, number 20, then the check digit is 1. Mathematically speaking 10 – (digit-sum mod 10). This will yield the following S330761S. This number is then represented by the following barcode (including the guard rails, represented by “S”):

While based on a binary system, the weight of each bar is different than in standard binary. The weight of each bar is as follows:

The following illustration shows are representation of all numbers:

To add zip code barcoding capabilities to a Report Writer report, for example an Invoice or a Check, you must first download and install the fonts. You can get a set of fonts from here. To install the fonts (the TTF files in the zipped file), extract the fonts to your My Documents folder, then copy them to your Windows\Fonts folder.

1) Open Report Writer and select the SOP Blank Invoice Form. Click the Layout button to open the report in the Layout window.

2) Add the RM_Customer_MSTR_ADDR.Zip field to both Report Header and Page Header sections. Set the fields properties to Invisible.

3) Create a string calculated field called (C) Postnet. Assign the RM_Customer_MSTR_ADDR.Zip field to this calculated field as shown in the picture:

4) Add the (C) Postnet calculated field to the Report Header and Page Header sections. Change the font to IDAutomationSPOSTNET. By now, your report layout should look like this:


5) Add the report to VBA. Go to Tools > Add Report to VBA.

6) Select all 4 fields, the 2 on the report header and the 2 on the page header and add them to VBA. Go to Tools > Add Fields to VBA.

7) Open the VBA Editor, locate the SOPBlankInvoiceForm (Report) object in the Project Explorer , double-click and add the following code:

Public Function EncodeZip(pZip As String) As String    Dim i As Integer    Dim sZip As String    Dim digitSum As Integer    Dim checkDigit As Integer

    sZip = "S"    digitSum = 0

    For i = 1 To Len(pZip)        If IsNumeric(Mid(pZip, i, 1)) Then            ' Concat the digit            sZip = sZip & Mid(pZip, i, 1)

            ' Add up the digits            digitSum = digitSum + CInt(Mid(pZip, i, 1))        End If    Next i

    ' Calculate check digit    checkDigit = 10 - (digitSum Mod 10)    sZip = sZip & CStr(checkDigit) & "S"

    EncodeZip = sZipEnd Function

Private Sub Report_BeforePH(SuppressBand As Boolean)    Dim sZip As String

    sZip = Zip    sZip = EncodeZip(sZip)    CPostnet = sZipEnd Sub

Private Sub Report_BeforeRH(SuppressBand As Boolean)    Dim sZip As String

    sZip = Zip    sZip = EncodeZip(sZip)    CPostnet = sZipEnd Sub

Compile the code.

8) Return to Microsoft Dynamics GP saving all changes as you exit.

9) Grant security to the modified report. Print an invoice to test.

I hope you found this article interesting and the implementation very simple. You can find the fonts and package file for this project at the bottom of this article.

Downloads

Postnet Fonts – Click here
v10 SOP Blank Invoice Form report – Click here

Until next post!

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


VBA – Creating a keyboard shortcut for a Microsoft Dynamics GP window expansion button

August 17, 2009

Well, I had been absent (more like out of ideas) from writing any new VBA articles. The truth is, they are hard to come by without giving away too many secrets. :-)

However, this one is worth giving away as I have seen many users request this feature to speed up data entry and processing. Take for example the Purchase Order Entry window. Won’t you just like the ability to press some combination of keys on your keyboard to quickly access the Vendor Detail Entry window where you can quickly change around shipping methods, or other information needed? Well this example shows just that, but can be used to add shortcuts to any other button control in any other Dynamics GP window.

The solution is simple:

1) Add a pixel size button to the window with Modifier.

2) Caption the button. Buttons can have captions preceeded with the ampersand (“&”) character, which in turn acts like a shortcut when used in combination with the Alt key on the keyboard.

As a personal choice, I captioned the button with &4, as the expansion button is Expansion Button 4.

3) In addition, we can change the button’s Visual properties to blend it in with the expansion button. I particularly prefer to stack these shortcut buttons on top of or next to the expansion button they will serve as a shortcut for.

4) The button can then be added to VBA where code can be written to force the execution the expansion button Change script. To run the Expansion Button 4 change script that will open the window, we use the Dynamics Continuum Integration library and pass-through Dexterity Sanscript.

Private Sub 4_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)    Dim CompilerApp As Object    Dim CompilerMessage As String    Dim CompilerError As Integer    Dim Commands As String

    ' Create link without having reference marked    Set CompilerApp = CreateObject("Dynamics.Application")    Commands = ""    Commands = Commands & "run script 'Expansion Button 4' of window POP_PO_Entry of form POP_PO_Entry;"

    ' Execute SanScript    CompilerError = CompilerApp.ExecuteSanscript(Commands, CompilerMessage)    If CompilerError  0 Then       MsgBox CompilerMessage    End IfEnd Sub

The following — and much simpler! — code will also do the trick for you non-Dexterity developers:

Private Sub 4_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)    ExpansionButton4.Value = 1End Sub

You will need to add the expansion button to VBA in addition to the pixel size button for the above code to work.

Very simple! Now when you go to the Purchase Order Entry screen, enter PO number and select a vendor, you can press Alt + 4 on the keyboard to open the associated window to the Vendor ID expansion button.

Hope you find this sample project useful.

Downloads

v10 – Sample Expansion Button shortcut package file – click here.

Until next post!

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


Getting started with VST: "Hello World!" – The Video

July 24, 2009

"End of Month + Net Days" payment terms due date calculation

July 16, 2009

Folks across the pond use payment terms and due dates that are not traditionally close the ones we are familiar with on this side of the hemisphere. “End of Month + Net Days” (EOM+ND) is a typical case.

In EOM+ND payment terms, an invoice becomes due a number of net days after the last day of the month for the invoice date. For example, if an invoice date is July 16 and we are on a payment term of EOM plus 45 net days, the invoice will not be due until September 14 — or 45 days from July 31.

Of course, you cannot manage this type of payment term request in GP, not out-of-the-box anyways, which most of the time will require a customization to deal with the issue.

In this article, I will examine setting up two SQL Server triggers: one on the PM Transaction Open File (dbo.PM20000) and another on the RM Open File (dbo.RM20101) tables. The triggers will use the Net Days field in the Payment Terms Master (dbo.SY03300) table to calculate the net days after the end of month to assign the invoice due date.

So here are the triggers:

trigger pmEOMPlusNet

-- Created by Mariano Gomez, MVP-- No warranties expressed or impliedCREATE TRIGGER pmEOMPlusNet ON dbo.PM20000 AFTER INSERTASBEGIN TRANSACTION;

BEGIN TRY  UPDATE A SET A.DUEDATE =    DATEADD(dd, B.DUEDTDS, DATEADD(dd, -1, DATEADD(mm, DATEDIFF(mm, 0, I.DOCDATE) + 1, 0)))  FROM PM20000 A    INNER JOIN INSERTED I ON (A.VCHRNMBR = I.VCHRNMBR) AND (A.DOCTYPE = I.DOCTYPE)    LEFT OUTER JOIN SY03300 B ON (I.PYMTRMID = B.PYMTRMID)  WHERE (I.DOCTYPE = 1) AND (I.PYMTRMID LIKE 'EOMPLUSND%')END TRYBEGIN CATCH  SELECT ERROR_NUMBER() AS ErrorNumber    , ERROR_SEVERITY() AS ErrorSeverity    , ERROR_STATE() AS ErrorState    , ERROR_PROCEDURE() AS ErrorProcedure    , ERROR_LINE() AS ErrorLine    , ERROR_MESSAGE() AS ErrorMessage;

  IF @@TRANCOUNT > 0    ROLLBACK TRANSACTION;END CATCH;

IF @@TRANCOUNT > 0  COMMIT TRANSACTION;GO

trigger rmEOMPlusNet

-- Created by Mariano Gomez, MVP-- No warranties expressed or impliedCREATE TRIGGER rmEOMPlusNet ON dbo.RM20101 AFTER INSERTASBEGIN TRANSACTION;

BEGIN TRY  UPDATE A SET A.DUEDATE =    DATEADD(dd, B.DUEDTDS, DATEADD(dd, -1, DATEADD(mm, DATEDIFF(mm, 0, I.DOCDATE) + 1, 0)))  FROM RM20101 A    INNER JOIN INSERTED I ON (A.CUSTNMBR = I.CUSTNMBR) AND (A.DOCNUMBR = I.DOCNUMBR)      AND (A.RMDTYPAL = I.RMDTYPAL)    LEFT OUTER JOIN SY03300 B ON (I.PYMTRMID = B.PYMTRMID)  WHERE (I.RMDTYPAL= 1) AND (I.PYMTRMID LIKE 'EOMPLUSND%')END TRYBEGIN CATCH  SELECT ERROR_NUMBER() AS ErrorNumber    , ERROR_SEVERITY() AS ErrorSeverity    , ERROR_STATE() AS ErrorState    , ERROR_PROCEDURE() AS ErrorProcedure    , ERROR_LINE() AS ErrorLine    , ERROR_MESSAGE() AS ErrorMessage;

  IF @@TRANCOUNT > 0    ROLLBACK TRANSACTION;END CATCH;

IF @@TRANCOUNT > 0  COMMIT TRANSACTION;GO

Setting up the payment term in Dynamics GP

Open the Payment Terms Setup window (MSDGP > Tools > Setup > Company > Payment Terms) and configure the payment term as shown below:


NOTE: You can still setup discount and discount types for the payment term, but these will be calculated based on the document date. If you need these to apply based on EOM as well, you will need to change the above triggers to reflect the discount calculation based on EOM as well.

Finally, once setup, these payment terms can be used from SOP and POP. Just keep in mind that the due dates will not be calculated while the transactions are stored in a batch, but rather when posted.

Until next post!

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


"End of Month + Net Days" payment terms due date calculation

July 16, 2009

Folks across the pond use payment terms and due dates that are not traditionally close the ones we are familiar with on this side of the hemisphere. “End of Month + Net Days” (EOM+ND) is a typical case.

In EOM+ND payment terms, an invoice becomes due a number of net days after the last day of the month for the invoice date. For example, if an invoice date is July 16 and we are on a payment term of EOM plus 45 net days, the invoice will not be due until September 14 — or 45 days from July 31.

Of course, you cannot manage this type of payment term request in GP, not out-of-the-box anyways, which most of the time will require a customization to deal with the issue.

In this article, I will examine setting up two SQL Server triggers: one on the PM Transaction Open File (dbo.PM20000) and another on the RM Open File (dbo.RM20101) tables. The triggers will use the Net Days field in the Payment Terms Master (dbo.SY03300) table to calculate the net days after the end of month to assign the invoice due date.

So here are the triggers:

trigger pmEOMPlusNet

-- Created by Mariano Gomez, MVP-- No warranties expressed or impliedCREATE TRIGGER pmEOMPlusNet ON dbo.PM20000 AFTER INSERTASBEGIN TRANSACTION;

BEGIN TRY  UPDATE A SET A.DUEDATE =    DATEADD(dd, B.DUEDTDS, DATEADD(dd, -1, DATEADD(mm, DATEDIFF(mm, 0, I.DOCDATE) + 1, 0)))  FROM PM20000 A    INNER JOIN INSERTED I ON (A.VCHRNMBR = I.VCHRNMBR) AND (A.DOCTYPE = I.DOCTYPE)    LEFT OUTER JOIN SY03300 B ON (I.PYMTRMID = B.PYMTRMID)  WHERE (I.DOCTYPE = 1) AND (I.PYMTRMID LIKE 'EOMPLUSND%')END TRYBEGIN CATCH  SELECT ERROR_NUMBER() AS ErrorNumber    , ERROR_SEVERITY() AS ErrorSeverity    , ERROR_STATE() AS ErrorState    , ERROR_PROCEDURE() AS ErrorProcedure    , ERROR_LINE() AS ErrorLine    , ERROR_MESSAGE() AS ErrorMessage;

  IF @@TRANCOUNT > 0    ROLLBACK TRANSACTION;END CATCH;

IF @@TRANCOUNT > 0  COMMIT TRANSACTION;GO

trigger rmEOMPlusNet

-- Created by Mariano Gomez, MVP-- No warranties expressed or impliedCREATE TRIGGER rmEOMPlusNet ON dbo.RM20101 AFTER INSERTASBEGIN TRANSACTION;

BEGIN TRY  UPDATE A SET A.DUEDATE =    DATEADD(dd, B.DUEDTDS, DATEADD(dd, -1, DATEADD(mm, DATEDIFF(mm, 0, I.DOCDATE) + 1, 0)))  FROM RM20101 A    INNER JOIN INSERTED I ON (A.CUSTNMBR = I.CUSTNMBR) AND (A.DOCNUMBR = I.DOCNUMBR)      AND (A.RMDTYPAL = I.RMDTYPAL)    LEFT OUTER JOIN SY03300 B ON (I.PYMTRMID = B.PYMTRMID)  WHERE (I.RMDTYPAL= 1) AND (I.PYMTRMID LIKE 'EOMPLUSND%')END TRYBEGIN CATCH  SELECT ERROR_NUMBER() AS ErrorNumber    , ERROR_SEVERITY() AS ErrorSeverity    , ERROR_STATE() AS ErrorState    , ERROR_PROCEDURE() AS ErrorProcedure    , ERROR_LINE() AS ErrorLine    , ERROR_MESSAGE() AS ErrorMessage;

  IF @@TRANCOUNT > 0    ROLLBACK TRANSACTION;END CATCH;

IF @@TRANCOUNT > 0  COMMIT TRANSACTION;GO

Setting up the payment term in Dynamics GP

Open the Payment Terms Setup window (MSDGP > Tools > Setup > Company > Payment Terms) and configure the payment term as shown below:


NOTE: You can still setup discount and discount types for the payment term, but these will be calculated based on the document date. If you need these to apply based on EOM as well, you will need to change the above triggers to reflect the discount calculation based on EOM as well.

Finally, once setup, these payment terms can be used from SOP and POP. Just keep in mind that the due dates will not be calculated while the transactions are stored in a batch, but rather when posted.

Until next post!

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


How to calculate the number of days a vendor check takes to clear?

July 7, 2009

I am always amazed at the things you can do with Microsoft Dynamics GP. Just recently, a user pointed out that the Days for Checks to Clear field on the Vendor Credit Summary window was always blank and that they needed this field to update automatically.

According to the help file, the field is defined as “View or change the average number of days that a check you issue to the vendor usually takes to clear your bank.“, in other words, you can manually update it if you need to track this data.

The user also pointed out that they performed daily bank reconciles and that the Cleared Date column in the CM Transaction (dbo.CM20200) table was reflective of the actual check cleared date in the bank and that they would like to use this field to update the Days for Checks to Clear field in the Vendor Credit Summary window. After all, the date value of the Cleared Date column only gets updated when the check is marked as cleared during a checkbook reconciliation process and does not necessarily reflect the actual date the check cleared the bank, but with daily bank reconciles this should not be an issue, because the would be one of the same.

So, if you perform daily bank reconciliations and would like to know the average days a vendor check takes to clear your bank, you could use the following T-SQL query to update this column value:

-- Created by Mariano Gomez, MVPWITH AVGCTE(VENDORID, AVGDAYS) AS (  SELECT A.CMLinkID, AVG(DATEDIFF(DD, A.TRXDATE, A.clearedate)) AS AVGDAYS  FROM CM20200 A  GROUP BY A.CMLinkID)UPDATE PM00201 SET DYCHTCLR = AVGDAYSFROM PM00201 INNER JOIN AVGCTE ON (PM00201.VENDORID = AVGCTE.VENDORID)

Now what to do with the script? You can schedule it as part of a SQL Server job that will run daily to update this value for you! This will allow you to have accurate average days for each vendor and in turn will allow you to make better purchasing decisions to preserve your hard earned cash.

Until next post!

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


How to calculate the number of days a vendor check takes to clear?

July 7, 2009

I am always amazed at the things you can do with Microsoft Dynamics GP. Just recently, a user pointed out that the Days for Checks to Clear field on the Vendor Credit Summary window was always blank and that they needed this field to update automatically.

According to the help file, the field is defined as “View or change the average number of days that a check you issue to the vendor usually takes to clear your bank.“, in other words, you can manually update it if you need to track this data.

The user also pointed out that they performed daily bank reconciles and that the Cleared Date column in the CM Transaction (dbo.CM20200) table was reflective of the actual check cleared date in the bank and that they would like to use this field to update the Days for Checks to Clear field in the Vendor Credit Summary window. After all, the date value of the Cleared Date column only gets updated when the check is marked as cleared during a checkbook reconciliation process and does not necessarily reflect the actual date the check cleared the bank, but with daily bank reconciles this should not be an issue, because the would be one of the same.

So, if you perform daily bank reconciliations and would like to know the average days a vendor check takes to clear your bank, you could use the following T-SQL query to update this column value:

-- Created by Mariano Gomez, MVPWITH AVGCTE(VENDORID, AVGDAYS) AS (  SELECT A.CMLinkID, AVG(DATEDIFF(DD, A.TRXDATE, A.clearedate)) AS AVGDAYS  FROM CM20200 A  GROUP BY A.CMLinkID)UPDATE PM00201 SET DYCHTCLR = AVGDAYSFROM PM00201 INNER JOIN AVGCTE ON (PM00201.VENDORID = AVGCTE.VENDORID)

Now what to do with the script? You can schedule it as part of a SQL Server job that will run daily to update this value for you! This will allow you to have accurate average days for each vendor and in turn will allow you to make better purchasing decisions to preserve your hard earned cash.

Until next post!

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


How to import the Vendor 1099 Box with Integration Manager

May 14, 2009

Business Situation

A few days aback I addressed an issue where the user needed to set the 1099 Box on the vendor import with Integration Manager. To my surprise, while there is a field to map the 1099 Type, there is no 1099 Box field in the Options collection in the Vendor import in IM. To make matters a bit more interesting, the user needed to have the 1099 Box filled based on some settings in the source system.

Solution

The 1099 Box is not accessible via Integration Manager, however we can create a small SQL Server stored procedure in the company database that will accept the vendor ID and the 1099 Box as parameters. The stored procedure in turn will update the vendor record with the value submitted.

dbo.uspUpdateVendor1099Box


-- Created by Mariano Gomez, MVP

IF OBJECT_ID ( N'dbo.uspUpdateVendor1099Box', N'P' ) IS NOT NULLDROP PROCEDURE uspUpdateVendor1099Box;GO
CREATE PROCEDURE dbo.uspUpdateVendor1099Box@VENDORID CHAR(21) = NULL,@TEN99BOXNUMBER SMALLINT = NULL,@RET_VAL INT OUTPUTAS
SET @RET_VAL = 0
IF (@VENDORID IS NULL) OR (@TEN99BOXNUMBER IS NULL)BEGIN SELECT @RET_VAL = 0; RETURNEND
BEGIN TRY UPDATE PM00200 SET TEN99BOXNUMBER = @TEN99BOXNUMBER WHERE VENDORID = @VENDORIDEND TRYBEGIN CATCH SELECT @RET_VAL = ERROR_NUMBER()END CATCH;GO
GRANT EXECUTE ON dbo.uspUpdateVendor1099Box TO DYNGRPGO

Now, in the Vendor integration, we can open the After Document event script and add the following VBScript code:

After Document


' Created by Mariano Gomez, MVPConst adUseClient = 3Const adCmdStoredProc = 4Const adSmallInt = 2Const adInteger = 3Const adChar = 129Const adParamInput = 1Const adExecuteNoRecords = 128
Dim oCnDim oCmdDim pVendorID, pTen99BoxNumber, pRetVal
set oCn = CreateObject("ADODB.Connection")oCn.ConnectionString = "database=" & GPConnection.GPConnIntercompanyIDoCn.CursorLocation = adUseClientGPConnection.Open(oCn)
With oCmd .ActiveConnection = oCn .CommandType = adCmdStoredProc or adExecuteNoRecords .CommandText = "dbo.uspUpdateVendor1099Box"
'Set parameters set pVendorID = .CreateParameter("VENDORID", adChar, adParamInput, 21, _ GetVariable("gVendorID")) .Parameter.Append pVendorID
set pTen99BoxNumber = .CreateParameter("TEN99BOXNUMBER", adSmallInt, _ adParamInput, 8, GetVariable("gBoxNumber")) .Parameter.Append pTen99BoxNumber
set pRetVal = .CreateParameter("RET_VAL", adInteger, adParamOutput) .Parameter.Append pRetVal
.ExecuteEnd With
If pRetVal.Value 0 Then' Error handling here, you can choose to write to IM's logEnd If

Since I am making use of global variables, gVendorID and gBoxNumber, we will need to capture both of these values in the vendor ID field script — we will no longer map the vendor ID since it’s necessary to use a field script.

Vendor ID field script


' Created by Mariano Gomez, MVPSetVariable "gVendorID", SourceFields("someSource.Vendor")SetVariable "gBoxNumber", SourceFields("someSource.Ten99Box")CurrentField.Value = SourceFields("someSource.Vendor")

This conclude our integration! Don’t get discourage if you don’t see a specific field mapping in IM. With little creativity and the right mindset you can always come around with a solution that is worth showcasing.

Until next post!

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


How to import the Vendor 1099 Box with Integration Manager

May 14, 2009

Business Situation

A few days aback I addressed an issue where the user needed to set the 1099 Box on the vendor import with Integration Manager. To my surprise, while there is a field to map the 1099 Type, there is no 1099 Box field in the Options collection in the Vendor import in IM. To make matters a bit more interesting, the user needed to have the 1099 Box filled based on some settings in the source system.

Solution

The 1099 Box is not accessible via Integration Manager, however we can create a small SQL Server stored procedure in the company database that will accept the vendor ID and the 1099 Box as parameters. The stored procedure in turn will update the vendor record with the value submitted.

dbo.uspUpdateVendor1099Box


-- Created by Mariano Gomez, MVP

IF OBJECT_ID ( N'dbo.uspUpdateVendor1099Box', N'P' ) IS NOT NULLDROP PROCEDURE uspUpdateVendor1099Box;GO
CREATE PROCEDURE dbo.uspUpdateVendor1099Box@VENDORID CHAR(21) = NULL,@TEN99BOXNUMBER SMALLINT = NULL,@RET_VAL INT OUTPUTAS
SET @RET_VAL = 0
IF (@VENDORID IS NULL) OR (@TEN99BOXNUMBER IS NULL)BEGIN SELECT @RET_VAL = 0; RETURNEND
BEGIN TRY UPDATE PM00200 SET TEN99BOXNUMBER = @TEN99BOXNUMBER WHERE VENDORID = @VENDORIDEND TRYBEGIN CATCH SELECT @RET_VAL = ERROR_NUMBER()END CATCH;GO
GRANT EXECUTE ON dbo.uspUpdateVendor1099Box TO DYNGRPGO

Now, in the Vendor integration, we can open the After Document event script and add the following VBScript code:

After Document


' Created by Mariano Gomez, MVPConst adUseClient = 3Const adCmdStoredProc = 4Const adSmallInt = 2Const adInteger = 3Const adChar = 129Const adParamInput = 1Const adExecuteNoRecords = 128
Dim oCnDim oCmdDim pVendorID, pTen99BoxNumber, pRetVal
set oCn = CreateObject("ADODB.Connection")oCn.ConnectionString = "database=" & GPConnection.GPConnIntercompanyIDoCn.CursorLocation = adUseClientGPConnection.Open(oCn)
With oCmd .ActiveConnection = oCn .CommandType = adCmdStoredProc or adExecuteNoRecords .CommandText = "dbo.uspUpdateVendor1099Box"
'Set parameters set pVendorID = .CreateParameter("VENDORID", adChar, adParamInput, 21, _ GetVariable("gVendorID")) .Parameter.Append pVendorID
set pTen99BoxNumber = .CreateParameter("TEN99BOXNUMBER", adSmallInt, _ adParamInput, 8, GetVariable("gBoxNumber")) .Parameter.Append pTen99BoxNumber
set pRetVal = .CreateParameter("RET_VAL", adInteger, adParamOutput) .Parameter.Append pRetVal
.ExecuteEnd With
If pRetVal.Value 0 Then' Error handling here, you can choose to write to IM's logEnd If

Since I am making use of global variables, gVendorID and gBoxNumber, we will need to capture both of these values in the vendor ID field script — we will no longer map the vendor ID since it’s necessary to use a field script.

Vendor ID field script


' Created by Mariano Gomez, MVPSetVariable "gVendorID", SourceFields("someSource.Vendor")SetVariable "gBoxNumber", SourceFields("someSource.Ten99Box")CurrentField.Value = SourceFields("someSource.Vendor")

This conclude our integration! Don’t get discourage if you don’t see a specific field mapping in IM. With little creativity and the right mindset you can always come around with a solution that is worth showcasing.

Until next post!

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