If you want to control for which users your VBA Code runs... you can... in some situations.
VBA Code can run behind a Modified or Original Window in GP, or not at all, based on the event mode you select in the window properties in the VBA Editor:
You could modify a window mildly and place your code behind the modified version just so that you can control for which users the VBA code runs by only granting access to the modified window to certain users. This won't work in every situation such as those in which you need to modify the window for all users but only want VBA code to run for some.
Showing posts with label Modifier. Show all posts
Showing posts with label Modifier. Show all posts
25 August, 2010
22 August, 2010
Filtering Grids in Dynamics GP with Modifier/VBA
It is pretty simple to apply custom filters to grids in Dynamics GP to control the data that loads into Lookups and Transaction Entry Windows.
In this example, my client wanted to be able to filter the Contract Maintenance - Lines window by Item Number and/or Serial Number. Their contracts can be quite lengthy. Research and contract maintenance would be cumbersome and inefficient without the ability to filter the records in this window.
To do this, use Modifier to add 2 new Text Boxes to the Contract Maintenance - Lines window in which to capture the filter criteria. I placed them directly above the grid in the window.
Next, add the Contract Maintenance - Lines window and the following fields to your VBA Project:
In this example, my client wanted to be able to filter the Contract Maintenance - Lines window by Item Number and/or Serial Number. Their contracts can be quite lengthy. Research and contract maintenance would be cumbersome and inefficient without the ability to filter the records in this window.
To do this, use Modifier to add 2 new Text Boxes to the Contract Maintenance - Lines window in which to capture the filter criteria. I placed them directly above the grid in the window.
Next, add the Contract Maintenance - Lines window and the following fields to your VBA Project:
- Item Number and Serial Number in the Grid
- Item Number and Serial Number fields you added with Modifier
Paste the following code in the ContractMaintenanceLDetail Grid BeforeLinePopulate event:
Now, just click the Redisplay button to apply the filter.
This code will evaluate records as they are populated in the grid and reject those that don't match the filter criteria. In this case, I used the Like operator so that any records that did not contain the filter criteria would be rejected.
19 January, 2010
Hybrid Development: Using VST to overcome the Cyclic reference of projects constraint in VBA
When customizing GP with Modifier/VBA you may run into situations where you need to create cyclic references between .vba Projects. In this example, I needed to allow the assignment a Contract Type to each Item in Item Maintenance to meet a Customer's requirement. Contract Type Lookup is in the Field Service dictionary and Item Maintenance is in the Dynamics dictionary.
I first tried using VBA to 1) Open the Contract Lookup after clicking on a lookup push button I added to Item Maintenance and then 2) Update a new string field I added to capture and display the Contact Type assigned to each item in Item Maintenance. To do this with VBA I had to open Contract Lookup from Item Maintenance in the Dynamics dictionary and then set the value in my custom string field on Item Maintenance on the Contract Type Lookup Select After User Changed Event. To do this, I would have to set a reference from Dynamics to FieldService AND from FieldService to Dynamics. You'll quickly discover that this is not permitted in VBA.
Before the introduction of VST you would have had to create your own lookup window. A workable solution, but not optimal. Now, with the VST for GP the solution is simple. You can use the Dictionary Assembly Generator (Dag.exe) to create an application assembly for your modified forms. This is required to access local fields added to windows in GP using Modifier. Over at The Dynamics GP Blogster, Mariano does a good job describing how to do use the Dag.exe in one of his posts on hybrid development techniques. Mariano explains:
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
After adding a reference to the Application.Dynamics.ModifiedForms.dll that to your VST project, you are able to use VST to launch Contract Type Lookup from Item Maintenance and set the value in Item Maintenance on the Contract Type Lookup Select After User Changed Event without issue. The GPAddin.vb code may look like this:
The end result is the native Field Service Contract Type Lookup window nicely bound to the Dynamics Item Maintenance Window:
I first tried using VBA to 1) Open the Contract Lookup after clicking on a lookup push button I added to Item Maintenance and then 2) Update a new string field I added to capture and display the Contact Type assigned to each item in Item Maintenance. To do this with VBA I had to open Contract Lookup from Item Maintenance in the Dynamics dictionary and then set the value in my custom string field on Item Maintenance on the Contract Type Lookup Select After User Changed Event. To do this, I would have to set a reference from Dynamics to FieldService AND from FieldService to Dynamics. You'll quickly discover that this is not permitted in VBA.
Before the introduction of VST you would have had to create your own lookup window. A workable solution, but not optimal. Now, with the VST for GP the solution is simple. You can use the Dictionary Assembly Generator (Dag.exe) to create an application assembly for your modified forms. This is required to access local fields added to windows in GP using Modifier. Over at The Dynamics GP Blogster, Mariano does a good job describing how to do use the Dag.exe in one of his posts on hybrid development techniques. Mariano explains:
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
After adding a reference to the Application.Dynamics.ModifiedForms.dll that to your VST project, you are able to use VST to launch Contract Type Lookup from Item Maintenance and set the value in Item Maintenance on the Contract Type Lookup Select After User Changed Event without issue. The GPAddin.vb code may look like this:
The end result is the native Field Service Contract Type Lookup window nicely bound to the Dynamics Item Maintenance Window:
Next, you would need to save the Contract Type associated with the Item Number to the database. You could do that using either VST or VBA. That's beyond the scope of what I was trying to communicate here but not a bad subject for a future post. Let me know what you think.
30 September, 2009
Avoid some GP Form Modifications with VSTools
I've been doing a lot of work with Visual Studio Tools lately and find myself migrating more towards that from VBA. VSTools is not a replacement for VBA but in some cases can prove to be a more effective tool.
Modifying a Form in GP is often a simple thing to do with few repercussions if planned and executed properly. One drawback to a form modification is that you have to upgrade the modified forms even when applying service packs. This makes the service pack application and upgrade processes slightly more cumbersome. Not a big deal but another step in the process that in some instances you might be able to avoid. Some of my existing clients are starting to request VSTools customizations over VBA partly for this reason.
While this isn't always applicable, you can't modify a GP Form with VSTools after all, you can sometimes leverage the VSTools .AddMenuHandler method in place of modifying a form in GP. You can find more information about the .AddMenuHandler on page 71 of the VSTDGPProgrammersGuide.pdf.
Here's an example of how to use the .AddMenuHandler method instead of modifying a GP Form:
Below is the code to add an Additional Menu Handler that when executed calls a function that will retrieve the next numeric Fixed Asset ID and populate the Asset ID in the Asset General Information Window.
Dim FANextNumericID As System.EventHandler
Sub Initialize() Implements IDexterityAddIn.Initialize
FANextNumericID = New System.EventHandler(AddressOf FAGetNextNumericID)
FixedAssets.Forms.FaGeneralMaintenance.AddMenuHandler(FANextNumericID, "Next Asset ID", "N")
End Sub
Now, in GP you can simply use the Ctrl-N hotkey or select Next Asset ID from the Additional Menu…
… to assign the Next Numeric Fixed Asset ID to new Fixed Asset Record.
Now, not only do you not have to deal with merging Form Modifications and/or VBA code with existing Form Modifications or VBA projects but if there weren't any to begin with you don't have to deal with upgrading them when applying services packs or upgrading.
Modifying a Form in GP is often a simple thing to do with few repercussions if planned and executed properly. One drawback to a form modification is that you have to upgrade the modified forms even when applying service packs. This makes the service pack application and upgrade processes slightly more cumbersome. Not a big deal but another step in the process that in some instances you might be able to avoid. Some of my existing clients are starting to request VSTools customizations over VBA partly for this reason.
While this isn't always applicable, you can't modify a GP Form with VSTools after all, you can sometimes leverage the VSTools .AddMenuHandler method in place of modifying a form in GP. You can find more information about the .AddMenuHandler on page 71 of the VSTDGPProgrammersGuide.pdf.
Here's an example of how to use the .AddMenuHandler method instead of modifying a GP Form:
Below is the code to add an Additional Menu Handler that when executed calls a function that will retrieve the next numeric Fixed Asset ID and populate the Asset ID in the Asset General Information Window.
Dim FANextNumericID As System.EventHandler
Sub Initialize() Implements IDexterityAddIn.Initialize
FANextNumericID = New System.EventHandler(AddressOf FAGetNextNumericID)
FixedAssets.Forms.FaGeneralMaintenance.AddMenuHandler(FANextNumericID, "Next Asset ID", "N")
End Sub
Now, in GP you can simply use the Ctrl-N hotkey or select Next Asset ID from the Additional Menu…
22 June, 2009
Removing a Reference to a Field or Object in VBA
While upgrading some customizations to GP 10 I encountered a situation in which I needed to remove references to 4 fields out of 60+ on Sales Transaction Entry that had been added to VBA. Many of the valid references were to invisible fields. For a couple of reasons the standard method of copying the code to .txt, noting all of the fields that needed to be added back, removing the window from VBA, adding the window back along with all of the valid fields, and then pasting the code back in seemed very laborious.
It made sense in this instance to spend a few minutes trying to remove the invalid references without having to click so many buttons.
The steps to remove a field reference from a VBA Project are:
1. Export your Form with VBA to a .package file (Tools>>Customize>>Customization Maintenance).
2. Open the .package file with notepad and find the references to the field you need to remove.
3. Remove any references to your field. Most importantly, remove the WindowField reference. This is how VBA knows about the field. It will look like this:
WindowField "Transfer Button"
{
ArrayIndex "0"
DisplayName "Transfer"
Local "false"
ProgrammerName "Transfer Button"
}
4. Save your .package file and import the modified version. (Tools>>Customize>>Customization Maintenance).
NOTE: The technique described here directly modifies the contents of a customization package with Notepad. This technique is not supported by Microsoft Dynamics GP support.
It made sense in this instance to spend a few minutes trying to remove the invalid references without having to click so many buttons.
The steps to remove a field reference from a VBA Project are:
1. Export your Form with VBA to a .package file (Tools>>Customize>>Customization Maintenance).
2. Open the .package file with notepad and find the references to the field you need to remove.
3. Remove any references to your field. Most importantly, remove the WindowField reference. This is how VBA knows about the field. It will look like this:
WindowField "Transfer Button"
{
ArrayIndex "0"
DisplayName "Transfer"
Local "false"
ProgrammerName "Transfer Button"
}
4. Save your .package file and import the modified version. (Tools>>Customize>>Customization Maintenance).
NOTE: The technique described here directly modifies the contents of a customization package with Notepad. This technique is not supported by Microsoft Dynamics GP support.
17 June, 2009
Creating Drop Down Lists using Modifier with VBA
Inspired by a recent post on the GP Newgroup, I've taken the time to document a simple customization I recently did for a client. This is a very common type of request that is relatively easy to do and adds a lot of value. You can greatly improve the quality and consistency of your data by using custom drop down lists instead of settling with free form text fields.
Some background on this example; The client needs to track an invoice format for each Customer. They have 3 different invoice formats and it is critical that each customer is assigned a valid format. This client uses Contract Administration for Billing. Another customization is reliant on this field to assign the Contract Type to new Contracts that corresponds to the customer's invoice format so that invoices are batched properly when Contracts are billed. Standardization and consistency are critical.




bolUserChanged = False
End Sub
If CustomerID.Empty = False Then
End Sub
Private Sub UserDefined2_Changed()
If bolUserChanged = False Then
End Sub

First, open the window, Customer Maintenance in this example, on which you want to add the drop down list and bounce into Modifier (CTRL+F10 or Tools>>Customize>>Modify Current Window).

In modifier, select the Drop-down List control from the Toolbox and add one to the Window. At this point, any free peice of real estate on the window will do. We'll move it into the right position later. I've added the (L) DDLM79 field you see just to the right of the City field in the screen shot below.

Next, change a few of the properties of the new Drop-down List (DDL) field. Click on the DDL and find the Properties window. It might be hidden behind another window. To activate it you could select Properties from the Layout Menu or enter CTRL+M.

On the Object Tab double click the Data Type entry to open the Local Field Definition window. I like to change the name to something logical; in this example, "ddlInvoiceFormat".

Then click the Static Value elipse to access the Static Text Values Window. Enter the values you want to appear in your drop down list and click Insert.
You're done with Modifier for now. Click Ok to close the Static Text Values and Local Field Definition Windows. Then select Microsoft Dynamics GP from the File menu to return to GP. When prompted, save the changes made to the window layout. Once back in GP, grant security to the modified window.
Now, you have a Drop-down List on your window with your static values. That's nice but only half the battle. Next, we need to add the VBA code to store the data. In this example, I chose to store the data in the User Defined 2 field on the Customer Maintenance window. You could have elected to store this in your own table (using ADO) or the DUOS.
To do this, open the Customer Maintenance window and add the window to your VBA project (CTRL+F11 or Tools>>Customize>>Add Current Window to Visual Basic). Then, add the fields you need on the window to your VBA project (Shift+F11 or Tools>>Customize>>Add Fields to Visual Basic). In this example, add the Customer ID, User Defined 2, and the new Drop-down List (ddlInvoiceFormat). Finally, open the VBA Editor (Alt+F11 or Tools>>Customize>>Visual Basic Editor) to add the code.
There is code on on 3 events:
Declare a variable to track whether or not a user has changed the Drop-down List (DDL) value.
Dim bolUserChanged As Boolean
On the CustomerID_Changed event set that variable to false.
Private Sub CustomerID_Changed()
bolUserChanged = False
End Sub
On the ddlInvoiceFormat_AfterUserChanged event set the UserDefined2 value equal to the Drop-down List value and the variable to True only if the CustomerID is empty. There's no point in setting the value otherwise.
Private Sub ddlInvoiceFormat_AfterUserChanged()
If CustomerID.Empty = False Then
bolUserChanged = True
UserDefined2.Value = ddlInvoiceFormat.Value
Else
Changed = False
bolUserChanged = False
End If
End Sub
Only if a User did not change the ddlInvoiceFormat value (bolUserChanged = False) set the ddlInvoiceFormat equal to the UserDefined2 value. This is how the value in the Drop-down List gets updated as you scroll through or select different records in the window. Of course, you wouldn't want to update the DDL if the user just changed it.
Private Sub UserDefined2_Changed()
If bolUserChanged = False Then
ddlInvoiceFormat.Value = UserDefined2.Value
End If
End Sub
The reason for putting the new Drop-down List field on the window anywhere space was available was to allow for testing and validation before moving it to a permanent place. You'll notice that the value stored in the User Defined field is an integer value that corresponds to each static text value. You could translate that with VBA and store the static text value or translate it when necessary later in a query or report. Once the code is in place and tested, go back into Modifier (Tools>>Customize>>Modify Current Window) to move it to a permanent position and in this case make the User Defined 2 field invisible.
Click on the User Defined 2 field and change the Visible Property to False. The new Drop-down List will replace that field on the window for the user.
Finally, move the new Drop-down List on top of the User Defined 2 field then change the tab sequence and size/align the field accordingly. The end result is a User Defined field that is no longer a free form text but rather a Drop-down List.

11 April, 2009
Dynamics GP for Equipment Rentals
I recently wrapped up an implementation in the role of solution architect for a multi-location Equipment Rental company. I discussed our design with some of the best GP consultants I know who expressed interest in hearing more. I hope you find this useful.
We chose to lead with the GP Field Service Series; Contract Administration, Returns Management, & Depot Management Module along with the Sales Order Processing and Inventory Control modules to handle Equipment Rental processes and requirements. I continue to be impressed by the variety of applications I have found for this suite of GP modules.
In this scenario, the process begins with the contract. A customer phones the inbound call center and requests equipment for a specified period of time. The call center agent enters the contract terms into Contract Entry/Update. We mapped Contract Type to the customer's Location/Warehouse and customized the way GL distributions were populated (More on that to come).
The Create Order push button simply creates a new sales order header using default from SOP Setup and values from Contract Entry/Update and forces a relationship between the Sales Order (GL Reference) and the Contract (Job). The user then only has to enter the order lines and set the requested ship date then let the standard order fulfillment process run its course.

If you have worked with the Contract Administration Module you would realize at this point that we didn't assign any equipment to the Contract. The business process in this scenario is to assign the equipment to the Contract only after the equipment has shipped to the customer. It's only at that point that you would know which serialized piece of equipment was shipped.
At this point, the equipment has been shipped to the customer and the clock is ticking on the contract. You may have noticed that we defaulted the Hold flag on Contract Entry/Update to true (Simply done with VBA). This prevents the contract from being invoiced before the equipment is returned and inspected signaling the completion of the contract. This is where we'll pick up the process next.

Next, follow the standard process for receive the RMA. This will adjust the returned equipment inventory into the designated In Service Location.

Once received, use the RMA Line Process Return window to create Depot Management Workorders for each item so that it can be inspected and returned to stock.

Post Labor and Parts to the Work Order(s) to track repair costs that might be billed back to the customer later. In this scenario, these charges would not be invoiced separately from the Contract Invoice. Rather, the labor and parts posted against the Work Order(s) will be used later in the process to apply additional repair charges to the Contract before it is billed.
After the parts and labor are posted and Work Order is complete we finished the inspection process by transferring the equipment from the In Service location back to general stock to be available for a future rental.

Linking the RMA to the invoice on which the equipment was shipped to the customer and the RMA to the Work Order against which inspection labor and parts are posted allows the backoffice to have visibility to returns of equipment and costs of inspection on unbilled contracts. There's a relationship between the RMA and Work Order all the way back to the Contract through the GL Reference:Job relationship created when the Sales Order was initially created from the Contract.

The final step in the process is to Bill the Contract to create the SOP Invoice to send to the customer for the rental, freight, and repair/inspection charges.

Now, you can enter and track all of your transactions, costs, inventory movements, etc. associated with managing your equipment rental business using the Dynamics GP Field Service Suite which comes packaged with your BRL. There's no need for spreadsheets or disparate systems to manage these processes. We customized this implementation to streamline data processing, ensure consistency, and enforce data integrity. However, you could opt to implement this process without any customization at all.
We chose to lead with the GP Field Service Series; Contract Administration, Returns Management, & Depot Management Module along with the Sales Order Processing and Inventory Control modules to handle Equipment Rental processes and requirements. I continue to be impressed by the variety of applications I have found for this suite of GP modules.
In this scenario, the process begins with the contract. A customer phones the inbound call center and requests equipment for a specified period of time. The call center agent enters the contract terms into Contract Entry/Update. We mapped Contract Type to the customer's Location/Warehouse and customized the way GL distributions were populated (More on that to come).
The next step is to use a push button we added to the Contract Entry/Update window to automate the generation of a Sales Order that the warehouse operations can fulfill to record the shipment of the equipment to the customer. This was a better fit than leveraging native functionality to create the Contract from SOP as the contract needed to be initiated before the SOP Invoice was posted. We setup the equipment as serialized inventory items without cost so that we could track shipments to customers and availability of equipment for rental.
The Create Order push button simply creates a new sales order header using default from SOP Setup and values from Contract Entry/Update and forces a relationship between the Sales Order (GL Reference) and the Contract (Job). The user then only has to enter the order lines and set the requested ship date then let the standard order fulfillment process run its course.

If you have worked with the Contract Administration Module you would realize at this point that we didn't assign any equipment to the Contract. The business process in this scenario is to assign the equipment to the Contract only after the equipment has shipped to the customer. It's only at that point that you would know which serialized piece of equipment was shipped.
We chose to automatically insert the equipment record on the Contract after the order was fulfilled, invoiced, and posted. We placed a trigger on SOP10201 to fire off a stored procedure that assigns the shipped serialized equipment records (SVC00300/SOP10201) to the Contract using the GL Reference:Job relationship. This is also where we assign the GL Account to the contract line based on the Location (SVC00600.CNTTYPE), Type of Customer (RM00101.USERDEF1), and Item Type (IV00101.USCATVLS_1) per the customer requirements.
At this point, the equipment has been shipped to the customer and the clock is ticking on the contract. You may have noticed that we defaulted the Hold flag on Contract Entry/Update to true (Simply done with VBA). This prevents the contract from being invoiced before the equipment is returned and inspected signaling the completion of the contract. This is where we'll pick up the process next.
We implemented the RMA module to track the returns of the equipment from the customer, send the equipment through the depot for inspection, and place the equipment back into stock to be available for future rental. The RMA and Depot Management modules were a great fit for this scenario.
We setup the RMA with a return path of none and to post the received inventory to an In Service Inventory Location. There's no need to credit or bill the customer for anything related to the RMA. We'll handle all of the charges when we bill the Contract later. We linked the RMA to the Invoice that we posted to record the shipment of the equipment to the customer.

Next, follow the standard process for receive the RMA. This will adjust the returned equipment inventory into the designated In Service Location.

Once received, use the RMA Line Process Return window to create Depot Management Workorders for each item so that it can be inspected and returned to stock.

Post Labor and Parts to the Work Order(s) to track repair costs that might be billed back to the customer later. In this scenario, these charges would not be invoiced separately from the Contract Invoice. Rather, the labor and parts posted against the Work Order(s) will be used later in the process to apply additional repair charges to the Contract before it is billed.
After the parts and labor are posted and Work Order is complete we finished the inspection process by transferring the equipment from the In Service location back to general stock to be available for a future rental.

Linking the RMA to the invoice on which the equipment was shipped to the customer and the RMA to the Work Order against which inspection labor and parts are posted allows the backoffice to have visibility to returns of equipment and costs of inspection on unbilled contracts. There's a relationship between the RMA and Work Order all the way back to the Contract through the GL Reference:Job relationship created when the Sales Order was initially created from the Contract.
The backoffice now knows that the equipment has been returned, received, and inspected. They can query the costs of repair/inspection and prepare the contract for invoicing. In this scenario they chose to add new contract lines for additional charges such as Freight and Repair.

The final step in the process is to Bill the Contract to create the SOP Invoice to send to the customer for the rental, freight, and repair/inspection charges.

Now, you can enter and track all of your transactions, costs, inventory movements, etc. associated with managing your equipment rental business using the Dynamics GP Field Service Suite which comes packaged with your BRL. There's no need for spreadsheets or disparate systems to manage these processes. We customized this implementation to streamline data processing, ensure consistency, and enforce data integrity. However, you could opt to implement this process without any customization at all.
Using this process also allows you to query all of your equipment; in your own inventory (IV00102 and/or IV00200) as well as the equipment that is out on a rental contract (SVC00300 and SVC00601). You can use this information for Available to Promise Reports.
You may have noticed the Create Project Button on the Contract Entry/Update window. We also integrated the FSS Contract with Project Accounting so that we could leverage PAS to track T&M activity related to the equipment rental. PAS was a better fit than Service Call management in this case and maintaining the relationship between the CA Contract and the PA Contract enabled us to report on the profitability of the relationship with the customer by combining both T&M project costs and billing with rental contract transactions.
15 March, 2009
Quick Lookups with Modifier & VBA
It seems that the last few times I have implemented Contract Administration I've had to work around the inherent restrictions on the Contract Number field by using another field, in this case User Defined 1, to track an internal Customer Contract Number; in this example "Job Number". Maybe I'm missing something here but this is how I was able to work around this.
It's nice that you can move the User Defined 1 field onto the Contract Entry/Update window and add it to the Contract Lookup with Modifier in just seconds. This isn't as simple on some other windows in GP:


The problem was that Contracts needed to be retrieved using this Job Number value. Depending on how you address that, it could have a much more significant impact on the project budget. In this case, the customer was just as happy entering the Job Number to retrieve the Contract Record as they would be if the field were added to the Find Function in the Contract Lookup window.
It's important to note in this example that Job Number uniqueness is forced across Contracts.
To do this in GP 10; first, create some Sub Procedures to make and close a connection to the database:
Option Explicit
'Declare variables for the ADO Connection
Dim cn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
Public Sub Get_ADOConnection()
'Get_NewConnection
Set cn = UserInfoGet.CreateADOConnection
cn.DefaultDatabase = UserInfoGet.IntercompanyID
cmd.ActiveConnection = cn
End Sub
Public Sub Close_ADOConnection()
cmd.ActiveConnection.Close
End Sub
Then, add some code behind UserDefined1 on the Before User Changed event to force uniqueness of Job Number across Contracts:
Private Sub UserDefined1_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)
On Error GoTo Proc_Error:
If ContractNumber.Empty = False Then
'Get_NewConnection
Get_ADOConnection
'Make sure the job number is not already assigned to a contract
cmd.CommandText = "select top 1 CONTNBR from SVC00600 where USERDEF1 = '" & Me.UserDefined1 & "'"
Set rst = cmd.Execute
'If a contact exists for this job notify the user and force them to enter a unique job number
If rst.EOF = False Then
MsgBox ("This Job Number has already been assigned to contract " & RTrim(rst.Fields("CONTNBR")) & ".")
CancelLogic = True
KeepFocus = True
End If
Close_ADOConnection
End If
GoTo Procedure_Exit:
Proc_Error:
MsgBox Error$ & " " & Error, vbOKOnly, "UserDefined1_BeforeUserChanged"
Procedure_Exit:
End Sub
Finally, add some code behind User Defined 1 on the After User Changed Event to query the Contract Master Table and retrieve the Contract to which the Job Number has previously been assigned:
Private Sub UserDefined1_AfterUserChanged()
On Error GoTo Proc_Error:
If ContractNumber.Empty = True Then
'Get_NewConnection
Get_ADOConnection
'Lookup the Contract for this Job
cmd.CommandText = "select top 1 CONTNBR from SVC00600 where USERDEF1 = '" & Me.UserDefined1 & "'"
Set rst = cmd.Execute
If rst.EOF = False Then
Clear = 1
ContractNumber = rst.Fields("CONTNBR")
Else
MsgBox ("This Job Number has not been assigned to a contract.")
End If
Close_ADOConnection
End If
GoTo Procedure_Exit:
Proc_Error:
MsgBox Error$ & " " & Error, vbOKOnly, "UserDefined1_BeforeUserChanged"
Procedure_Exit:
End Sub
The end result of this not only can you easily assign the Job Number (User Defined 1) to the Contract and view the Job Number in the Contract Lookup Window but, most importantly, you can pull the Contract into the Contract Entry/Update Window by keying into the Job Number field.
Simple, quick, cost effective solution that could be applied to a variety of windows in GP.
It's nice that you can move the User Defined 1 field onto the Contract Entry/Update window and add it to the Contract Lookup with Modifier in just seconds. This isn't as simple on some other windows in GP:


The problem was that Contracts needed to be retrieved using this Job Number value. Depending on how you address that, it could have a much more significant impact on the project budget. In this case, the customer was just as happy entering the Job Number to retrieve the Contract Record as they would be if the field were added to the Find Function in the Contract Lookup window.
It's important to note in this example that Job Number uniqueness is forced across Contracts.
To do this in GP 10; first, create some Sub Procedures to make and close a connection to the database:
Option Explicit
'Declare variables for the ADO Connection
Dim cn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
Public Sub Get_ADOConnection()
'Get_NewConnection
Set cn = UserInfoGet.CreateADOConnection
cn.DefaultDatabase = UserInfoGet.IntercompanyID
cmd.ActiveConnection = cn
End Sub
Public Sub Close_ADOConnection()
cmd.ActiveConnection.Close
End Sub
Then, add some code behind UserDefined1 on the Before User Changed event to force uniqueness of Job Number across Contracts:
Private Sub UserDefined1_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)
On Error GoTo Proc_Error:
If ContractNumber.Empty = False Then
'Get_NewConnection
Get_ADOConnection
'Make sure the job number is not already assigned to a contract
cmd.CommandText = "select top 1 CONTNBR from SVC00600 where USERDEF1 = '" & Me.UserDefined1 & "'"
Set rst = cmd.Execute
'If a contact exists for this job notify the user and force them to enter a unique job number
If rst.EOF = False Then
MsgBox ("This Job Number has already been assigned to contract " & RTrim(rst.Fields("CONTNBR")) & ".")
CancelLogic = True
KeepFocus = True
End If
Close_ADOConnection
End If
GoTo Procedure_Exit:
Proc_Error:
MsgBox Error$ & " " & Error, vbOKOnly, "UserDefined1_BeforeUserChanged"
Procedure_Exit:
End Sub
Finally, add some code behind User Defined 1 on the After User Changed Event to query the Contract Master Table and retrieve the Contract to which the Job Number has previously been assigned:
Private Sub UserDefined1_AfterUserChanged()
On Error GoTo Proc_Error:
If ContractNumber.Empty = True Then
'Get_NewConnection
Get_ADOConnection
'Lookup the Contract for this Job
cmd.CommandText = "select top 1 CONTNBR from SVC00600 where USERDEF1 = '" & Me.UserDefined1 & "'"
Set rst = cmd.Execute
If rst.EOF = False Then
Clear = 1
ContractNumber = rst.Fields("CONTNBR")
Else
MsgBox ("This Job Number has not been assigned to a contract.")
End If
Close_ADOConnection
End If
GoTo Procedure_Exit:
Proc_Error:
MsgBox Error$ & " " & Error, vbOKOnly, "UserDefined1_BeforeUserChanged"
Procedure_Exit:
End Sub
The end result of this not only can you easily assign the Job Number (User Defined 1) to the Contract and view the Job Number in the Contract Lookup Window but, most importantly, you can pull the Contract into the Contract Entry/Update Window by keying into the Job Number field.
Simple, quick, cost effective solution that could be applied to a variety of windows in GP.
01 March, 2009
GP Self Service - Locked Transactions
I neglected to mention another potential good reason to Customize GP; control your support costs, increase your IT resource capacity, and increase user satisfaction. There are routine problems that are easily resolved but often require the assistance of a system administrator. For example, records locked by other users, orphaned TempDB.dbo.DEX_LOCK records, can be a nuisance. This typically grows more common as the concurrent user count increases in Citrix environments. These records are necessary to prevent multiple users from accessing the same transactions at the same time. However, when they are not properly cleared they prevent users from accessing transactions even though another user may not be.
In this example, I added a Push Button to Sales Transaction Entry using Modifier.
Then, I created 2 stored procedures; one to return the userid that has locked the transaction so the user can attempt to resolve this problem on their own ...
... and the other to remove the locking record.

Next, add the Sales Transaction Entry Window, the Document No. field, and the Unlock Trx button to your VBA Project.
Open the VBA Editor to set a Reference in the Microsoft_Dynamics_GP Project to the Microsoft Active X Data Objects 2.x Library. This is required to access the database directly through VBA.
Finally, paste the following code behind the Sales Transaction Entry Window. If some pieces of this are foreign to you try to take advantage of Mariano's VBA workshop this week to learn more and check back as I take a deeper dive in the future into some of these concepts. My apologies for the formatting of this code. I'll work on that.
Private Sub UnlockTrx_AfterUserChanged()
'Declare the variables for the message boxes
Dim Msg, Style, Title, Help, Ctxt, Response, MyString, Default
'Declare the variables to make the connection to the database
Dim cn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
On Error GoTo Proc_Error:
'Prompt the user for the Document Number they want to unlock
Msg = "Enter the Document Number you want unlocked." ' Set prompt.
Title = "Unlock SOP Trx" ' Set title.
MyString = InputBox(Msg, Title, Default)
'Set the variables required to make the connection
Set cn = UserInfoGet.CreateADOConnection
cn.DefaultDatabase = UserInfoGet.IntercompanyID
cmd.ActiveConnection = cn
'Query the database to get user that has the document locked
cmd.CommandText = "exec uSp_SELLockedDocUser '" & Microsoft_Dynamics_GP.SalesTransactionEntry.DocumentNo & _
"', '" & cn.DefaultDatabase & "', 'SOP10100'"
Set rst = cmd.Execute
If rst.EOF = False Then
'Inform the user and give them the option to unlock the document or cancel
Msg = "This document is locked by " & (RTrim(rst.Fields("userid"))) & ". Continue Unlocking?"
Style = vbOKCancel + vbCritical ' Define buttons.
Title = "Dynamics GP" ' Define title.
Help = "DEMO.HLP" ' Define Help file.
Ctxt = 1000 ' Define topic
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
'Unlock the document if requested by the user
If Response = vbOK Then
cmd.CommandText = "exec uSp_DELClearLockedDoc '" & Microsoft_Dynamics_GP.SalesTransactionEntry.DocumentNo & "', '" & _
cn.DefaultDatabase & "', 'SOP10100'"
Set rst = cmd.Execute
End If
Else
'Inform the user that the record is not locked
Msg = "This document is not currently locked by another user."
Style = vbOKOnly + vbInformation ' Define buttons.
Title = "Dynamics GP" ' Define title.
Help = "DEMO.HLP" ' Define Help file.
Ctxt = 1000 ' Define topic
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
End If
GoTo Procedure_Exit:
Proc_Error:
MsgBox Error$ & " " & Error, vbOKOnly, "UnlockTrx_AfterUserChanged"
Procedure_Exit:
End Sub
In this example, I added a Push Button to Sales Transaction Entry using Modifier.
Then, I created 2 stored procedures; one to return the userid that has locked the transaction so the user can attempt to resolve this problem on their own ...
... and the other to remove the locking record.
Next, add the Sales Transaction Entry Window, the Document No. field, and the Unlock Trx button to your VBA Project.
Open the VBA Editor to set a Reference in the Microsoft_Dynamics_GP Project to the Microsoft Active X Data Objects 2.x Library. This is required to access the database directly through VBA.
Finally, paste the following code behind the Sales Transaction Entry Window. If some pieces of this are foreign to you try to take advantage of Mariano's VBA workshop this week to learn more and check back as I take a deeper dive in the future into some of these concepts. My apologies for the formatting of this code. I'll work on that.
Private Sub UnlockTrx_AfterUserChanged()
'Declare the variables for the message boxes
Dim Msg, Style, Title, Help, Ctxt, Response, MyString, Default
'Declare the variables to make the connection to the database
Dim cn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
On Error GoTo Proc_Error:
'Prompt the user for the Document Number they want to unlock
Msg = "Enter the Document Number you want unlocked." ' Set prompt.
Title = "Unlock SOP Trx" ' Set title.
MyString = InputBox(Msg, Title, Default)
'Set the variables required to make the connection
Set cn = UserInfoGet.CreateADOConnection
cn.DefaultDatabase = UserInfoGet.IntercompanyID
cmd.ActiveConnection = cn
'Query the database to get user that has the document locked
cmd.CommandText = "exec uSp_SELLockedDocUser '" & Microsoft_Dynamics_GP.SalesTransactionEntry.DocumentNo & _
"', '" & cn.DefaultDatabase & "', 'SOP10100'"
Set rst = cmd.Execute
If rst.EOF = False Then
'Inform the user and give them the option to unlock the document or cancel
Msg = "This document is locked by " & (RTrim(rst.Fields("userid"))) & ". Continue Unlocking?"
Style = vbOKCancel + vbCritical ' Define buttons.
Title = "Dynamics GP" ' Define title.
Help = "DEMO.HLP" ' Define Help file.
Ctxt = 1000 ' Define topic
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
'Unlock the document if requested by the user
If Response = vbOK Then
cmd.CommandText = "exec uSp_DELClearLockedDoc '" & Microsoft_Dynamics_GP.SalesTransactionEntry.DocumentNo & "', '" & _
cn.DefaultDatabase & "', 'SOP10100'"
Set rst = cmd.Execute
End If
Else
'Inform the user that the record is not locked
Msg = "This document is not currently locked by another user."
Style = vbOKOnly + vbInformation ' Define buttons.
Title = "Dynamics GP" ' Define title.
Help = "DEMO.HLP" ' Define Help file.
Ctxt = 1000 ' Define topic
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
End If
GoTo Procedure_Exit:
Proc_Error:
MsgBox Error$ & " " & Error, vbOKOnly, "UnlockTrx_AfterUserChanged"
Procedure_Exit:
End Sub
21 February, 2009
How to make PO field required for specific customer

This requirement came up last week and after Mariano explained how to do it, I went ahead and did it... for fun. Sick, I know.
I posted an example of using the DUOS a couple of year ago and used that, with very few tweaks, after using Modifier to add a Check Box control to the Customer Maintenance window to store the RequiredPO flag in the DUOS (SY90000) as Mariano suggested. If you have problems converting that example to this scenario let me know and I will e-mail you the code.
After that, all you have to do is add the Sales Transaction Entry Window and the Customer ID and Customer PO Fields on that window to your Visual Basic Project. Open the VB Editor and add this code to the SalesTransactionEntry (Window) to make the Customer PO field required for selected customers:
Option Explicit
Dim Msg, Style, Title, Help, Ctxt, Response, MyString, Default
Dim ItemCollection As DUOSObjects
Dim ItemObject As DUOSObject
Private Sub CustomerID_Changed()
On Error GoTo Proc_Error:
Set ItemCollection = DUOSObjectsGet("Customer")
If CustomerID.Empty = False Then
Set ItemObject = ItemCollection(CustomerID)
If ItemObject.Properties("RequirePO") = "1" Then
CustomerPONumber.Required = True
Else
CustomerPONumber.Required = False
End If
End If
Exit Sub
Proc_Error: MsgBox Error$ & " " & Error, vbOKOnly, "CustomerID_Changed"
End Sub
27 November, 2007
Using VBA to Mark Inventory Batches to Post to GL
I think this is pretty much common knowledge but it is a simple change you can make with VBA to ensure your inventory adjustments post to the GL. Paste this code below behind the Inventory Batch Entry window to mark the checkbox to post to the GL by Default and then prompt the user before posting without posting to the GL. This demonstrates a couple of handy VBA techniques you can use to alter and control the behavior of GP (forgive the formatting).
Option Explicit
Dim Msg, Style, Title, Help, Ctxt, Response, MyString, Default
Private Sub Comment_AfterGotFocus()
'Mark the Post to GL Checkbox after Comment Got Focus if not already marked
If PosttoGeneralLedger = 0 Then
PosttoGeneralLedger = 1
Changed = False
End If
End Sub
Private Sub Origin_AfterUserChanged()
'Mark the Post to GL Checkbox after changing the origin if not already marked
If PosttoGeneralLedger = 0 Then
PosttoGeneralLedger = 1
Changed = False
End If
End Sub
Private Sub Post_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)
If BatchID.Empty = False Then
If InventoryBatchEntry.PosttoGeneralLedger.Value = 0 Then
Msg = "Do you want to post this batch without posting to GL?" ' Define message.
Style = vbYesNoCancel + vbCritical ' Define buttons.
Title = "Great Plains" ' Define title.
Help = "DEMO.HLP\" ' Define Help file.
Ctxt = 1000 ' Define topic
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
If Response = vbNo Then
InventoryBatchEntry.PosttoGeneralLedger.Value = 1
Else
If Response = vbCancel Then
CancelLogic = True
End If
End If
End If
End If
End Sub
Option Explicit
Dim Msg, Style, Title, Help, Ctxt, Response, MyString, Default
Private Sub Comment_AfterGotFocus()
'Mark the Post to GL Checkbox after Comment Got Focus if not already marked
If PosttoGeneralLedger = 0 Then
PosttoGeneralLedger = 1
Changed = False
End If
End Sub
Private Sub Origin_AfterUserChanged()
'Mark the Post to GL Checkbox after changing the origin if not already marked
If PosttoGeneralLedger = 0 Then
PosttoGeneralLedger = 1
Changed = False
End If
End Sub
Private Sub Post_BeforeUserChanged(KeepFocus As Boolean, CancelLogic As Boolean)
If BatchID.Empty = False Then
If InventoryBatchEntry.PosttoGeneralLedger.Value = 0 Then
Msg = "Do you want to post this batch without posting to GL?" ' Define message.
Style = vbYesNoCancel + vbCritical ' Define buttons.
Title = "Great Plains" ' Define title.
Help = "DEMO.HLP\" ' Define Help file.
Ctxt = 1000 ' Define topic
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
If Response = vbNo Then
InventoryBatchEntry.PosttoGeneralLedger.Value = 1
Else
If Response = vbCancel Then
CancelLogic = True
End If
End If
End If
End If
End Sub
Subscribe to:
Posts (Atom)











