0% found this document useful (0 votes)
4 views736 pages

IG

The Microsoft Dynamics GP 2010 Integration Guide provides comprehensive instructions for developing integrations using Microsoft Dexterity. It covers integration basics, components, object triggers, window elements, navigation, lists, SmartList, and application services, along with sample code and procedures. The document is intended for internal reference and is provided 'as-is' with no warranty from Microsoft.

Uploaded by

helpdeskssusa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views736 pages

IG

The Microsoft Dynamics GP 2010 Integration Guide provides comprehensive instructions for developing integrations using Microsoft Dexterity. It covers integration basics, components, object triggers, window elements, navigation, lists, SmartList, and application services, along with sample code and procedures. The document is intended for internal reference and is provided 'as-is' with no warranty from Microsoft.

Uploaded by

helpdeskssusa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 736

Microsoft® Dexterity

Microsoft Dynamics® GP 2010 Integration Guide


Copyright Copyright © 2011 Microsoft Corporation. All rights reserved.

Limitation of liability This document is provided “as-is”. Information and views expressed in this document, including
URL and other Internet Web site references, may change without notice. You bear the risk of using
it.

Some examples depicted herein are provided for illustration only and are fictitious. No real
association or connection is intended or should be inferred.

Intellectual property This document does not provide you with any legal rights to any intellectual property in any
Microsoft product.

You may copy and use this document for your internal, reference purposes.

Trademarks Microsoft, Dexterity, Microsoft Dynamics, MSDN, Visua SourceSafe, Visual Studio, and Windows
are trademarks of the Microsoft group of companies. FairCom and c-tree Plus are trademarks of
FairCom Corporation and are registered in the United States and other countries.

All other trademarks are property of their respective owners.

Warranty disclaimer Microsoft Corporation disclaims any warranty regarding the sample code contained in this
documentation, including the warranties of merchantability and fitness for a particular purpose.

License agreement Use of this product is covered by a license agreement provided with the software product. If you
have any questions, please call the Microsoft Dynamics GP Customer Assistance Department at
800-456-0025 (in the U.S. or Canada) or +1-701-281-6500.

Publication date February 2011


Contents
Introduction ................................................................................................................................................. 2
What’s in this manual...................................................................................................................................2
Symbols and conventions ............................................................................................................................3

Part 1: Integration Basics.......................................................................................................... 6


Chapter 1: Developing Integrations .................................................................................... 7
Types of integrations ....................................................................................................................................7
Multidictionary environment......................................................................................................................7
Development process ...................................................................................................................................9
Using a product ID .....................................................................................................................................10
Determining the current product ............................................................................................................. 11
Creating a development folder ................................................................................................................. 11
Preparing for test mode ............................................................................................................................. 11
Source Code Control...................................................................................................................................12

Chapter 2: Sample Integration .............................................................................................. 13


Sample overview.........................................................................................................................................13
Installing the sample ..................................................................................................................................18
Using the sample source code...................................................................................................................21

Part 2: Integration Components .................................................................................. 24


Chapter 3: Forms ................................................................................................................................ 25
New forms ...................................................................................................................................................25
Alternate forms ...........................................................................................................................................27
Using the Modifier......................................................................................................................................29
Controlling form access..............................................................................................................................31

Chapter 4: Tables ............................................................................................................................... 33


Designing tables ..........................................................................................................................................33
Creating SQL tables ....................................................................................................................................35
Granting SQL access privileges ................................................................................................................36
Assigning default values to columns.......................................................................................................36
Working with SQL Server™ ......................................................................................................................38
Storing account numbers ...........................................................................................................................38
Pathnames....................................................................................................................................................41

Chapter 5: Reports ........................................................................................................................... 43


Alternate reports .........................................................................................................................................43
Creating an alternate report ......................................................................................................................44
Using the runtime Report Writer .............................................................................................................47
Controlling report access ...........................................................................................................................48
Report Writer functions to access report data.........................................................................................49
Report writer function examples ..............................................................................................................50

INTEGRATION GUIDE i
C O N T E N T S

Report Writer function reference ..............................................................................................................54


Word templates for reports........................................................................................................................57

Chapter 6: Procedures .................................................................................................................. 63


Calling a procedure ....................................................................................................................................63
Using procedure triggers ...........................................................................................................................64
Using the script logger ...............................................................................................................................64
Procedure list ...............................................................................................................................................65

Part 3: Object Triggers .............................................................................................................. 72


Chapter 7: Using Triggers .......................................................................................................... 73
Trigger benefits............................................................................................................................................73
Types of triggers..........................................................................................................................................74
Registering triggers.....................................................................................................................................75
Trigger processing procedure....................................................................................................................76
Unregistering triggers ................................................................................................................................76
Enabling and disabling triggers................................................................................................................77
Customization Status window..................................................................................................................77
Testing triggers ............................................................................................................................................78

Chapter 8: Form Triggers ............................................................................................................ 79


Registering form triggers...........................................................................................................................80
Disabling form triggers ..............................................................................................................................80
Multiple third-party developer issues .....................................................................................................81

Chapter 9: Focus Triggers .......................................................................................................... 83


Registering focus triggers ..........................................................................................................................83
Using reject script........................................................................................................................................84
Multiple third-party developer issues .....................................................................................................84
Pending focus events..................................................................................................................................85
Verifying table operations..........................................................................................................................85
Form focus triggers.....................................................................................................................................88
Window focus triggers ...............................................................................................................................89
Scrolling window focus triggers ...............................................................................................................90
Field focus triggers .....................................................................................................................................92
Menu focus triggers....................................................................................................................................93
Command focus triggers ...........................................................................................................................93
Table buffers for focus triggers .................................................................................................................93

Chapter 10: Database Triggers .............................................................................................. 95


Registering database triggers ....................................................................................................................95
Working with table buffers ........................................................................................................................96
Restricting table operations .......................................................................................................................96
Add database triggers ................................................................................................................................97
Update database triggers ...........................................................................................................................98
Delete database triggers.............................................................................................................................98
Read database triggers .............................................................................................................................100

ii IN T E G R AT I O N G U ID E
C O N T E N T S

Chapter 11: Procedure Triggers ......................................................................................... 103


Registering procedure triggers ...............................................................................................................103
Working with parameters ........................................................................................................................103
Disabling procedure triggers...................................................................................................................107

Chapter 12: Function Triggers ............................................................................................ 109


Registering function triggers...................................................................................................................109
Working with parameters ........................................................................................................................ 110

Chapter 13: Cross-dictionary triggers ......................................................................... 113


Registering cross-dictionary triggers ..................................................................................................... 113
Responding to cross-dictionary triggers ............................................................................................... 113
Helper functions........................................................................................................................................ 114
Cross-dictionary database triggers......................................................................................................... 115

Part 4: Window Elements ................................................................................................... 118


Chapter 14: Browse Controls ................................................................................................ 119
Browse buttons.......................................................................................................................................... 119
Sort lists ......................................................................................................................................................121

Chapter 15: Push Buttons ....................................................................................................... 123


Adding push buttons ...............................................................................................................................123
Cancel button.............................................................................................................................................124
Clear button ...............................................................................................................................................124
Delete button .............................................................................................................................................125
OK button...................................................................................................................................................125
Save button ................................................................................................................................................126

Chapter 16: Lookups.................................................................................................................... 127


Using existing lookups.............................................................................................................................128
Lookup types .............................................................................................................................................129
Adding a lookup control..........................................................................................................................131
Adding records on the fly........................................................................................................................132
Creating a lookup......................................................................................................................................133
Scrolling window ......................................................................................................................................133
Sort by/View options ...............................................................................................................................134
Column headers ........................................................................................................................................136
Refresh button ...........................................................................................................................................137
Show/Hide Detail button........................................................................................................................139
Find .............................................................................................................................................................140
Select and Cancel buttons ........................................................................................................................141
Open and New buttons............................................................................................................................142
Note.............................................................................................................................................................142

Chapter 17: Expansions And Zooms ............................................................................. 143


Expansions .................................................................................................................................................143
Zooms .........................................................................................................................................................144

INTEGRATION GUIDE iii


C O N T E N T S

Chapter 18: Notes .......................................................................................................................... 147


Window-level notes ..................................................................................................................................147
Record-level notes.....................................................................................................................................152

Chapter 19: Password Control............................................................................................ 159


Using passwords .......................................................................................................................................159

Chapter 20: Data Entry Conventions ............................................................................ 163


Required fields ..........................................................................................................................................163
Date fields ..................................................................................................................................................164
Prompts ......................................................................................................................................................164
Auto-complete...........................................................................................................................................166
Field groups ...............................................................................................................................................166
Tab sequence ..............................................................................................................................................167
Using product names ...............................................................................................................................168

Part 5: Navigation ........................................................................................................................ 170


Chapter 21: Commands ............................................................................................................ 171
Command overview .................................................................................................................................171
Command forms .......................................................................................................................................171
Defining commands .................................................................................................................................172
Opening the command form ...................................................................................................................173
Closing the command form.....................................................................................................................173
Command security ...................................................................................................................................173

Chapter 22: Menus in Microsoft Dynamics GP ................................................... 175


Menu overview .........................................................................................................................................175
Menu implementation..............................................................................................................................176
Menu structure in Microsoft Dynamics GP ..........................................................................................177
Viewing the menu structure ....................................................................................................................179
Adding to Microsoft Dynamics GP menus ...........................................................................................180
Menu creation procedure.........................................................................................................................181
Menu creation example............................................................................................................................182

Chapter 23: Toolbars in Microsoft Dynamics GP .............................................. 187


Toolbar overview ......................................................................................................................................187
Toolbar implementation...........................................................................................................................187
Toolbars in Microsoft Dynamics GP.......................................................................................................188
Adding to Microsoft Dynamics GP toolbars.........................................................................................188
Toolbar creation procedure......................................................................................................................189

Chapter 24: Navigation Pane Categories and Area Pages ....................... 195
Area Page ...................................................................................................................................................195
Navigation pane category........................................................................................................................196

Chapter 25: Shortcuts ................................................................................................................ 199


Adding Shortcuts ......................................................................................................................................199
Restricting shortcuts .................................................................................................................................200

iv IN T E G R AT I O N G U ID E
C O N T E N T S

Part 6: Lists........................................................................................................................................... 202


Chapter 26: List Overview ...................................................................................................... 203
List features................................................................................................................................................203
List types ....................................................................................................................................................204
Categories and navigation.......................................................................................................................205
Opening lists by using code ....................................................................................................................206
List Debugging Tools................................................................................................................................209

Chapter 27: Action Pane .......................................................................................................... 211


Action ID .................................................................................................................................................... 211
Commands for the Action Pane..............................................................................................................212
Command scripts ......................................................................................................................................214
Adding to the Action Pane ......................................................................................................................214
Registering actions and groups...............................................................................................................217
Checking action access .............................................................................................................................217
Verifying an action ....................................................................................................................................219
Executing an action...................................................................................................................................220
Performing actions for marked rows .....................................................................................................222
Logging action status ...............................................................................................................................223
Acting on action errors.............................................................................................................................226

Chapter 28: Information Pane............................................................................................. 229


Information Pane layout ..........................................................................................................................229
Adding content to the Information Pane...............................................................................................229
Adding to the Information Pane header................................................................................................230
Adding to the Information Pane line items...........................................................................................231
Information Pane procedure reference ..................................................................................................232

Chapter 29: Card Lists ............................................................................................................... 243


Card list form.............................................................................................................................................243
Checking access.........................................................................................................................................244
Creating a temporary table......................................................................................................................244
Attaching tables.........................................................................................................................................245
Table access ................................................................................................................................................245
List columns...............................................................................................................................................246
List options.................................................................................................................................................249
Selecting the data to display....................................................................................................................250
Filling the list .............................................................................................................................................252
Formatting list data ..................................................................................................................................256
Filter tokens ...............................................................................................................................................258
Action Pane................................................................................................................................................259
Information Pane ......................................................................................................................................267
Business Analyzer.....................................................................................................................................270
Row selection actions ...............................................................................................................................272
Open and closing ......................................................................................................................................272
List navigation...........................................................................................................................................273

INTEGRATION GUIDE v
C O N T E N T S

Custom list views......................................................................................................................................275

Chapter 30: Transaction Lists ............................................................................................. 279


Transaction list form .................................................................................................................................280
Checking access.........................................................................................................................................280
Creating a temporary table......................................................................................................................281
Attaching tables.........................................................................................................................................281
Table access ................................................................................................................................................281
List columns...............................................................................................................................................282
List options.................................................................................................................................................284
Loading the temporary table...................................................................................................................285
Selecting the data to display....................................................................................................................288
Filling the list .............................................................................................................................................291
Formatting list data ..................................................................................................................................292
Filter tokens ...............................................................................................................................................294
Action Pane................................................................................................................................................296
Information Pane ......................................................................................................................................302
Business Analyzer.....................................................................................................................................304
Row selection actions ...............................................................................................................................304
Open and closing ......................................................................................................................................304
List navigation...........................................................................................................................................306
Custom list views......................................................................................................................................308

Chapter 31: Report Lists .......................................................................................................... 309


Report types...............................................................................................................................................310
Report series ..............................................................................................................................................310
Integrating with Report List....................................................................................................................310
Adding Report List items ........................................................................................................................ 311
Retrieving Report List item information ...............................................................................................316
Printing and viewing reports ..................................................................................................................321
Custom actions ..........................................................................................................................................323
Composite definitions ..............................................................................................................................324

Part 7: SmartList ........................................................................................................................... 328


Chapter 32: SmartList Overview ...................................................................................... 329
How SmartList works ..............................................................................................................................329
Integration types .......................................................................................................................................330
Integration technique ...............................................................................................................................331
Explorer procedures .................................................................................................................................332
SmartList objects .......................................................................................................................................332

Chapter 33: Adding to SmartList Objects ............................................................... 341


Columns .....................................................................................................................................................341
Go To items ................................................................................................................................................350

Chapter 34: Creating New SmartList Objects ..................................................... 353


Creating the SmartList object ..................................................................................................................353

vi IN T E G R AT I O N G U ID E
C O N T E N T S

SmartList security .....................................................................................................................................354


Object name ...............................................................................................................................................354
Object columns ..........................................................................................................................................354
Retrieving the table name ........................................................................................................................356
Retrieving column datatypes ..................................................................................................................356
Retrieving column values ........................................................................................................................357
Retrieving list field types .........................................................................................................................360
Retrieving list field values .......................................................................................................................360
Adding a single row to SmartList...........................................................................................................362
Retrieving records for the SmartList ......................................................................................................364
Starting the retrieve and display process ..............................................................................................368
SQL optimization ......................................................................................................................................370
Go To items ................................................................................................................................................374
Integrating with Report List....................................................................................................................376

Chapter 35: SmartList Procedure Reference ........................................................ 379


Explorer_Fill_Range_DDLs_From_Field_ID ........................................................................................379
Explorer_Get_Datatype............................................................................................................................380
Explorer_Get_DDL_Type.........................................................................................................................381
Explorer_Get_Field_As_String_From_Table.........................................................................................381
Explorer_Get_Object_Name....................................................................................................................383
Explorer_Get_Records_Background ......................................................................................................383
Explorer_Get_SQL_Field_Info ................................................................................................................385
Explorer_Get_SQL_Join_Info ..................................................................................................................386
Explorer_Get_SQL_Override_Field_Name ..........................................................................................387
Explorer_Get_SQL_Query_Fields ..........................................................................................................387
Explorer_Get_Table_Name......................................................................................................................388
Explorer_Get_User_Defined_Prompt ....................................................................................................388
Explorer_GoTo_Button.............................................................................................................................389
Explorer_Optimize_For_SQL..................................................................................................................389
Explorer_Process_SQL_Data...................................................................................................................390

Part 8: Application Services ......................................................................................... 392


Chapter 36: Security .................................................................................................................... 393
Microsoft Dynamics GP security model................................................................................................393
Adding security data................................................................................................................................394
Security tasks .............................................................................................................................................394
Security task operations ...........................................................................................................................395
Security roles .............................................................................................................................................397
Checking security access..........................................................................................................................398
Excluding resources from security checks ............................................................................................399
Removing security information ..............................................................................................................400
Creating a new security resource type...................................................................................................400
System password ......................................................................................................................................406
Database security ......................................................................................................................................407

INTEGRATION GUIDE vii


C O N T E N T S

Chapter 37: Home Pages ......................................................................................................... 409


Roles............................................................................................................................................................409
Adding additional roles ...........................................................................................................................410
Adding to Home Page templates ...........................................................................................................412
Adding Quick Links .................................................................................................................................414
Adding reports ..........................................................................................................................................415
Metric overview ........................................................................................................................................415
SSRS metrics ..............................................................................................................................................416
OWC metrics .............................................................................................................................................416
Creating OWC metrics .............................................................................................................................417
Writing an OWC metric procedure ........................................................................................................421
Making OWC metrics available..............................................................................................................423
OWC Metric chart reference....................................................................................................................424

Chapter 38: Setup Checklist ................................................................................................ 427


Setup Checklist overview ........................................................................................................................427
Setup Checklist structure .........................................................................................................................428
Adding to Setup Checklist.......................................................................................................................429
Help for Setup Checklist items ...............................................................................................................431

Chapter 39: Online Help ........................................................................................................... 433


Third-party help responsibilities ............................................................................................................433
Using the Microsoft Dynamics GP help model ....................................................................................434
Implementing a help system ..................................................................................................................434
Writing a help processing procedure .....................................................................................................435
Registering the help processing procedure...........................................................................................436
Help button................................................................................................................................................436
Creating help source files.........................................................................................................................437
Help issues for integrating applications................................................................................................438

Chapter 40: Unified Communications......................................................................... 439


Presence overview ....................................................................................................................................439
Adding presence support to a window .................................................................................................440
Adding actions to Communicator or Lync............................................................................................443

Part 9: Packaging Your Application .................................................................... 448


Chapter 41: Building An Application ........................................................................... 449
Extracting your application .....................................................................................................................449
Transferring alternate forms and reports ..............................................................................................450
Adding product information...................................................................................................................451
Compressing your dictionary .................................................................................................................453
Completing the packaging process ........................................................................................................454
Using macros .............................................................................................................................................454

Chapter 42: Making Installation Files.......................................................................... 455


Writing installation scripts.......................................................................................................................455
Building a chunk dictionary....................................................................................................................456

viii IN T E G R AT I O N G U ID E
C O N T E N T S

Using the Auto-Chunk utility .................................................................................................................456


Testing the installation process ...............................................................................................................458

Chapter 43: Updating an Application .......................................................................... 461


Transferring third-party resources .........................................................................................................461
Common update problems......................................................................................................................465
Reviewing Microsoft Dynamics GP changes ........................................................................................468
Converting data.........................................................................................................................................469
Alternate forms and reports ....................................................................................................................469
Testing your application ..........................................................................................................................469
Building an update chunk dictionary ....................................................................................................469
Updating forms and reports dictionaries ..............................................................................................470

Part 10: Windows Installer ............................................................................................... 474


Chapter 44: Windows Installer Overview ................................................................. 475
Windows Installer Services......................................................................................................................475
WiX..............................................................................................................................................................476
GUIDs .........................................................................................................................................................476

Chapter 45: Installer Template ........................................................................................... 477


Installer template overview.....................................................................................................................477
Creating an installer .................................................................................................................................478
Adding multiple-instance support.........................................................................................................482

Chapter 46: Patches ..................................................................................................................... 485


Patch overview ..........................................................................................................................................485
Creating a patch ........................................................................................................................................486

Part 11: Script Reference................................................................................................... 492


Area Page scripts ......................................................................................................................................493
AddCategory .....................................................................................................................................494
AddCommand...................................................................................................................................495
AddContentArea...............................................................................................................................496
AddItems............................................................................................................................................498
Create ..................................................................................................................................................499
Display................................................................................................................................................500
Command scripts .....................................................................................................................................501
Command_HideAndDisable...........................................................................................................502
Command_ShowAndEnable...........................................................................................................503
Home page scripts....................................................................................................................................505
AddMetric..........................................................................................................................................506
AddMyReport().................................................................................................................................507
AddNew.............................................................................................................................................508
AddQuickLink ..................................................................................................................................509
AddSection......................................................................................................................................... 511
AddSubSection..................................................................................................................................512
Create() ...............................................................................................................................................513
Commit() ............................................................................................................................................515
Destroy ...............................................................................................................................................516
Exists() ................................................................................................................................................517

INTEGRATION GUIDE ix
C O N T E N T S

Get() ....................................................................................................................................................518
Release ................................................................................................................................................519
SetIndex ..............................................................................................................................................520
SetUserRole........................................................................................................................................521
List scripts..................................................................................................................................................523
ActionStatus_LogActionComplete() ..............................................................................................525
ActionStatus_LogError()..................................................................................................................526
AddCommand()................................................................................................................................528
AddGroup() .......................................................................................................................................533
AddReport().......................................................................................................................................535
BuildDictSpecificID()........................................................................................................................536
Columns_AddToken()......................................................................................................................537
Columns_AutoGenTokensForEnumField() ..................................................................................540
ConfirmAction() ................................................................................................................................541
CreateDefaultColumn()....................................................................................................................543
CreateDefaultCustomViewRecord() ..............................................................................................545
CreateDefaultFactBox() ....................................................................................................................546
CreateDefaultViewRecord() -- Options..........................................................................................548
CreateDefaultViewRecord() -- View...............................................................................................549
DeleteForListView() -- Options.......................................................................................................550
DeleteForListView() -- Columns .....................................................................................................551
DeleteForListView() -- Business Analyzer Reports......................................................................552
DisassembleDictSpecificID..............................................................................................................553
Exists() ................................................................................................................................................554
ExistsAsAction()................................................................................................................................556
ExistsAsGroup() ................................................................................................................................557
FactBoxParameter_Add ...................................................................................................................558
FindCommandInCmdList().............................................................................................................560
GetListID() .........................................................................................................................................561
GetMarkedRecordCount() ...............................................................................................................562
GetMarkedRecordsTableIndex().....................................................................................................563
GetMarkedRecordsTableRef() .........................................................................................................564
GetViewID() .......................................................................................................................................565
InfoValue_ClearState() .....................................................................................................................566
InfoValue_IsStateSet().......................................................................................................................567
InfoValue_SetState()..........................................................................................................................568
List_FormatBoolean() .......................................................................................................................569
List_FormatCurrency().....................................................................................................................570
List_FormatDate() .............................................................................................................................571
List_FormatInteger().........................................................................................................................572
List_FormatPhone() ..........................................................................................................................573
List_FormatQuantity() .....................................................................................................................574
List_FormatString()...........................................................................................................................575
List_FormatTime() ............................................................................................................................576
List_GetIDsForCoreCommand .......................................................................................................577
List_MultiSelectActionCompleteEvent .........................................................................................579
List_Open ...........................................................................................................................................580
List_RegisterAction()........................................................................................................................582
List_RegisterGroup() ........................................................................................................................583
List_SetFactBoxParameter ...............................................................................................................584
RegisterListNavigationCommand()...............................................................................................585
XMLDoc_AddColumn .....................................................................................................................586
XMLDoc_AddHeaderField .............................................................................................................587
XMLDoc_AddLineItem ...................................................................................................................588
XMLDoc_AddLineItemValue .........................................................................................................589
XMLDoc_Create ................................................................................................................................590

x IN T E G R A T I O N G U I D E
C O N T E N T S

XMLDoc_Save ...................................................................................................................................593
Menu scripts..............................................................................................................................................595
AddCommandToMenu() .................................................................................................................596
AddNavBarButton() .........................................................................................................................598
AlreadyExistsOnMenu() ..................................................................................................................600
FindCommandInMenu()..................................................................................................................601
MenusExistForProduct()..................................................................................................................602
Report scripts ............................................................................................................................................603
syImportReportTemplate() ..............................................................................................................604
syRemoveReportTemplate() ............................................................................................................606
Security scripts .........................................................................................................................................607
AddSecurityTaskOperation() ..........................................................................................................608
AddTaskToRole() .............................................................................................................................. 611
CreateSecurityRole().........................................................................................................................612
CreateSecurityTask().........................................................................................................................613
DeleteSecurityForProduct().............................................................................................................614
Exists() -- Security Role ....................................................................................................................615
Exists() -- Security Task ....................................................................................................................616
Exists() -- Security Task Operation .................................................................................................617
Exists() -- Security Task Role ...........................................................................................................619
GetValidSystemPassword() .............................................................................................................620
LoadListView.....................................................................................................................................621
Security() ............................................................................................................................................622
SetIndex ..............................................................................................................................................623
syUserInRole()...................................................................................................................................626
Shortcut scripts.........................................................................................................................................627
ScBar_AddDexForm() ......................................................................................................................628
ScBar_AddExternalFile()..................................................................................................................629
ScBar_AddFolder() ...........................................................................................................................630
ScBar_AddMacro()............................................................................................................................631
ScBar_AddUrl() .................................................................................................................................632
ScBar_ItemExists ...............................................................................................................................633
Setup Checklist scripts ...........................................................................................................................635
AddSetupChecklistItem() ................................................................................................................636
FindSetupChecklistItem() ................................................................................................................639
SmartList scripts.......................................................................................................................................641
Explorer_Add_Column_To_Object ................................................................................................642
Explorer_Add_GoTo_Item...............................................................................................................645
Explorer_Add_Object.......................................................................................................................647
Explorer_AddItem_To_ListView ....................................................................................................648
Explorer_Add_SubItem_To_ListView ...........................................................................................651
Explorer_Check_Stop_Processing ..................................................................................................652
Explorer_Remove_Column_From_Object ....................................................................................654
Explorer_Remove_GoTo_Item ........................................................................................................655
Explorer_Remove_Object ................................................................................................................656
Explorer_Search_Generic.................................................................................................................657
Explorer_Set_SQL_Join_Info ...........................................................................................................661
Explorer_Set_SQL_Query_Field .....................................................................................................663
Explorer_SQL_Search_Generic .......................................................................................................664
SQL scripts ................................................................................................................................................667
GrantAccess() ....................................................................................................................................668
SQL_GetConnection() ......................................................................................................................669
Toolbar scripts ..........................................................................................................................................671
AddCommandBar()..........................................................................................................................672

INTEGRATION GUIDE xi
C O N T E N T S

AddCommandToCmdBar().............................................................................................................674
ButtonsExistForProduct() ................................................................................................................676
CmdBarIsVisible().............................................................................................................................677
ExistsForUserID()..............................................................................................................................678
FindCommandInCmdList().............................................................................................................679
ToggleCommandBar() ......................................................................................................................680
Unified Communications scripts..........................................................................................................681
Activate...............................................................................................................................................682
GatherSIP().........................................................................................................................................683
Register...............................................................................................................................................684
Unregister...........................................................................................................................................686

Appendix .................................................................................................................................................. 690


Appendix A: Naming Conventions ................................................................................. 691
General naming guidelines .....................................................................................................................691
Standard abbreviations ............................................................................................................................692
Data types ..................................................................................................................................................693
Formats.......................................................................................................................................................693
Fields...........................................................................................................................................................694
Tables ..........................................................................................................................................................695
Forms and windows .................................................................................................................................698
Reports........................................................................................................................................................699
Scripts .........................................................................................................................................................700
Native pictures ..........................................................................................................................................700
Prompts and window text .......................................................................................................................701

Glossary ..................................................................................................................................................... 705

Index ............................................................................................................................................................... 709

xii IN T E G R A T I O N G U I D E
INTRODUCTION
Introduction
The Integration Guide provides information about developing Microsoft® Dexterity
applications that integrate with Microsoft Dynamics™ GP. You should be familiar
with creating Dexterity applications before using the information in this manual.
Refer to the Dexterity Quick Start, Dexterity Programmer’s Guide, SanScript
Reference and Function Library Reference manuals for additional information
about resources and sanScript commands described in this manual.

A sample integrating application, Develop.cnk, for Microsoft Dynamics GP is


included with Dexterity. This sample application demonstrates how basic
application functions can be implemented in an integrating application.

You may use and modify the scripts and resources in the sample integrating application for
use in your own applications, but we make no warranties regarding the sample dictionary,
including any warranties of merchantability or fitness for a particular purpose.

What’s in this manual


This manual includes the following parts:

• Part 1, Integration Basics, describes the process of developing an integration


and introduces the sample integration for Microsoft Dynamics GP.

• Part 2, Integration Components, explains how to use standard components like


forms and reports in your integration.

• Part 3, Object Triggers, explains how to use and implement form, focus, data-
base and procedure triggers in an integrating application.

• Part 4, Window Elements, explains the conventions used for window compo-
nents, such as lookups, zooms and notes. Use the information provided to cre-
ate applications that look and function like Microsoft Dynamics GP.

• Part 5, Navigation, describes how to implement navigation for your integra-


tion.

• Part 6, Lists, explains how to implement lists for your integration, or add func-
tionality to existing Microsoft Dynamics GP lists.

• Part 7, SmartList, explains how to integrate with SmartList in Microsoft


Dynamics GP.

• Part 8, Application Services, describes several services provided by Microsoft


Dynamics GP that you can use for your integration, such as security and the
Setup Checklist.

• Part 9, Packaging Your Application, explains the process used to build, pack-
age, install and update an integrating application.

• Part 10, Windows Installer, describes how to create an installer for your
Microsoft Dynamics GP integration.

• Part 11, Script Reference, provides detailed descriptions for the procedures and
functions you will use to implement core functionality in your integration.

2 IN T E G R A T I O N G U I D E
IN T RO D U C T IO N

Symbols and conventions


To help you use the Dexterity documentation more effectively, we’ve used the
following symbols and conventions to make specific types of information stand out.

Symbol Description
➥ of table Items; A continuation character indicates that a script
continued from one line to the next should be typed as
one line in the Script Editor.
The light bulb symbol indicates helpful tips, shortcuts
and suggestions.

Warnings indicate situations you should be aware of


when completing tasks.

Margin notes summa- Margin notes call attention to critical information. and
rize important informa- direct you to other areas of the documentation where a
tion. topic is explained.

Convention Description
Part 2, Object Triggers Bold type indicates a part name.
Chapter 3, “Reports” Quotation marks indicate a chapter name.
Using the Modifier Italicized type indicates a section name.
set 'l_Item' to 1; This font is used for script examples.
RUNTIME.EXE Words in uppercase indicate a file name.
Software Development Acronyms are spelled out the first time they’re used.
Kit (SDK)
TAB or ALT+M Small capital letters indicate a key or a key sequence.

INTEGRATION GUIDE 3
4 IN T E G R A T I O N G U I D E
PART 1: INTEGRATION BASICS
Part 1: Integration Basics
This portion of the documentation provides an overview of creating an integration
for Microsoft Dynamics GP. The following topics are discussed:

• Chapter 1, “Developing Integrations,” describes the types of integrations you


can create, and provides an overview of the development process you will use.

• Chapter 2, “Sample Integration,” describes the sample integration included


with Microsoft Dexterity. You will use this sample while learning to create your
own integrations.

6 IN T E G R A T I O N G U I D E
Chapter 1: Developing Integrations
Before you begin, it’s important to understand what types of integrations you can
make and what the basic process is for creating them. Information about developing
integrations is divided into the following sections:

• Types of integrations
• Multidictionary environment
• Development process
• Using a product ID
• Determining the current product
• Creating a development folder
• Preparing for test mode
• Source Code Control

Types of integrations
For additional Typically, you will develop applications that contain vertical enhancements,
information about customizations to functionality in the accounting system, or a combination of both.
creating new or
customized forms and Vertical enhancements
reports, refer to The most common type of development involves creating new forms and reports
Chapter 3, “Forms,” that add new functionality to the accounting system. This type of development
and Chapter 5, allows you to create custom vertical applications not already provided by the core
“Reports.” application.

Vertical enhancements allow you to tie your application into existing functionality
by re-using resources from the main product dictionary. For example, the Lead
Maintenance form in the sample integrating application uses lookup, note, save,
delete and clear buttons. This form also uses the RM_Salesperson_MSTR table, and
uses the Salesperson lookup form provided by the main dictionary.

Customizations
This type of development involves the direct customization of existing forms and
reports in the main product dictionary. Common customizations include adding
new fields to a form or report, or new menus or tables to a form. Direct
customizations allow you to offer features or reporting capabilities not already
provided in existing forms and reports.

Refer to Part 3, Object Although delivering customized forms and reports can be a very valuable part of your
Triggers, for more product offering, be aware that you must redo any customizations to forms and reports with
information about each Microsoft Dynamics GP update. If your primary focus is customizations, we
using triggers. recommend that you use object triggers in your application. Triggers reduce the number of
customizations to forms in the main product dictionary, reducing the impact of maintenance
updates on your application.

Multidictionary environment
The multidictionary feature supported by the Dexterity runtime engine allows your
application to seamlessly integrate with Microsoft Dynamics GP. Multidictionary
allows the runtime environment to recognize separate application dictionaries and
run them as one integrated application. When you develop an integrating
application and deliver it to customers, it must operate in this multidictionary
environment.

INTEGRATION GUIDE 7
PA RT 1 I N T E G R A T I O N B A S I C S

For the runtime engine to recognize all dictionaries in a multidictionary


environment, the launch file must list all dictionaries that run together. For
example, the following illustration shows the launch file that’s necessary to run the
sample integrating application and Microsoft Dynamics GP in a multidictionary
environment.

2
0
Microsoft Dynamics GP
3333
Sample Integrating App.
Windows
:C:Dynamics GP/Dynamics.dic
:C:Dynamics GP/Data/Forms.dic
:C:Dynamics GP/Data/Reports.dic
:C:Dynamics GP/Develop.dic
:C:Dynamics GP/Data/F3333.DIC
:C:Dynamics GP/Data/R3333.DIC

Refer to Chapter 58, Each line in the launch file contains information necessary for the runtime engine to
“Using Launch Files,” run the various dictionaries that make up the complete application. When you
in Volume 1 of the install one or more integrating applications, you add additional information to the
Dexterity launch file that allows the additional dictionary to work in the multidictionary
Programmer’s Guide environment.
for more information
about launch files. The following illustration shows how you would configure a launch file to launch
Microsoft Dynamics GP and the Sample Integrating Application included with
Dexterity:

The number of products


in the multidictionary 2
environment. 0
Microsoft Dynamics GP
The product ID 3333
and name. Sample Integrating App.
The dictionary location ID. Windows
:C:Dynamics GP/Dynamics.dic
:C:Dynamics GP/Data/Forms.dic
:C:Dynamics GP/Data/Reports.dic
The locations of the :C:Dynamics GP/Develop.dic
application, forms and :C:Dynamics GP/Data/F3333.DIC
reports dictionaries. :C:Dynamics GP/Data/R3333.DIC

To create an application that runs in a multidictionary environment, you must first


develop it within the main product dictionary (Dynamics.dic) and then package it
using the Dexterity Utilities. The section Development process on page 9, provides an
overview of this process.

8 IN T E G R A T I O N G U I D E
C H A P T E R 1 DE V E LO P I N G IN T E G R A T IO N S

Development process
The development process for an integration begins by creating your application
directly in the main product dictionary (Dynamics.dic). This allows you to add new
resources, such as new forms and reports, use existing resources in the main
product dictionary, such as data types and fields, and customize existing forms and
reports. Once you’ve completed your application development, you’ll package your
application using Dexterity Utilities, then deliver the application to customers.

The following illustration provides an overview of this process:

Create new or use Build your application using Package and ship
existing resources in Dexterity Utilities to extract your application
the Dynamics resources with IDs of 22,000 or dictionary.
dictionary. This is greater, and transfer alternate
called the development forms and reports..
dictionary.

Dexterity App.cnk
App.dic

Dynamics DexUtils Dynamics

This checklist provides the steps required to develop an application that integrates
in a multidictionary environment. Each step describes a phase in your application’s
development, and provides instructions for finding additional information about
each phase.

1. Develop your application in the main product dictionary.


Install the latest version of Microsoft Dynamics GP you will be integrating with,
then develop your application directly in the main product dictionary
(Dynamics.dic). The main product dictionary that contains the product you’re
developing is called the development dictionary. As you add your application’s
forms and reports, Dexterity flags each with resource IDs starting at 22,000. This
allows Dexterity, Dexterity Utilities, and the runtime engine to differentiate
between third-party and main product resources.

Be sure to make a backup of the Dynamics dictionary prior to starting your application
development.

As you create your application in the development dictionary, you can:

• Create new forms and reports

• Open main product forms from within your application

• Call procedures and functions in the main product

INTEGRATION GUIDE 9
PA RT 1 I N T E G R A T I O N B A S I C S

• Use main product fields on your forms, reports and in tables

• Customize main product forms and reports

Refer to Part 2, Integration Components, for additional information about


creating or modifying forms, reports and tables, or calling main product
procedures and functions.

2. Test your integrating application.


Use Dexterity test mode to run the development dictionary. Although test mode
does not reflect actual multidictionary operation, new forms and reports you
add to the main product dictionary will work the same in test mode as they will
in a multidictionary environment.

You will also want to test your completed application in a multidictionary environment.

3. Package your integrating application.


You don’t ship a development dictionary to your customers. Instead, you’ll use
Dexterity Utilities to do the following:

• Extract your application dictionary from the development dictionary.

• Transfer any forms or reports you’ve customized to the extracted applica-


tion dictionary.

• Set product information for the extracted dictionary. This is information


that’s added to the launch file when you install your application.

• Prepare the extracted dictionary for installation with your customer’s


installation.

Refer to Part 9, Packaging Your Application, for information about extracting


your application dictionary, setting product information and creating an
installation file.

4. Update your application.


Subsequent versions of Microsoft Dynamics GP delivered to your customers
may include changes that have an effect on the integration with your
application. Therefore, you’ll need to deliver an update for your application
that corresponds to each core product update. Refer to Chapter 43, “Updating
an Application,” for information about creating an update chunk.

Using a product ID
Each integrating product must have its own unique product ID. You will use the
product ID in several places throughout the code for your integration. We
recommend that you create a constant for the product ID, rather than hard-coding
the product ID into scripts. For example, the sample integrating application uses the
following constant for the product ID:

IG_PROD_ID 3333

Using a constant allows you to easily change the product ID if needed. It also allows
you to begin coding if you haven’t yet requested a product ID from Microsoft.

10 IN T E G R AT I O N G U ID E
C H A P T E R 1 DE V E LO P I N G IN T E G R A T IO N S

Determining the current product


To determine whether the professional or standard version of Microsoft Dynamics
GP is being used, you need to check the appropriate registration slot. The following
example code does this.

if 'Module Registered'[SM_CS] of globals = true then


{Microsoft Dynamics GP Professional]
else
{Microsoft Dynamics GP Standard}
end if;

Creating a development folder


When developing your integration, consider creating a separate “development”
folder. To this folder you will add a copy of the Dynamics dictionary, which will
become your development dictionary. Using a separate development folder has the
following benefits:

• It keeps the core dictionary for the Microsoft Dynamics GP installation in its
original state, which is important for testing your integration in a runtime
setting.

• The additional files generated, such as Resource Explorer temporary files and
reference information files won’t clutter the application installation folder.

• The path for accessing the development folder can be much simpler. For
example, C:\Develop.

• Build operations, such as creating a dictionary chunk for your integration, can
be performed in the development folder.

• It’s easier to make backups of your work.

Preparing for test mode


During development, you will want to run your integration in Dexterity’s test
mode. For your development dictionary to run properly in test mode, you must
copy the Dex.ini file from the Microsoft Dynamics GP installation and replace the
one in the folder from which Dexterity is being run. The Dex.ini file contains several
settings that are required for Microsoft Dynamics GP to run properly.

Keep in mind that several features in the accounting system won’t be available
when you run in test mode. Test mode has no support for the multidictionary
architecture, so common features like SmartList won’t be available. It’s important
that you thoroughly test your integration in a multidictionary runtime
environment. Code that works in test mode can operate differently when used with
the runtime engine.

To allow running in test mode, you may need to write two versions of specific
sections of sanScript code. One version will be designed to run in test mode, and the
other will be designed to work with the runtime engine. You can use the following
code to determine whether code is being executed in test mode or with the runtime
engine:

INTEGRATION GUIDE 11
PA RT 1 I N T E G R A T I O N B A S I C S

if Launch_GetFileName() <> "" then


{Runtime engine is being used}
else
{Test mode is being used}
end if;

Source Code Control


Dexterity has integrated support for using a source code control system, such as
Visual SourceSafe®. Using source code control is an essential part of developing an
integration for Microsoft Dynamics GP. It makes development much easier and
provides the following benefits:

• Resources for the integration are much easier to manage, because only new or
modified resources are stored in the source code control repository.

• Multiple developers can work on the same integration while minimizing


resource conflicts and eliminating the risk of lost work.

• It’s much easier to upgrade your integration to work with new releases of the
core product. Source code control is an essential part of the upgrade process.
You will learn about the upgrade process in Chapter 43, “Updating an
Application.”

To learn more about using Source Code Control when creating an integration for
Microsoft Dynamics GP, refer to Chapter 55, “Source Code Control for Integrating
Applications,” in Volume 1 of the Dexterity Programmer’s Guide.

12 IN T E G R AT I O N G U ID E
Chapter 2: Sample Integration
The sample integrating application (Develop.cnk) available with Dexterity
illustrates many of the concepts needed while developing an integrating application
for Microsoft Dynamics GP. Information about the sample integration is divided
into the following sections:

• Sample overview
• Installing the sample
• Using the sample source code

Sample overview
The sample application includes source code for a sample maintenance form, a
sample trigger form, and a sample inquiry form. The sample also includes a card
list, a transaction list, and a report list integration. The sample also shows how to
implement the various forms of navigation, such as menus and toolbars.

Sample maintenance form


Refer to Part 4, The sample Lead Maintenance form shows many of the conventions used for
Window Elements, designing and coding a typical maintenance form. Use the source code available
for information about with this sample form to understand how to implement form- and record-level
implementing notes, browse buttons and other window conventions in applications like Microsoft
components used in Dynamics GP.
this form.

Sample trigger form


Refer to Part 3, Object The sample Contact History form demonstrates how a third-party form could use
Triggers, for more object triggers to integrate with Microsoft Dynamics GP. This form works with the
information about RM_Customer_Maintenance form to store third-party contact records associated
implementing triggers. with customer records.

INTEGRATION GUIDE 13
PA RT 1 I N T E G R A T I O N B A S I C S

Sample inquiry form


The sample Lead Inquiry form demonstrates how to create an inquiry form for an
integration. This form allows a user to view lead information that is created and
maintained with the Lead Maintenance window.

Sample setup form


The sample application for Microsoft Dynamics GP contains a setup form used to
configure the Contact History window. This setup form is also accessed from the
Setup Checklist.

Sample reports form


The Leads Reports form in the sample application for Microsoft Dynamics GP
demonstrates how to use report options for reports in an application.

14 IN T E G R AT I O N G U ID E
C H A P T E R 2 SA MP LE I N TE GRA T ION

The Leads Report Options window is used to create and modify the report options
for the various Leads reports. This window is also accessed from the Report List in
Microsoft Dynamics GP.

Sample SmartList
The sample application for Microsoft Dynamics GP creates a new SmartList object
that displays Lead information.

Sample card list


The sample application for Microsoft Dynamics GP has a card list that displays
Leads. The list allows users to perform actions for leads, like viewing or editing.

INTEGRATION GUIDE 15
PA RT 1 I N T E G R A T I O N B A S I C S

Sample transaction list


The sample application for Microsoft Dynamics GP has a transaction list that shows
how to display date-sensitive information. In this case, it displays customer contact
information.

Sample report list


The sample application for Microsoft Dynamics GP integrates with the Sales Report
List, providing access to the reports for the sample application.

16 IN T E G R AT I O N G U ID E
C H A P T E R 2 SA MP LE I N TE GRA T ION

Sample reports
The sample application provide examples of reports, and shows how they can be
run from within the application.

Navigation
The sample integrating application uses the standard forms of navigation in
Microsoft Dynamics GP, such as Area Pages, menus, and toolbars. The following
illustration shows the Leads item that was added to the Sales Area Page.

Your integration will add


menu items that will
appear in the Area Page.

INTEGRATION GUIDE 17
PA RT 1 I N T E G R A T I O N B A S I C S

This toolbar is added by the sample integrating application for Microsoft Dynamics
GP, and allows access to windows provided by the sample.

Installing the sample


The resources for the Microsoft Dynamics GP sample integrating application are
contained in the installation file named Develop.cnk. When the file is added to a
Microsoft Dynamics GP installation, it will allow the sample application to run in a
multidictionary environment.

Installing
To install the sample integrating application, complete the following steps:

1. Copy the chunk file.


Copy the Develop.cnk chunk file for the sample integration into the same folder
as the main application dictionary (Dynamics.dic).

2. Copy the sample help file.


Copy the appropriate help file Develop.chm file into the same folder as the
main application dictionary (Dynamics.dic).

3. Start Microsoft Dynamics GP.


A message will appear asking whether you want to include the new application
code. Click Yes. The code for the sample will be added to the Develop.dic
sample dictionary.

4. Log in as the administrator.


Logging in as the administrator allows the tables for the sample integrating
application to be created properly. Log in as the administrator “DYNSA”. You
could also log in as “sa”.

5. Display the sample application’s windows.


The windows defined in the sample will now appear in the navigation for
Microsoft Dynamics GP. The following table lists the navigation used to access
the sample windows:

Item Navigation
Lead Maintenance Cards >> Sales >> Leads
Lead Inquiry Inquiry >> Sales >> Leads
Leads Reports Reports >> IG Sample >> Leads
Leads List View >> Sales Lists >> Leads
Contact History Cards >> Sales >> Customer
Selection from the Extras >> Additional submenu.
Contact History Setup Tools >> Setup >> Sales >> Contact History
Contact History List View >> Sales Lists >> Contact History

18 IN T E G R AT I O N G U ID E
C H A P T E R 2 SA MP LE I N TE GRA T ION

Adding sample data for Microsoft Dynamics GP


A macro is provided with the sample integrating application to add sample data
that can be used by the sample. You must run this macro when logged into the
sample company, since this macro assumes that data from the sample company will
be accessible.

To run the macro, choose Microsoft Dynamics GP >> Tools >> Macro >> Play. Select
the IG_Sample_Data.mac macro file, located in the Develop folder of the Samples
folder of your Dexterity installation.

Installing Word templates


Two reports for the sample integrating application are template-enabled, and have
Word templates that can be used for them. To install a Word template for the sample
integration, complete the following steps:

1. Open Report Template Maintenance.


In Microsoft Dynamics GP, choose Reports >> Template Maintenance.

2. Display the template-enabled reports for the sample.


In the Report Name drop-down list, choose More Reports. In the Reports
lookup window, make the following selections:

Product Set this to Sample Integrating App.

Series Set this to Sales.

Status Set this to Original.

The template-enabled reports for the sample integrating application will be


listed.

3. Select the IG_Leads report.


In the list, select IG_Leads and then click Select.

INTEGRATION GUIDE 19
PA RT 1 I N T E G R A T I O N B A S I C S

4. Add the template for the IG_Leads report.


Click the Add template button (the green plus) to open a dialog box that allows
you select a Word template. Choose the IG_Leads Template.docx file, located in
the Develop folder of the Samples folder of your Dexterity installation.

5. Open the Company Assignment window.


In the Assign button drop-list, choose Company to open the Company
Assignment window.

6. Assign a company.
In the Company Assignment window, mark the company that you want to use
the template with.

7. Set the default template.


Click Set Default to open the Default Assignment window. Select a company
and then mark the report template that you want to use as the default.

Click Save.

20 IN T E G R AT I O N G U ID E
C H A P T E R 2 SA MP LE I N TE GRA T ION

8. Close the Company Assignment window.


Click Save to close the Company Assignment window. The IG_Leads report
now has a default Word template assigned to it for the company.

9. Install the template for the IG_Leads_List report.


Repeat this procedure for the IG_Leads_List report.

When you specify the report destination for either the IG_Leads report or the
IG_Leads_List report, you will see Template listed as an available report type.

After installing and


configuring a Word template
for a report, the Template
report type will be available.

Using the sample source code


Names for most To review the source code and resources in the sample integrating application, you
resources in the should not edit the dictionary directly with Dexterity. Instead, transfer the sample
sample integrating integrating dictionary to the most current unmodified Microsoft Dynamics GP
application begin with dictionary (DYNAMICS.DIC). To do this, use the Developer Update utility in
the prefix “IG” Dexterity Utilities to complete the transfer.
(Integration Guide).
Start Dexterity Utilities, and open the sample application (DEVELOP.DIC) as a
source dictionary, and a new, unmodified Microsoft Dynamics GP dictionary
(DYNAMICS.DIC) as a destination dictionary. Be sure this is not the development
dictionary where you are completing existing application development.

INTEGRATION GUIDE 21
PA RT 1 I N T E G R A T I O N B A S I C S

Do not transfer the contents of the sample application to your current development
dictionary. The update process will replace existing resources with IDs at and above 22,000
with resources in the sample application dictionary. Use only a copy of an unmodified
Microsoft Dynamics GP dictionary.

1. Transfer third-party resources.


Choose Developer Update from the Transfer menu. When the window appears,
click Transfer; the Report File Name dialog box will appear. Enter the name and
location for the Developer Update Status Report file, then click OK to continue
the process.

2. Update series resources.


Close both the source and destination dictionaries, then open the updated
Microsoft Dynamics GP dictionary as an editable dictionary. Choose Series
Resources from the Resources menu. In the Series Resources window, mark the
All Resource Types and All Series options, then click Update.

3. View source code using Dexterity.


Once you’ve completed the update, launch Dexterity and open the
development dictionary containing the sample integrating application. You can
review source code for the sample.

22 IN T E G R AT I O N G U ID E
PART 2: INTEGRATION COMPONENTS
Part 2: Integration Components
This portion of the Integration Guide explains how to work with standard resources
for your integrating application. The follolwing topics are discussed:

• Chapter 3, “Forms,” explains the process of creating new forms and


customizing existing forms.

• Chapter 4, “Tables,” explains how to use tables in Microsoft Dynamics GP, and
contains standards for using and maintaining tables.

• Chapter 5, “Reports,” explains the process of customizing reports.

• Chapter 6, “Procedures,” explains how to use Microsoft Dynamics GP


procedures in your application.

24 IN T E G R AT I O N G U ID E
Chapter 3: Forms
There are two primary ways you implement forms in your development dictionary;
you can create new forms, or you can create alternate forms by changing Microsoft
Dynamics GP forms directly. Information about forms is divided into the following
sections:

• New forms
• Alternate forms
• Using the Modifier
• Controlling form access

New forms
You can create new forms directly in your development dictionary, and re-use
existing resources from the Dynamics.dic dictionary in these forms. For example,
the sample application’s Lead Maintenance form re-uses resources, including the
RM_Salesperson_Lookup form, the Salesperson ID field, and various window
controls, such as the Save, Clear, and Delete buttons, and the note and padlock
buttons.

These buttons come from


the main dictionary.

The lookup displays the


Salesperson lookup form. The
zoom displays the Salesperson
Maintenance window.

These controls come from


the main dictionary.

Creating new forms


Refer to Part 4, You will want to retain the “look and feel” of Microsoft Dynamics GP for your new
Window Elements, forms. Although this isn’t an essential requirement for an integrating application,
for information about doing so will create a more seamless integration with the accounting system.
implementing each of
these components. To do this, new forms should support a number of standard window components:

Name Component Description


Browse Browse controls allow the user to move from
controls one record to the next, or to the beginning or
end of a table.
Expansions Expansions extend the functionality of a
window when the window becomes too large
for the viewing area.
Lookups Lookup buttons display a lookup form. The
lookup form can be either a third-party form or
an existing Microsoft Dynamics GP form.

INTEGRATION GUIDE 25
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Name Component Description


Notes Window-level notes allow users to attach notes
to a window and share information on a
company-wide basis. Record-level notes allow
users to provide additional information about a
specific record on a company-wide basis.
Push buttons Standard push buttons complete record
operations in the accounting system.
Zooms Zoom fields allow the user to “drill down” to
additional information.

Refer to Part 4, Window Elements, for information about implementing each of


these components.

Testing new forms in test mode


Use Dexterity test mode to test the operation of new forms using the sample
company provided with Microsoft Dynamics GP. Prior to entering Dexterity test
mode, be sure you copy the Dex.ini file from the Microsoft Dynamics GP
installation and replace the one in the folder from which Dexterity is being run. This
ensures that Dexterity test mode uses the same startup information as the Microsoft
Dynamics GP runtime engine.

In test mode, access new forms using one of the following methods:

• Shortcut Bar item – A shortcut bar item provides navigation to any form in the
development dictionary (except forms in the System series). You can add new
forms from the development dictionary to the Shortcut Bar in exactly the same
manner as Microsoft Dynamics GP forms.

• Form trigger – A form trigger provides navigation to a new form from an


existing Microsoft Dynamics GP form. When the user opens the specified form,
the trigger runs and displays an item in the “Additional” menu on the menu
bar, providing navigation to a new form.

Testing new forms in a multidictionary


environment
Refer to Part 9, Use the following utilities in Dexterity Utilities to build your application dictionary
Packaging Your and test new forms in a multidictionary environment:
Application, for
information about ✔ Step Description
using Dexterity Utilities 1 Extract third-party forms using the Extract utility.
to package and install
2 Add product information using the Product Information utility.
an application in a
multidictionary 3 Create an installation file using the Auto-Chunk utility, and install it with an
unmodified Dynamics.dic dictionary.
environment.

When you install your integrating application in a multidictionary environment, be


sure you’re installing with a Dynamics.dic dictionary that’s exactly the same as the
one your customers use. Don’t install your application with your development
dictionary. This can produce unreliable results since you’re not using the same
dictionary as your customers will use.

Once installed, access your application’s forms by adding them to the Shortcut Bar.
If you’re using a form trigger, display the form that allows you to activate the form
trigger.

26 IN T E G R AT I O N G U ID E
C H A P T E R 3 F O R M S

Alternate forms
An alternate form is a Microsoft Dynamics GP form you customize, then deliver with
your integrating application. After the user installs your product, they can use
system security to access the alternate form instead of the original. There are several
types of customizations you may choose to make:

• Add a new window to a Microsoft Dynamics GP form

• Add a new menu to a Microsoft Dynamics GP form

• Add new fields and tables to a Microsoft Dynamics GP form

• Add new form procedures and functions to a Microsoft Dynamics GP form

• Add new local fields to a Microsoft Dynamics GP form

It’s important that you do not change existing functionality on the form. This
includes removing an existing field from the form, or altering the way in which the
accounting system processes information in the form.

Creating alternate forms


If you choose to deliver alternate forms, there are a number of issues you should be
aware of. The following sections explain these issues in detail.

Refer to Chapter 43, Handling updates


“Updating an Although delivering a customized form can be a very valuable part of your product
Application,” for offering, be aware that you must redo customizations you make to forms and
additional information reports when an update is released. It’s important that you acquire beta code as
about how updates soon as you can to update and test your integration. This ensures that the release of
affect your application. your updated product will synchronize as closely as possible with the general
availability release of Microsoft Dynamics GP.

By limiting the number of customizations to forms, your application’s code is more


independent of Microsoft Dynamics GP, thereby reducing the impact of maintenance
updates on your application. We strongly recommend you limit customizations by using
object triggers in your application.

Multiple third-party customizations


The System Manager controls access to alternate forms through system security.
Using security, you can grant a user access to either the original Microsoft Dynamics
GP form, or to the alternate version of that form. However, if multiple third-party
developers deliver the same alternate form, system security allows the user access
to only one version of the alternate form.

Scripts
You cannot modify existing field, window or form scripts, but you can attach a
script to a focus event (a pre, change or post event) that Microsoft Dynamics GP
isn’t using. However, there is a danger that the focus event will be used in future
releases. This would inhibit your script from running once you’ve installed your
application.

We recommend that you use a focus trigger rather than applying a script directly to a
Microsoft Dynamics GP field. Maintenance updates have no effect on triggers.

INTEGRATION GUIDE 27
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Using object triggers for navigation


Refer to Part 3, Object Object triggers allow you reduce the number of customizations made to Microsoft
Triggers, for more Dynamics GP forms, such as adding navigational buttons, adding additional fields,
information about or attaching form scripts. Triggers also allow multiple third-party developers to
using triggers in your provide applications for a single Microsoft Dynamics GP form with fewer conflicts.
application.
Keep in mind that triggers may not totally eliminate the need to customize forms. Most
likely, you’ll use a combination of triggers and form customizations.

Object triggers are especially useful when tracking additional data in a Microsoft
Dynamics GP form. For instance, a third-party developer added two fields to track
lead information in the RM_Salesperson form, like the following illustration:

Additional third-party
fields.

In this case, the third-party developer delivers the entire alternate form as part of the
extracted third-party dictionary. With a form trigger, the third-party developer can
attach the same functionality to the form without modifying the form directly. The
form trigger adds an item to the Additional menu, where the user can access one or
more third-party forms related to the Microsoft Dynamics GP form:

The form trigger adds an


“Additional” menu when the
Salesperson Maintenance
form is active.

When you select the


menu item, the third-party
form is displayed.

28 IN T E G R AT I O N G U ID E
C H A P T E R 3 F O R M S

By using the form trigger rather than delivering an alternate form, the original form
remains available to the user, and updates won’t affect your integration.

Testing alternate forms in test mode


Use Dexterity test mode with your development dictionary to test your changes
thoroughly. Prior to entering Dexterity test mode, be sure you copy the Dex.ini file
from the Microsoft Dynamics GP installation and replace the one in the folder from
which Dexterity is being run. This ensures that Dexterity test mode uses the same
startup information as the Microsoft Dynamics GP runtime engine.

Testing alternate forms in a multidictionary


environment
Refer to Part 9, Use the following utilities in Dexterity Utilities to build your application dictionary
Packaging Your and test alternate forms in a multidictionary environment:
Application, for
information about ✔ Step Description
using Dexterity Utilities 1 Extract new third-party resources using the Extract utility.
to package and install
2 Transfer alternate forms using the Transfer Dictionary Module utility.
an application in a
multidictionary 3 Add product information using the Product Information utility.
environment. 4 Update series resources using the Series Resources utility.
5 Create an installation file using the Auto-Chunk utility, and install it with
an unmodified Dynamics.dic dictionary.

Once you’ve built your application, be sure to install it with a Dynamics.dic


dictionary that’s exactly the same as the one your customers use. Do not install your
application with your development dictionary. This can produce unreliable results
since you’re not using the same dictionary as your customers will use.

Using the Modifier


Once you’ve installed your application in a multidictionary environment, users
who have registered the Modifier can modify new third-party forms and alternate
forms in your dictionary. When the user accesses the Modifier in a multidictionary
environment, the following window appears, allowing the user to enter the forms
dictionary for either the main product (Microsoft Dynamics GP) or the third-party
dictionary:

In the main dictionary, users can modify forms as they normally would. In the third-
party dictionary, users can modify either new forms or alternate forms.

INTEGRATION GUIDE 29
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Refer to Chapter 43, Creating a forms dictionary


“Updating an When the user modifies forms in your dictionary for the first time, the runtime
Application,” for engine creates a new forms dictionary for your application using the information in
information about the launch file. The pathname entry for the forms dictionary in the launch file
updating forms and specifies the location and name of the forms dictionary:
reports dictionaries.

2
0
Microsoft Dynamics GP
3333
Sample Integrating App.
Windows
:C:Dynamics GP/Dynamics.dic
:C:Dynamics GP/Data/Forms.dic
:C:Dynamics GP/Data/Reports.dic
This generic pathname in
:C:Dynamics GP/Develop.dic
the launch file specifies
the name and location of
:C:Dynamics GP/Data/F3333.DIC
the forms dictionary. :C:Dynamics GP/Data/R3333.DIC

The default location of the forms dictionary is the same location as your application
dictionary. A user can change the location of the forms dictionary using the Edit
Launch File window in Microsoft Dynamics GP. This window shows all
applications appearing in a multidictionary environment, and allows the user to
change the location of the forms or reports dictionaries:

This list shows the


products in the
launch file.

For instance, changing the location of the forms dictionary to a network location
allows multiple users to share a single forms dictionary across a network.

If you change the path for your forms dictionary, be sure to move an existing forms
dictionary to that location. Otherwise, the runtime engine will attempt to create a new forms
dictionary the next time a user accesses the Modifier.

30 IN T E G R AT I O N G U ID E
C H A P T E R 3 F O R M S

Controlling form access


To control access to new forms you will need to add them to a security task using
the Security Task Setup window. You could create a new security task or add them
to an existing security task. Refer to Adding security data on page 394 for more
information about adding security data for your integration. The following
illustration shows one of the security tasks that controls access for forms in the
sample integration.

By default, security in Microsoft Dynamics GP doesn’t allow access to a new form.


Users assigned to the power user role will be able to access the original form, but
not the modified or alternate versions of the form. The administrator for the
Microsoft Dynamics GP installation will need to use the Alternate/Modified Forms
and Reports window to specify access to a modified or alternate version of a form.

Refer to the system documentation for Microsoft Dynamics GP for details about
using this window to control access to forms.

INTEGRATION GUIDE 31
32 IN T E G R AT I O N G U ID E
Chapter 4: Tables
Refer to Chapter 9, You can create tables in your development dictionary using any of the Microsoft
“Tables,” in the Volume Dynamics GP fields. In addition, you can read, write, delete or update existing
1 of the Dexterity records in Microsoft Dynamics GP tables. However, you cannot modify existing
Programmer’s Guide table definition in any way, including changing keys, adding fields, or changing
for information about names. The following sections explain the methods you should use when creating
creating tables. the tables for your integration:

• Designing tables
• Creating SQL tables
• Granting SQL access privileges
• Assigning default values to columns
• Working with SQL Server™
• Storing account numbers
• Pathnames

Designing tables
In many types of integrations, you’ll want to associate records in your application
with records in the accounting system. For instance, you may want to track
additional contact information for a customer record in a third-party table. To do
this, you could create a table that includes new fields you’ve created in your
development dictionary, as well as one or more of the RM_Customer_MSTR table’s
key values.

Main Product table Third-party table


(RM_Customer_MSTR) (IG_Contact_History_MSTR)
Use the key fields from
Customer Number Customer Number
the Main Product table in
the table you’re creating. Customer Name Customer Name
Address 1 Contact Person
Address 2 First Contact Date
Phone 1 Last Contact Date
Phone 2 Salesperson 1
City Salesperson 2
State

Salesperson

Using the key values from the customer record, you can retrieve the corresponding
contacts record. This is especially important when Microsoft Dynamics GP
performs actions with the customer record (such as deleting the record or creating a
new one), and you want to perform similar actions to the corresponding customer
contact record. This is necessary to maintain referential integrity between a third-
party record and a related record in the accounting system. Object triggers provide
the best means for implementing referential integrity in your application.

INTEGRATION GUIDE 33
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Using object triggers


Refer to Part 3, Object Database triggers are the most reliable method of ensuring referential integrity
Triggers, for more between third-party records and related Microsoft Dynamics GP records. These
information about triggers respond to successful database operations performed on the core
using triggers in your application’s table, such as saving, updating or deleting a record. In response to the
application. trigger, you can save, update or delete a corresponding record in your application.

The following illustration shows how deleting a customer record triggers the
deletion of a related customer contacts record in the third-party table:

The Delete button deletes


the customer record.

RM_Customer_MSTR
Customer Number AARONFIT001
Customer Name Aaron Fitz Electrical
Address 1 One Microsoft Way
Address 2
Phone 1 4255550101
The delete operation Phone 2

activates a trigger that sets


Salesperson PAUL W.
the key values in the third-
party table’s buffer, and IG_Contact_History_MSTR
deletes the corresponding Customer Number AARONFIT001
record. Customer Name Aaron Fitz Electrical
Contact Person Bob Fitz
First Contact Date 110295
Last Contact Date 112195
Salesperson 1 PAUL W.
Salesperson 2 ERIN J.

You can specify the type of database action (read, read lock, add, update or delete)
that you want a database trigger to respond to using the
Trigger_RegisterDatabase() function.

Example: Deleting a record using a database trigger


In this example, the database trigger runs whenever the user deletes a customer
record from the RM_Customer_MSTR table (using the RM_Customer_Maintenance
form). The following script registers this trigger.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterDatabase(reference(table RM_Customer_MSTR), form


➥ RM_Customer_Maintenance, TRIGGER_ON_DB_DELETE, script
➥ IG_Trigger_Delete_Contact_History);
if l_result <> SY_NOERR then
warning "Database trigger registration failed.";
end if;

34 IN T E G R AT I O N G U ID E
C H A P T E R 4 T A B LE S

When the delete operation occurs, the trigger passes the contents of the deleted
table buffer as an inout parameter to the trigger processing procedure, as shown
below. The trigger processing procedure then sets key values from the
RM_Customer_MSTR table buffer and deletes the contact history record that
corresponds to the deleted RM_Customer_MSTR record.

{Name: IG_Trigger_Delete_Contact_History}
inout table RM_Customer_MSTR;

'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number'


➥ of table RM_Customer_MSTR;
release table IG_Contact_History_MSTR;
change table IG_Contact_History_MSTR by number 1;
if err() = OKAY then
remove table IG_Contact_History_MSTR;
if isopen(form IG_Contact_History) then
clear form IG_Contact_History;
end if;
end if;

Creating SQL tables


If your integrating application will be using its own tables, it must provide some
method of creating them on the SQL server. Some integrating applications use a
separate window to create SQL tables, but this isn’t an ideal solution. When creating
tables for your integrating application, we recommend that you use a technique
similar to that used by the sample integrating application.

Two issues must be solved when creating SQL tables:

• You must be logged into SQL, or an additional SQL Login dialog will be
displayed when the tables are created.

• The current SQL user must have create permissions, or an error will occur when
tables are created.

To resolve these issues, the sample integrating application creates SQL tables for the
current company, only after the user has logged into the system as “DYNSA” or
“sa”. This ensures that the no additional login dialog is displayed, and that no
creation errors will occur since the administrator always has create privileges. Refer
to Database security on page 407 for more information.

The following focus trigger is used to create SQL tables for the sample integrating
application.

local integer l_result;

l_result = Trigger_RegisterProcedure(script Add_Successful_Login_Record,


➥ TRIGGER_AFTER_ORIGINAL, script IG_Setup_SQL_Tables);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for setting up tables failed.";
end if;

The trigger is activated only after the user has logged into a company and to the
appropriate SQL database. This prevents the additional login dialog from being
displayed.

INTEGRATION GUIDE 35
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

The following code is the trigger processing procedure that creates the SQL tables.
The procedure uses a helper procedure that creates the table and then grants access
to the table and the table’s stored procedures. This is described in following section,
Granting SQL access privileges. It also calls another helper procedure to bind default
values to the columns in each of the tables created. This is described in Assigning
default values to columns.

if 'SQL Server' of globals > 0 then


{Is the system administrator logging in?}
if ('User ID' of globals = "sa") or ('User ID' of globals = "DYNSA") then

call IG_Create_Table, "IG_Contact_History_MSTR";


call IG_Create_Table, "IG_Contact_History_SETP";
call IG_Create_Table, "IG_Leads_MSTR";
call IG_Create_Table, "IG_Leads_ROPT";

call IG_BindSQLDefaults;
end if;
end if;

Granting SQL access privileges


Once a SQL table and its auto-generated stored procedures have been created, you
must grant privileges to them so they can be accessed by other users. The DYNGRP
group, which is set up during the Microsoft Dynamics GP installation, indicates
which users have access. All tables and auto-generated stored procedures you
create should grant privileges to this group.

To grant access privileges to the DYNGRP group, you will call a special function in
the Dynamics.dic dictionary. The GrantAccess() function is part of the SQL
Maintenance form in Dynamics.dic. The function can grant access to the table and
also to the auto-generated stored procedures for the table. The following example
shows how this function could be used to grant access to the IG_Leads_MSTR table
and its auto-generated stored procedures.

local boolean result;

{Grant access to the table}


result = GrantAccess(physicalname(table IG_Leads_MSTR), false, "DYNGRP",
➥ 'Intercompany ID' of globals) of form 'SQL Maintenance';

{Grant access to the table auto-generated procedures}


result = GrantAccess(physicalname(table IG_Leads_MSTR), true, "DYNGRP",
➥ 'Intercompany ID' of globals) of form 'SQL Maintenance';

Assigning default values to columns


If external applications (those other than Microsoft Dynamics GP) will be creating
records in your SQL tables, you may want to bind default values to each of the
table’s columns. If a value for a column isn’t supplied when a record is created, the
default value bound to the column will be used.

36 IN T E G R AT I O N G U ID E
C H A P T E R 4 T A B LE S

Microsoft Dynamics GP defines the following default values that can be used for
columns in your integration’s tables.

Default Description
GPS_CHAR Used for string and text fields
GPS_DATE Used for date fields
GPS_INT Used for integer fields
GPS_MONEY Used for currency fields

To apply default values to columns, you can use pass-through SQL. The
sp_bindefault stored procedure allows you to bind a default value to a column. For
example, the following code from the sample integration shows the pass-through
SQL used to assign default values to the columns for the
IG_Contact_History_MSTR table. This code must be run by a user who is the
database owner, such as “sa” or “DYNSA”. Otherwise, the procedure won’t have
sufficient privileges to bind defaults to the columns.
local string database;
local long SQL_connection, status;
local text SQL_Statements;

{Get the current database in which the tables were created}


database = 'Intercompany ID' of globals;

if 'SQL Server' of globals > 0 then


{Connect to the SQL data source.}
status = SQL_Connect(SQL_connection);
if status = 0 then
{Build and execute SQL statement to use the appropriate database.}
SQL_Statements = "use " + database;
status = SQL_Execute(SQL_connection, SQL_Statements);
if status = 0 then
{Were able to switch databases. Bind the columns}
{Build the SQL statements.}
SQL_Statements = "EXEC sp_bindefault 'dbo.GPS_CHAR',
➥ 'IG003.[ContactSalespersonID1]'" + char(13);
SQL_Statements = SQL_Statements + "EXEC sp_bindefault
➥ 'dbo.GPS_CHAR', 'IG003.[ContactSalespersonID2]'" + char(13);
SQL_Statements = SQL_Statements + "EXEC sp_bindefault
➥ 'dbo.GPS_CHAR', 'IG003.[CNTCPRSN]'" + char(13);
SQL_Statements = SQL_Statements + "EXEC sp_bindefault
➥ 'dbo.GPS_CHAR', 'IG003.[CUSTNAME]'" + char(13);
SQL_Statements = SQL_Statements + "EXEC sp_bindefault
➥ 'dbo.GPS_CHAR', 'IG003.[CUSTNMBR]'" + char(13);
SQL_Statements = SQL_Statements + "EXEC sp_bindefault
➥ 'dbo.GPS_DATE', 'IG003.[FirstContactDate]'" + char(13);
SQL_Statements = SQL_Statements + "EXEC sp_bindefault
➥ 'dbo.GPS_DATE', 'IG003.[LastContactDate]'" + char(13);
{Execute the SQL statements}
status = SQL_Execute(SQL_connection, SQL_Statements);
else
error "Could not switch to the correct database when
➥ binding default column values.";
end if;
end if;
{Disconnect from the SQL data source.}
status = SQL_Terminate(SQL_connection);
end if;

INTEGRATION GUIDE 37
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Working with SQL Server™


Since most of the tables for Microsoft Dynamics GP are managed by SQL Server,
your integration may have to interact with SQL Server directly. For example, you
may need to execute stored procedures to perform tasks for your integration.
Microsoft Dynamics GP provides some infrastructure that makes working with SQL
Server easier in your integration.

Database names
You may need to retrieve the names of the system database, or of specific company
databases. To retrieve the name of the system database (the database that contains
the core accounting system tables) use the following code:

local string database_name;


local boolean result;

database_name = SQL_GetDbName(DYNAMICS, DYNAMICS, 7, 0, result);

To retrieve the name of the database for the current company, you can use the
Intercompany ID global variable. This variable is automatically set to the name of
the database for the current company.

local string database_name;

database_name = 'Intercompany ID' of globals;

Pass-through SQL
For some aspects of your integration, you may need to use pass-through SQL. Pass-
through SQL requires an additional connection to the SQL server when being
executed. To make managing these pass-through connections easier, Microsoft
Dynamics GP provides an infrascture for these connections. The
SQL_GetConnection() function is used to retrieve a pass-through SQL connection
from Microsoft Dynamics GP. Using a connection maintained by the core
application is much more efficient than opening a separate pass-through connection
for your integration.

Storing account numbers


You should avoid using the Account Number field in your application’s tables.
Because the user sets the length of the account number at installation, account
numbers will vary in length from site to site. If you need to store account number
information, use the account number’s index instead.

If you use the account number directly in your table, and the user changes the account
number structure, you will need to convert data in that table.

The Account Index field uniquely identifies each account. This index provides a
reference that you can use to retrieve and display the actual account number,
regardless of its format. There are two primary tables that store account numbers
and their corresponding indexes:

• The GL_Account_Index_MSTR table stores all account numbers and their


associated indexes.

• The GL_Account_MSTR table stores account numbers, their indexes and all
additional information about the account number, such as the account
description.

38 IN T E G R AT I O N G U ID E
C H A P T E R 4 T A B LE S

In Microsoft Dynamics GP, the account number indexes are consecutive integers
that start at 1. When an account number is deleted, its index is no longer used.
When a new account is added, an index for the account is reserved at the end of the
index sequence.

Example: Using the account index


This example uses a third-party table for tracking project information, and assigns
an account number for each project. The following table shows the layout of the
third-party table (IG_Project_MSTR) used in the example. The table doesn’t store
the account number, but instead stores the account index using the Account Index
field.

Field Description
Project ID The key for the third-party table.
Phase A third-party field for tracking project phase information.
Detail A third-party field for tracking project detail information.
Account Index A global field. This field is also an invisible window field on the third-party
form.

The third-party form uses the GL_Account_MSTR table, as well as the third-party’s
IG_Project_MSTR table. The following illustration shows the Project Accounts
window in the third-party form.

The following steps explain how to display account information using the account
index.

1. Retrieve an account number.


Retrieve an account number using the Account_Lookup form. The sample form
opens the Account Number lookup form by attaching the following change
script to the Account Number field’s lookup button:

open form Account_Lookup return to 'Account Number';


{Set the sort list to Account Description.}
'Sort By' of window Account_Lookup = 1;
{Set an invisible field for the account type. The scrolling
window will be filled with accounts of this type.}
'(L) Account Type1' of window Account_Lookup of form
➥ Account_Lookup = UNIT_ACCT;
{Run the sort list change script to fill the scrolling window.}
run script 'Sort By' of window Account_Lookup of form Account_Lookup;

2. Retrieve the account number index.


Using the account number retrieved in step 1, retrieve the associated account
number index and description. The sample form sets the value of an invisible
account index field and the account description using the following change
script for the Account Number field:

INTEGRATION GUIDE 39
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

'Account Number' of table GL_Account_MSTR = 'Account Number';


{Get the Account Master table by key 6. This key uses
only the Account Number field.}
get table GL_Account_MSTR by GL_Account_MSTR_Key6;
if err()=OKAY then
{Retrieve the index and description.}
'Account Index' = 'Account Index' of table GL_Account_MSTR;
'Account Description'='Account Description' of table GL_Account_MSTR;
end if;

3. Save the account index with the third-party record.


When the sample form saves the project record, it also saves the account index
with the project record:

if required(form IG_Project_Accounts) then


copy to table IG_Project_MSTR;
save table IG_Project_MSTR;
restart form;
else
warning "Not all required fields have been entered.";
end if;

4. Retrieve the third-party record.


To display the appropriate account with the third-party record, set the account
index in the Account Master table to the account index stored with the third-
party record, then display the associated account number:

'Project Number' of table IG_Project_MSTR = 'Project Number';


release table IG_Project_MSTR;
change table IG_Project_MSTR by IG_Project_MSTR_Key1;
if err()=OKAY then
copy from table IG_Project_MSTR;
{Set the account index in the Account Master table to
the index stored with the project table.}
'Account Index' of table GL_Account_MSTR = 'Account Index';
get table GL_Account_MSTR by GL_Account_MSTR_Key1;
if err()=OKAY then
{Display the account number and description from the
Account Master table.}
'Account Number' = 'Account Number' of table GL_Account_MSTR;
'Account Description' = 'Account Description' of table
➥ GL_Account_MSTR;
end if;
clear changes form IG_Project_Accounts;
end if;
lock 'Project Number';

40 IN T E G R AT I O N G U ID E
C H A P T E R 4 T A B LE S

Pathnames
A new table you create will be stored in the appropriate database, based on the table
series you specified for the table in Dexterity. For series values such as Sales or
Financial, your third-party table will be accessed in each company database set up
in the accounting system. If you specify System as the series, your third-party table
will be accessed in the DYNAMICS database.

If you want your tables to be accessed from some other location, you must add the
tables to table groups. Then you can add records to the SY_Pathnames table
(SY02100) to specify the locations for third-party tables. An alternative to adding
records through code is to use the Pathnames window in Microsoft Dynamics GP to
specify pathnames for third-party tables. The following illustration shows this
window:

The third-party tables


must be in a table group.

The Pathnames window is not directly accessible in Microsoft Dynamics GP. You must add
it as a shortcut so that it can be accessed from the Navigation pane.

Assigning table groups


To support pathnames for third-party tables, you must define table groups using
the Table Group Definition window in Dexterity. Once you’ve defined table groups,
set the location of tables using the Pathnames window. Refer to Chapter 26, “Table
Groups,” in Volume 1 of the Dexterity Programmer’s Guide for information about
creating table groups.

Depending upon how you want to organize your application’s table groups, use the
following guidelines:

• Use a table group with a single table if you want to change pathnames for that
table alone. Microsoft Dynamics GP supports pathnames only if the table is part
of a table group.

• Use a table group with multiple tables to change pathnames for all tables in the
group. For instance, a group of tables that individually store invoicing header,
line item and summary information should be part of a single invoicing table
group. When you change pathnames for the table group, Microsoft Dynamics
GP will look for these three tables in the same location.

You cannot add a third-party table to an existing Microsoft Dynamics GP table group, nor
can you add a Microsoft Dynamics GP table to a third-party group.

INTEGRATION GUIDE 41
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Setting pathnames
To change the location of your application’s data, use the Pathnames window. This
window writes pathname records to the SY_Pathnames table (SY02100). When the
SQLPath procedure in the accounting system runs, it checks the SY_Pathnames
table for a pathname based upon the company ID, product ID and series for the
table group being accessed. It then performs the table operation using that path.

42 IN T E G R AT I O N G U ID E
Chapter 5: Reports
You can develop either new reports in your development dictionary or customize
existing reports. However, if you need to customize an existing report directly, you
will face a few development issues. Information about reports is divided into the
following sections:

• Alternate reports
• Creating an alternate report
• Using the runtime Report Writer
• Controlling report access
• Report Writer functions to access report data
• Report writer function examples
• Report Writer function reference
• Word templates for reports

Alternate reports
You’ll need to customize a Microsoft Dynamics GP report if you want to change the
report directly, either by adding fields from one or more third-party tables, or by
changing report table relationships to include third-party tables.

Once you customize the Microsoft Dynamics GP report, use Dexterity Utilities to
transfer it to your extracted dictionary. Like alternate forms, you can then deliver
the alternate report to customers, where it takes the place of the original report. The
following RM Customer Report uses third-party fields from a third-party table
(IG_Contact_History_MSTR) for tracking contact history information.

RM Customer Report

Additional third-party
fields.

INTEGRATION GUIDE 43
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

You cannot directly customize Microsoft Dynamics GP reports that use a temporary table as
the main table. Instead, you must the technique described in Report Writer functions to
access report data on page 49 to make third-party data available to the report.

The following procedure uses components of this sample report to illustrate how to
set up an alternate report.

Creating an alternate report


Creating an alternate report involves changing table relationships for the report
prior to making actual changes to the report layout. This is necessary if you use a
third-party table with the Microsoft Dynamics GP report. Changing table
relationships ensures that the alternate report retains all associated table
relationships once you’ve transferred it to your application dictionary using
Dexterity Utilities.

To create an alternate report, complete the following steps.

Open your development dictionary using Dexterity and display the report
definition for the report you’re customizing.

1. Ascertain the main table for the report.


Note the main table and the table’s first key. For the sample alternate report, this
information is in the following table:

Main table RM_Customer_MSTR


Key RM_Customer_MSTR_Key1

2. Duplicate the main table.


Use the Duplicate Utility in Dexterity to duplicate the main table for the report
you selected in step 1. Be sure you rename the duplicate table differently from
the original table. In the sample alternate report, the duplicate table is
IG_Customer_MSTR.

Main table RM_Customer_MSTR


Duplicate table IG_Customer_MSTR

3. Change the display name of the duplicate table.


Open the Table Definition window for the table you duplicated in step 2 and
change its display name so the name isn’t the same as the original table.

Duplicate table IG_Customer_MSTR


Display name IG Customer Master

44 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

4. Create a new table relationship.


Click Relationships to open the Table Relationship window, then click New.
Using the Table Relationship Definition window, define a relationship between
the duplicate table and the main table. In the sample alternate report, the Table
Relationship Definition window looks like the following illustration.

Once you’ve defined the relationship for the duplicate table and original table,
define additional relationships between the duplicate table and any third-party
tables you want to add to the relationship.

Since the sample alternate report displays contact history information, an


additional relationship must exist between the duplicate (primary) table
(IG_Customer_MSTR) and the secondary third-party table
(IG_Contact_History_MSTR).

Primary table IG_Customer_MSTR


Secondary table IG_Contact_History_MSTR
Secondary table key IG_Contact_History_MSTR_Key1
Relationship type One Record

Once you’ve finished creating relationships, close the Table Relationship


Definition, Table Relationship, and Table Definition windows.

5. Ascertain the existing table relationships for the report.


Open the Report Definition window for the report you want to customize and
click Tables to display the Report Table Relationships window. Note all the
report table relationships that exist for the main table. For the sample alternate
report (RM Customer Report), the relationships look like the following:

INTEGRATION GUIDE 45
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

After you’ve noted the report table relationships, close the Report Table
Relationships window.

6. Switch the main table for the report to the duplicate table.
In the Report Definition window, switch the main table for the report from the
original table to the duplicate table. A message will appear asking whether you
want to change the main table. Click OK. For the sample alternate report, the
duplicate table (IG_Customer_MSTR) replaces the original main table
(RM_Customer_MSTR).

7. Add table relationships to the new main table.


Click the Tables button and use the Report Table Relationships window to add
the table relationships you noted in step 5. For the sample alternate report,
relationships must exist for the following tables:

• RM Customer MSTR
• Customer Master Summary
• RM Period Setup
• RM Customer/Class Report TEMP
• Customer Statements E-mail Addresses Temp
• User Language Master

In addition, create new report table relationships for any third-party table(s)
you related to the duplicate table in step 4. In the sample alternate report, a new
report table relationship for the third-party table IG_Contact_History_MSTR
exists for the RM Customer Report. When finished, the report table
relationships for the sample RM Customer Report look like the following:

Duplicate table (main table)


Original tables related to the report
Third-party table

Once you’ve created the report table relationships, close the Report Table
Relationships window.

8. Lay out the report


In the Report Definition window, click Layout and make changes to the report
layout by adding fields from the third-party table(s) you created report
relationships for in step 7.

Once you’ve made all your changes, test the report in a test mode environment. To
do this, simply print the report as you normally would. To test the report in a
multidictionary environment, follow the instructions in the following section.

46 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

Testing alternate reports in a multidictionary


environment
Refer to Part 9, Use the following utilities in Dexterity Utilities to build your application dictionary
Packaging Your and test alternate reports in a multidictionary environment:
Application, for
information about ✔ Step Description
using Dexterity Utilities 1 Extract new third-party resources using the Extract utility.
to package and install
2 Transfer alternate reports using the Transfer Dictionary Module utility.
an application in a
multidictionary 3 Add product information using the Product Information utility.
environment. 4 Update series resources for reports using the Series Resources utility.
5 Create an installation file using the Auto-Chunk utility, and install it with an
unmodified Microsoft Dynamics GP dictionary.

Using the runtime Report Writer


Users can modify new third-party reports and alternate reports in your dictionary
using the runtime Report Writer. In a multidictionary environment, the following
window appears, allowing the user to enter the reports dictionary for either the
main product or the third-party dictionary.

In the main dictionary (Dynamics.dic), users can modify reports, or create new
reports as they normally would. In the third-party dictionary, users can modify a
new third-party report, create a new report, or modify an alternate report you’ve
delivered.

Refer to Chapter 43, Creating a reports dictionary


“Updating an When the user modifies reports in your dictionary for the first time, the runtime
Application,” for engine creates a new reports dictionary for your application using the information
information about in the launch file. The pathname entry for the reports dictionary in the launch file
updating forms and specifies the location and name of the reports dictionary.
reports dictionaries.

2
0
Microsoft Dynamics GP
3333
Sample Integrating App.
Windows
:C:Dynamics GP/Dynamics.dic
:C:Dynamics GP/Data/Forms.dic
:C:Dynamics GP/Data/Reports.dic
This generic pathname in
:C:Dynamics GP/Develop.dic
the launch file specifies
the name and location of
:C:Dynamics GP/Data/F3333.DIC
the reports dictionary. :C:Dynamics GP/Data/R3333.DIC

INTEGRATION GUIDE 47
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

The default location of the reports dictionary is the same location as your
application dictionary. However, a user can change the location of your
application’s reports dictionary using the Edit Launch File window in Microsoft
Dynamics GP. This window shows all applications appearing in a multidictionary
environment, and allows the user to change the location of the forms or reports
dictionaries.

This list shows the


products in the
launch file.

For instance, changing the location of the reports dictionary to a network location or
shared drive allows multiple users to share a single forms dictionary across a
network.

If you change the path for your reports dictionary, be sure to move an existing reports
dictionary to that location. Otherwise, the runtime engine will attempt to create a new
reports dictionary the next time a user accesses the Report Writer.

Controlling report access


To control access to new reports you create, you will need to add them to a security
task using the Security Task Setup window. You could create a new security task or
add the reports to an existing security task. Refer to Adding security data on page 394
for more information about adding security data for your integration. The following
illustration show one of the security tasks that controls access for reports in the
sample integration.

48 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

By default, security in Microsoft Dynamics GP doesn’t allow access to a new report.


Users assigned to the power user role will be able to access the original report, but
not the modified or alternate versions of the report. The administrator for the
Microsoft Dynamics GP installation will need to use the Alternate/Modified Forms
and Reports window to specify access to a modified or alternate version of a report.

Refer to the system documentation for Microsoft Dynamics GP for details about
using this window to control access to reports.

Report Writer functions to access report data


Alternate reports are one approach to making third-party data available to existing
reports. However, they have key limitations:

• Only one version of an alternate report can be used at a time. This prevents
additions from multiple third-party applications from appearing on the same
report. This situation often occurs for Purchase Order Processing and Sales
Order Processing reports.

• The user may have already made extensive customizations to the main report.
They would need to re-create these customizations for the alternate report.

To overcome these limitation, third-party developers can implement a technique


that uses Report Writer functions to make third-party data available to all reports. A
set of six Report Writer functions are included in the Dynamics dictionary for the
purpose of retrieving third-party data for reports. These functions are:

• rw_TableHeaderCurrency()
• rw_TableHeaderString()
• rw_TableLineCurrency()
• rw_TableLineString()
• rw_ReportStart()
• rw_ReportEnd()

Within the Report Writer, end-users can create a calculated field that calls one of
these predefined Report Writer functions, passes in the appropriate parameters to
the function, and displays a piece of data from the third-party integration.

INTEGRATION GUIDE 49
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

As an integration developer, it is up to you to make the data for your third-party


integration available through these functions. You will do this by creating function
triggers for these predefined functions. The trigger processing functions you write
will retrieve the appropriate third-party data (based on the parameter values passed
into the function) so the data can be used in a calculated field on the report.

It is up to the individual third-party applications to provide documentation and examples of


how these Report Writer functions should be used to retrieve data for use on reports.

The set of predefined Report Writer functions was originally designed to provide
access to third-party Sales Order Processing (SOP) and Purchase Order Processing
(POP) data. The functions can be used to retrieve data for any other reports, but
some of the parameters for the functions won’t be used.

Report writer function examples


Some examples are helpful when understanding this technique for accessing third-
party data for reports. The first example describes how third-party contact history
data from the sample integrating application can be made available for various
customer reports. The second example describes how additional SOP line item data
can be made available to SOP reports.

Example 1 - Contact history data


The following contact history data is to be available for use on various customer
reports:

• First Contact Date


• First Contact Salesperson
• Last Contact Date
• Last Contact Salesperson

These items can all be returned as string values, so the rw_TableHeaderString()


Report Writer function will be used to retrieve them. The following function trigger
is registered:

l_result = Trigger_RegisterFunction(function rw_TableHeaderString,


➥ TRIGGER_AFTER_ORIGINAL, function GetContactHistoryData);
if l_result <> SY_NOERR then
warning "Function trigger registration failed.";
end if;

The following is the trigger processing function that runs in response to this
function trigger. This function will access the IG_Contact_History_MSTR table,
retrieving the contact history information for the specified customer. The ID of the
customer must be passed in through the sNumber parameter. The data item to be
retrieved is specified by the iControl parameter.

50 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

Function name: GetContactHistoryData


function returns string sData;

in integer Dict_ID;
in string Report_Name;
in string sNumber;
in integer sType;
in integer iControl;

if Dict_ID = Runtime_GetCurrentProductID() then

{Try to retrieve the customer's corresponding contact history record}


'Customer Number' of table IG_Contact_History_MSTR = sNumber;
get table IG_Contact_History_MSTR;
if err() = OKAY then
{Based on the control field, determine which string to return}
case iControl
in [1] {First Contact Date}
sData = str('First Contact Date' of table
➥ IG_Contact_History_MSTR);
in [2] {First Contact Salesperson}
sData = 'Contact Salesperson ID' of table
➥ IG_Contact_History_MSTR;
in [3] {Last Contact Date}
sData = str('Last Contact Date' of table
➥ IG_Contact_History_MSTR);
in [4] {Last Contact Salesperson}
sData = 'Contact Salesperson ID 2' of table
➥ IG_Contact_History_MSTR;
else
sData = "[Not Found]";
end case;
end if;
end if;

The remaining work must be performed by the Report Writer user. A new
calculated field must be created for the report that will access the contact history
data. This calculated field will call the rw_TableHeaderString() Report Writer
function, supplying the appropriate parameters to indicate which data to retrieve.
For instance, to retrieve the “Last Contact Date” value, the following calculated
expression would be used:

FUNCTION_SCRIPT( rw_TableHeaderString 3333 "RM Customer Report"


RM_Customer_MSTR.Customer Number 0 3 )

Notice that the product ID for the sample integration (3333) is passed in, along with
the report’s name, the ID of the customer for which information is being retrieved,
and the control value 3 to indicate to the processing procedure that the last contact
date is to be returned.

Once the calculated field is complete, it can be placed on the report. When the report
is run, the trigger will be activated, and the trigger processing procedure will
retrieve the appropriate contact history information.

INTEGRATION GUIDE 51
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Example 2 - SOP line item data


The following example describes how additional line item information can be made
available for Sales Order Processing reports. An additional third-party table,
SOP_Ship_Weight, contains shipping weight and vendor information for line items
in a sales document. The primary key structure for the SOP_Ship_Weight table is
the same as the SOP_LINE_WORK table in the Dynamics.dic dictionary.

These two items can all be returned as string values, and are line items, so the
rw_TableLineString() Report Writer function will be used to retrieve them. A
function trigger like the following function would need to be registered:

l_result = Trigger_RegisterFunction(function rw_TableLineString,


➥ TRIGGER_AFTER_ORIGINAL, function GetAdditionalSOPData);
if l_result <> SY_NOERR then
warning "Function trigger registration failed.";
end if;

The following is the trigger processing function that runs in response to this
function trigger.

Function name: GetAdditionalSOPData


function returns string sData;

in integer dict_id;
in string report_name;
in string sNumber;
in integer sType;
in currency cSequenceOne;
in currency cSequenceTwo;
in integer iControl;

{If this function is not for our product then quit}


if dict_id <> Runtime_GetCurrentProductID() then
abort script;
end if;

{The SOP_Ship_Weight table is a parallel table to the SOP_LINE_WORK


table and has the same primary key structure as that table: SOP Number,
SOP Type, Component Sequence, Line Item Sequence. The report_name parameter
is not referenced here as we want to return the field data regardless of which
report it is used on.}

'SOP Number' of table SOP_Ship_Weight = sNumber;


'SOP Type' of table SOP_Ship_Weight = sType;
'Component Sequence' of table SOP_Ship_Weight = cSequenceOne;
'Line Item Sequence' of table SOP_Ship_Weight = cSequenceTwo;
get table SOP_Ship_Weight;

if err() = OKAY then


{There are two additional pieces of data in this table: Item Shipping
Weight and 'Vendor ID'. Integer values 1 and 2 will be used to identify
the fields}
case iControl
in [1]
{Item Shipping Weight is stored as an integer. Divide by

52 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

100.0 to force decimal places and then convert to a string.}


sData= str('Item Shipping Weight' of table SOP_Ship_Weight /
➥ 100.0);
in [2]
sData = 'Vendor ID' of table SOP_Ship_Weight;
end case;
else
sData = "[Not Found]";
end if;

The remaining work must be performed by the Report Writer user. For instance, the
additional SOP data might be added to the SOP Blank Invoice Form. To identify a
specific line in the sales document, the Component Sequence and Line Item
Sequence values from the Sales Transaction Amounts Work table are used. These
values are stored as long integers. The rw_TableLineString() function is expecting
these values to be currencies, so two calculated fields must be created to convert the
long integer values to currencies. For example, the calculated field expression for a
new LineItemSequence calculated field would be:

SOP_LINE_WORK.Line Item Sequence

The calculated field would have the Currency return type.

An additional calculated field must be created for the report that will access the SOP
shipping weight and vendor data. This calculated field will call the
rw_TableLineString() Report Writer function, supplying the appropriate
parameters to indicate which data to retrieve. For instance, to retrieve the shipping
weight value, the following calculated expression would be used:

FUNCTION_SCRIPT( rw_TableLineString 3333 "SOP Blank Invoice"


SOP_LINE_WORK.SOP Number SOP_LINE_WORK.SOP Type ComponentSequence
LineItemSequence 1)

Notice that the product ID of the dictionary registering the function trigger (in this
example 3333) is passed in, along with the report’s name, the document number
and document type, the calculated fields for the component sequence and line item
sequence, and the control value 1 indicating to the processing procedure that the
shipping weight is to be returned.

Once the calculated field is complete, it can be placed on the report. When the report
is run, the trigger will be activated, and the trigger processing procedure will
retrieve the appropriate SOP line item information.

INTEGRATION GUIDE 53
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Report Writer function reference


The following Report Writer functions can be used to return data to a calculated
field for a report. Select the function appropriate for the type of information you
want to retrieve.

rw_TableHeaderCurrency()
This function returns a currency amount or integer value to the calculated field. It
can be used in the header or body of a report. The function has the following
parameters:

function returns currency sData;

in integer Dict_ID;
in string Report_Name;
in string sNumber;
in integer sType;
in integer iControl;

Dict_ID – An integer specifying the dictionary ID of the product that must process
the request for data. The trigger processing function must check this parameter to
determine whether it should process the request.

Report_Name – A string containing the name of the report on which the calculated
field will be used. You may not need to use this parameter. If it’s not needed, an
empty string should be supplied when creating the calculated field.

sNumber – A string that will typically contain the ID of the transaction or other item
for which additional information is being retrieved. For example, this may be the
SOP Number.

sType – An integer that is typically used to indicate a document type.

iControl – An integer that is used to indicate which piece of data to return. The
trigger processing procedure will examine this parameter to determine which data
to retrieve and return.

rw_TableHeaderString()
This function returns a string value to the calculated field. It can be used in the
header or body of a report. The function has the following parameters:

function returns string sData;

in integer Dict_ID;
in string Report_Name;
in string sNumber;
in integer sType;
in integer iControl;

Dict_ID – An integer specifying the dictionary ID of the product that must process
the request for data. The trigger processing function must check this parameter to
determine whether it should process the request.

54 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

Report_Name – A string containing the name of the report on which the calculated
field will be used. You may not need to use this parameter. If it’s not needed, an
empty string should be supplied when creating the calculated field.

sNumber – A string that will typically contain the ID of the transaction or other item
for which additional information is being retrieved. For example, this may be the
SOP Number.

sType – An integer that is typically used to indicate a document type.

iControl – An integer that is used to indicate which piece of data to return. The
trigger processing procedure will examine this parameter to determine which data
to retrieve and return.

rw_TableLineCurrency()
This function returns a currency amount or integer value to the calculated field. It is
typically used in the line items (additional header sections) of a report. The function
has the following parameters:

function returns currency sData;

in integer Dict_ID;
in string Report_Name;
in string sNumber;
in integer sType;
in currency cSequenceOne;
in currency cSequenceTwo;
in integer iControl;

Dict_ID – An integer specifying the dictionary ID of the product that must process
the request for data. The trigger processing function must check this parameter to
determine whether it should process the request.

Report_Name – A string containing the name of the report on which the calculated
field will be used. You may not need to use this parameter. If it’s not needed, an
empty string should be supplied when creating the calculated field.

sNumber – A string that will typically contain the ID of the transaction or other item
for which additional information is being retrieved. For example, this may be the
SOP Number.

sType – An integer that is typically used to indicate a document type.

cSequenceOne – A currency value typically used to identify the line item for which
additional data is being retrieved. For typical SOP integrations, this will be the
Component Sequence field. For typical POP integrations, this will be the Break Field
1 field.

cSequenceTwo – A currency value typically used to identify the line item for which
additional data is being retrieved. For typical SOP integrations, this will be the Line
Item Sequence field. For typical POP integrations, this parameter can remain empty.

iControl – An integer that is used to indicate which piece of data to return. The
trigger processing procedure will examine this parameter to determine which data
to retrieve and return.

INTEGRATION GUIDE 55
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

rw_TableLineString()
This function returns a string value to the calculated field. It is typically used in the
line items (additional header sections) of a report. The function has the following
parameters:
function returns string sData;

in integer Dict_ID;
in string Report_Name;
in string sNumber;
in integer sType;
in currency cSequenceOne;
in currency cSequenceTwo;
in integer iControl;

Dict_ID – An integer specifying the dictionary ID of the product that must process
the request for data. The trigger processing function must check this parameter to
determine whether it should process the request.

Report_Name – A string containing the name of the report on which the calculated
field will be used. You may not need to use this parameter. If it’s not needed, an
empty string should be supplied when creating the calculated field.

sNumber – A string that will typically contain the ID of the transaction or other item
for which additional information is being retrieved. For example, this may be the
SOP Number.

sType – An integer that is typically used to indicate a document type.

cSequenceOne – A currency value typically used to identify the line item for which
additional data is being retrieved. For typical SOP integrations, this will be the
Component Sequence field. For typical POP integrations, this will be the Break Field
1 field.

cSequenceTwo – A currency value typically used to identify the line item for which
additional data is being retrieved. For typical SOP integrations, this will be the Line
Item Sequence field. For typical POP integrations, this parameter can remain empty.

iControl – An integer that is used to indicate which piece of data to return. The
trigger processing procedure will examine this parameter to determine which data
to retrieve and return.

rw_ReportStart()
This function can be called to notify the third-party application that the report has
started. It is typically called from a calculated field in the Report Header section. of
a report. The function has the following parameters:
function returns string Ret_Val;

in integer Dict_ID;
in string Report_Name;

Dict_ID – An integer specifying the dictionary ID of the product that must process
the request for data. The trigger processing function must check this parameter to
determine whether it should process the request.

Report_Name – A string containing the name of the report on which the calculated
field will be used. You may not need to use this parameter. If it’s not needed, an
empty string should be supplied when creating the calculated field.

56 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

rw_ReportEnd()
This function can be called to notify the third-party application that the report has
ended. It is typically called from a calculated field in the Report Footer section of a
report. The function has the following parameters:
function returns string Ret_Val;

in integer Dict_ID;
in string Report_Name;

Dict_ID – An integer specifying the dictionary ID of the product that must process
the request for data. The trigger processing function must check this parameter to
determine whether it should process the request.

Report_Name – A string containing the name of the report on which the calculated
field will be used. You may not need to use this parameter. If it’s not needed, an
empty string should be supplied when creating the calculated field.

Word templates for reports


Microsoft Word can be used to render reports created with the Report Writer. You
will create a Microsoft Word template that defines how the data for the report will
be displayed in the Word document. Refer to the Report Writer documentation for
details about how to create a Word template for a report. To use a Word template for
a report, you must do the following:

• Indicate that the report is template-enabled. This makes the report visible in the
Reports lookup window in Microsoft Dynamics GP, allowing you to work with
the template for the report.

This step is no longer necessary beginning with Microsoft Dynamics GP 2010 R2 (also
known as Service Pack 2). Beginning with this release, all reports are template-enabled.

• Ensure that the Report Writer can locate and retrieve the Word template for the
report when the report is run.

Making a report template-enabled


To make a report template-enabled, you must register a function trigger for the
IsTemplateEnabledReport() function of the syReportLookup form. Template-
enabled reports can be selected in the Reports lookup.

Template-enabled reports
appear in the Reports
lookup.

INTEGRATION GUIDE 57
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

The following example shows the registration for this trigger.


local boolean result;

l_result = Trigger_RegisterFunction(function IsTemplateEnabledReport of form


➥ syReportLookup, TRIGGER_AFTER_ORIGINAL,
➥ function IG_IsTemplateEnabledReport);
if l_result <> SY_NOERR then
warning "Trigger registration for Word Template reports failed.";
end if;

In the trigger processing function, you must check the product ID and resource ID
of the report that are passed in. These values indicate the report that is being
checked to find out whether it is template-enabled. If the product ID matches your
product, and the report ID matches a report that you want to be template-enabled,
return the value true from the function. The following example is the
IG_IsTemplateEnabledReport() trigger processing function for the sample
integrating application. It examines the product ID and resource ID passed into the
function, and compares them to the resource IDs for the reports that are to be
template-enabled. If the IDs match, the value true is returned from the function.
function returns boolean result;

in 'Product ID' nProdID;


in Resid nResID;

if nProdID = IG_PROD_ID then


{It's our report. Indicate that it is template enabled.}
case nResID
in [resourceid(report IG_Leads),
resourceid(report IG_Leads_List)]
result = true;
end case;
end if;

Retrieving the template for a report


When a report is run, Microsoft Dynamics GP must be able to retrieve the Word
template that is used for the report. If a Word template can be found for the report,
then the user can choose to have the report rendered by Microsoft Word.

The Report Destination window that is automatically displayed by the run report or
run report with name statements will automatically retrieve a Word template for a
report if a template has been created.

• In Microsoft Dynamics GP 2010, if a Word template is found, the “Template”


choice will be added to the report type list. Otherwise, only the “Standard”
report choice will be available.

• Beginning with Microsoft Dynamics GP 2010 R2 (also know and Service Pack
2), the Template choice is always available. If the user chooses Template, but no
report template can be found, Microsoft Dynamics GP will use the HTML
version of the report.

58 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

The “Template” report type will


use the Word template if one is
available for the report.

If you have implemented a Report Options window for your integration that
displays a Report Destination window, you must modify your code that opens the
Report Destination window to allow it to find the a Word template for a report. The
Report_Destination form and window in the Dynamics.dic dictionary are typically
used for report options. The code in your Report Options window that opens the
Report Destination form must set the product ID and resource ID fields in the
Report_Destination window. The Report_Destination window uses these values to
find out whether a Word template has been created and assigned for the report. If
one has, the “Template” choice for the Report Type list will use that template.

Code for the Destination


button must set the product
ID and resource ID for the
Report_Destination window.

The following example is the change script for the Destination button in the Leads
Report Options window in the sample integrating application. It opens the
Report_Destination window from the Dynamics.dic dictionary, allowing the user to
select the report destination. Notice that the values of the Product ID field and the
Resid field in the Report_Destination window are set to the values for the current
report. This allows the Report_Destination window to retrieve a Word template that
has been set up for the report.

local string l_Filename;

{Verify that an option name has been entered}


if empty('(L) Report Options') then
warning "Please select an option first.";
focus '(L) Report Options';
else
open form Report_Destination return to '(L) Dummy Return';
'(L) Button Flag' of window Report_Destination of form Report_Destination
➥ = true;
'Financial Report Name' of window Report_Destination of form
➥ Report_Destination = "Leads";
'(L) Report Option' of window Report_Destination of form
➥ Report_Destination = '(L) Report Options';

{Set product ID and resource ID so that a template can be used if one has
been set up.}

INTEGRATION GUIDE 59
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

'Product ID' of window Report_Destination of form Report_Destination =


➥ IG_PROD_ID;

if 'Report ID' of window 'Leads Report Options' = ReptID_LeadsWithOptions


➥ then
Resid of window Report_Destination of form Report_Destination =
➥ resourceid(report IG_Leads);
end if;

if 'Report ID' of window 'Leads Report Options' = ReptID_LeadsList then


Resid of window Report_Destination of form Report_Destination =
➥ resourceid(report IG_Leads_List);
end if;

{Have not opened the destination window or retrieved a report option}


if '(L) Dummy Flag Destination' = false then
'Print to Printer' of window Report_Destination of form
➥ Report_Destination = true;
else
'Ask Each Time' of window Report_Destination of form
➥ Report_Destination = 'Ask Each Time' of table IG_Leads_ROPT;

{Set the Export Type}


if 'Export Type' of file IG_Leads_ROPT > 1000 then
'Export Type' of window Report_Destination of form
➥ Report_Destination = 'Export Type' of file IG_Leads_ROPT - 1000;
else
'Export Type' of window Report_Destination of form
➥ Report_Destination = 'Export Type' of table IG_Leads_ROPT;
end if;

{Display the native path}


l_Filename = Path_MakeNative('File Export Name' of table
➥ IG_Leads_ROPT);

'File Export Name' of window Report_Destination of form


➥ Report_Destination = l_Filename;
'If File Existing' of window Report_Destination of form
➥ Report_Destination = 'If File Existing' of table IG_Leads_ROPT;
'Print to File' of window Report_Destination of form
➥ Report_Destination = 'Print to File' of table IG_Leads_ROPT;
'Print to Printer' of window Report_Destination of form
➥ Report_Destination = 'Print to Printer' of table IG_Leads_ROPT;
'Print to Screen' of window Report_Destination of form
➥ Report_Destination = 'Print to Screen' of table IG_Leads_ROPT;
end if;

run script '(L) Dummy PRE Window' of window Report_Destination of form


➥ Report_Destination;

end if;

60 IN T E G R AT I O N G U ID E
C H A P T E R 5 R E P O R T S

Importing and removing report templates


Typically, report templates are imported or removed from Microsoft Dynamics GP
through the Report Template Maintenance window. If you include report templates
with your integration, you may want to use code to import them into or remove
them from Microsoft Dynamics GP. Beginning with Microsoft Dynamics GP 2010
R2, you can do this using the syImportReportTemplate() and
syRemoveReportTemplate() functions available in the Dynamics dictionary.

INTEGRATION GUIDE 61
62 IN T E G R AT I O N G U ID E
Chapter 6: Procedures
Your application can call procedures in the Dynamics.dic dictionary to complete
common tasks (such as attaching form- and record-level notes), or more closely
integrate with the accounting system (such as posting to Microsoft Dynamics GP
tables from your application). Although you can’t view procedure names in the
Dynamics.dic dictionary, the procedure design documents available with the SDK
(Software Development Kit) provide the name, description, and parameters of each
procedure in the accounting system.

Information about procedures is divided into the following sections:

• Calling a procedure
• Using procedure triggers
• Using the script logger
• Procedure list

Calling a procedure
You can call a Microsoft Dynamics GP procedure exactly the same way as you call
your own procedures. Use the call script_name syntax for procedures and the call
script_name of form form_name syntax for form procedures.

1. Find out which procedure you want to use.


There are a variety of ways you can determine which procedures you’ll need to
use:

• Use the Dexterity Script Logger to find the specific procedures Microsoft
Dynamics GP calls for a given process.

• Use the procedure design documents available with the SDK for a descrip-
tion of all procedures available.

• Use the procedures listed in Procedure list on page 65 as a reference to the


most common and useful procedures.

• Use the procedures listed in Part 11, Script Reference, to perform common
integration tasks, such as adding navigation for your application.

2. Call the procedure.


In your development dictionary, write the script that calls the procedure. Be
sure you’re using the exact name of the procedure as it’s displayed in the SDK
procedure design documents. Parameters passed from your script must use the
same data types and the same order as those listed in the documentation.

3. Test the results of the procedure.


Use the sample company and test the results of the call. If the procedure
updated several tables (such as when posting a batch or adding a record to a
work table), the accounting system may reject new records if the procedure
didn’t update associated tables properly. To check the validity of any Microsoft
Dynamics GP tables you’ve updated, use the table maintenance utilities for
each table you’ve updated.

INTEGRATION GUIDE 63
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Using procedure triggers


Procedure triggers are activated when a specific Microsoft Dynamics GP procedure
is run. The trigger processing procedure that runs in response to the call can run
before or after the Microsoft Dynamics GP procedure runs, and it has access to the
same parameters as the original procedure.

The recommended method of using procedure triggers is to not reference the parameters
passed from the original script. Using this method, a procedure trigger simply activates
when the selected procedure is called.

Procedure triggers are especially useful if you want to complete additional


processing when certain processes in the accounting system occur, such as posting.
Refer to Chapter 11, “Procedure Triggers,” for more information.

Using the script logger


Refer to Chapter 29, Use the Dexterity script logger to find out which procedures run during a given
“Script Logger,” in process. This can be a useful tool in helping you understand the call chain used for
Volume 2 of the specific processes, such as posting a batch, if you don’t have source code. The
Dexterity following illustration shows how this utility logs scripts when calculating a
Programmer’s Guide document amount in the Receivables Transaction Entry window:
for more information.

Scripts that call the 'RM_Sales_Entry Trade_Discount_Amount CHG on form RM_Sales_Entry'


procedure appear in the 'RM_Sales_Entry Account_Amount CHG on form
order in which they run. RM_Sales_Entry'

'Payment_Terms_Calculate', 498.33000, 15.00000,


Procedures appear with 0.00000, 0.00000, 0.00000, 0, 0.00000, file
their names and 'SY_Payment_Terms_MSTR', 0, 10/21/95, 10/21/95,
parameter values. 11/20/95, 0.00000, 0.00000, 0.00000, 0.00000, 0

'Payment_Terms_Calculate_Avail', 498.33000,
0.00000, 0, 0.00000, 0.00000, file
'SY_Payment_Terms_MSTR'

Not all Microsoft Dynamics GP procedures are usable within a third-party product. We
recommend that, whenever possible, you use the procedures listed in Procedure list on
page 65, or those recommended for use by Dexterity technical support.

Once you understand the procedures in the call chain, you can call the same
procedures in your application to complete similar processing. To use the Script
Logger, complete the following steps:

1. Move to the location where the accounting system calls the


procedure.
Enter Dexterity test mode and log into the sample company. Move to the
window where the accounting system initiates the processing that you want to
take advantage of. For instance, to find out which procedures are called when
posting a single sales transaction, move to the Sales Transactions window.

64 IN T E G R AT I O N G U ID E
C H A P T E R 6 P R O C ED U R E S

2. Create the log file.


Choose Log Scripts from the Debug menu. A dialog box will appear, allowing
you to enter the name and location of the script log. The script logger will log all
scripts until you turn it off.

3. Review the script log.


View the script log using a text editor. The script log will show the procedures
called and the parameters passed to each.

Procedure list
The procedures listed in this section are suitable for performing common tasks
within an integrating application, and we recommend their use.

General Ledger
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Cards GS_Add_Account_On_The_Fly Adds either a posting, unit, fixed allocation or
variable allocation account on the fly.
Posting Any “GL_BB“ procedure (such These are General Ledger black box posting
as GL_BB_Initialize) routines used for various generic posting
activities.
Post_GL_Batch Posts normal or clearing batches entered using
the General Ledger Batch Entry window.
Post_GL_Master Posts normal, clearing or business batches that
are marked to post in the Master Posting
window.
Post_GL_Series Posts any type of GL batch or quick journal.
Transactions Calculate_GL_Period Returns the number of fiscal periods a
specified date falls within, and whether a given
period is closed.
Get_Next_Journal_Entry Increments a journal entry number from the
GL_SETP table.
Verify_Journal_Entry Verifies that a given journal entry number
hasn’t already been posted to the
GL_YTD_TRX_OPEN table.
Verify_TRX_Date Calculates the General Ledger period and fiscal
year, and verifies a transaction date.

INTEGRATION GUIDE 65
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Inventory
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Posting IV_Post_Batch Posts batches listed in Master Post, Series Post
or Inventory Batch Entry windows.
Transactions IV_Allocate_Qty Updates the quantity allocated fields for a site
record and overall site record.
IV_Default_Document_ Generates and reserves the next document
Number number for use in Transaction Entry and
Transfer Entry windows.
IV_Document_Number_ Ascertains whether a document number exists
Validate in the IV_TRX_HIST_HDR table. If the number
doesn’t exist, the document number is valid. If
the number exists, it’s incremented and re-
verified until no matching number exists in the
IV_TRX_HIST_HDR table.
IV_Get_New_Qty_ Returns the quantity available from the
Available IV_Item_MSTR_QTYS table for a given item
number, location and quantity type.

Invoicing
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Posting IVC_Post_Batch Posts any batch entered in Invoicing Batch Entry.
Transactions IVC_Calculate_Item_ Returns the unit cost, unit price and quantity for
Amounts an item and unit of measure (U of M).
IVC_Tax_Recalc_Invoice Recalculates all taxes for lines on an invoice.
IVC_Update_Dist Updates the distributions for an invoicing
document.

Multicurrency Management
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Transactions MC_Calculate_Amt_ Calculates a transaction amount based on the
From_X_Rate exchange rate.
MC_Get_Exchange_Rate Locates a valid exchange rate for an exchange
table ID and an exchange date.
MC_Verify_Currency_ID Verifies a currency ID by ascertaining whether it
exists, whether it’s available to the current
company, and whether it’s active for the current
company.
MC_Verify_Exchange_ Verifies an exchange table ID by ascertaining
Table_ID whether it exists, whether it’s available to the
current company, and whether it’s active for the
current company.
MC_Verify_Rate_Type_ID Verifies a rate type ID by ascertaining whether it
exists and whether the rate type ID has an
association with the currency ID.

66 IN T E G R AT I O N G U ID E
C H A P T E R 6 P R O C ED U R E S

Payables Management
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Calculations Batch_Total_Inc_Dec Increases or decreases the batch total for a
particular batch.
Number_of_Trx_Per_ Increases or decreases the number of
Batch_Inc_Dec transactions for a particular batch.
Conversion Convert_To_Words_And_ Converts a currency amount to words only, or to
Words_And_Numbers_I a combination of words and numbers. For
example, the currency amount $20.08 would
convert to “Twenty Dollars and 08 Cents” for
words only, and “$***20 Dollars And 08 Cents”
for words and numbers.
Posting PM_Distribution_Default Creates default distribution accounts for a cash
receipt, if there are no distributions.
PM_Validate_Batch_ Verifies the information in the Batch_Headers
Information table for a batch.
Post_PM_Batch Posts a single transaction entry, manual
payments, or computer checks batch.
Transactions PM_Add_Vendor_On_ Prepares the PM_Vendor_ Maintenance form for
The_Fly a new vendor that’s added on the fly.
PM_Control_Number_Fix Gets the next valid control numbers (voucher
and payment numbers) from the PM_SETP table
for the PM_Transaction_ Entry form.
PM_Create_Distributions Updates an existing distribution with a
distribution amount. If the distribution doesn’t
exist, it’s created.
Validation PM_Control_Number_ Validates any control number (a voucher or
Validate payment number) by checking whether the
control number exists in the PM_Key_MSTR
table. If it exists, this script increments the
number.

Payroll
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Posting UPR_Batch_Number_ Increments the batch ID by 1 when processing
Increment excess returned commissions.
Transactions UPR_Get_Base_ Returns pay record information for a given
Employee_Pay_Record employee ID.
UPR_Get_Posting_ Returns the posting account number for an
Account_Number account type, department, job title and code.
UPR_Set_Batch_Status_ Sets the batch status of the UPR_TRX_
To_Busy Batch_Activity table to busy for a given batch ID
when a user edits the batch.
UPR_TRX_Sequence_ Ascertains the next available transaction
Number_Validate number.
UPR_Verify_Based_On_ Ascertains whether the pay code for the current
Pay_Record employee ID is valid.

INTEGRATION GUIDE 67
PA RT 2 I N T E G R A TI O N C O M PO N E N T S

Receivables Management
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Posting RM_Post_Master Posts any batch entered in Receivables Batch
Entry.
Transactions Document_Number_Inc_ Increments or decrements a document number.
Dec
RM_Cash_Distribution_ Creates default distribution accounts for a cash
Default receipt if no distributions exist.
RM_Create_Default_ Creates default distribution accounts for a
Commissions commission if no distributions exist.
RM_Document_Number_ Validates a document number by checking for a
Validate record in the RM_Keys_MSTR table.
RM_Sales_Distribution_ Creates default General Ledger distributions for
Default transaction documents created in Receivables
Transaction Entry.
RM_Validate_GL_ Validates any General Ledger account for use in
Account Receivables Management.

Sales Order Processing


Details about the procedures listed here are available in the SDK.

Category Procedure Description


Posting SOP_Delete_Document Deletes unposted work transactions by
unallocating the line items.
SOP_Post_Batch Posts any batch entered in Sales Order
Processing Batch Entry.
SOP_Post_Delete_Work_R Deletes the work records that are no longer
ecords required after posting a transaction and printing
the posting journal
SOP_Post_Init Returns the information required for posting a
batch of Sales Order Processing documents.
SOP_Post_Print_Reports Prints the posting journals for a batch of Sales
Order Processing transactions.
SOP_Post_TRX Posts a Sales Order Processing transaction.
Reports SOP_DP_Print_Forms Prints Sales Order Processing documents. This
script should be called in the background.
Transactions SOP_Allocate_QTY Allocates a quantity for an item entered in a
transaction, and returns item quantity
information.
SOP_Auto_Allocate_Lot_ Assigns lot numbers based on the valuation
Numbers method.
SOP_Auto_Allocate_ Assigns serial numbers based on the valuation
Serial_ Numbers method.
SOP_Calculate_Item_ Returns the unit cost based on the valuation
Amounts method, and the unit price based on the
valuation method and price method.
SOP_Comm_Calc_ Calculates the commissions for a document
Invoice_Total that’s set to calculate commissions on the
invoice total.
SOP_Comm_Calc_Line_ Calculates the commissions for a document
Item that’s set to calculate commissions on the sale
amount.
SOP_Dist_Default Creates default distributions for an entire
document.

68 IN T E G R AT I O N G U ID E
C H A P T E R 6 P R O C ED U R E S

Category Procedure Description


Transactions SOP_Dist_Update_Other Updates the various header level distributions
(cont.) for a document.
SOP_Get_Aux_Accounts Returns the proper posting account number for
Sales Order Processing distributions.
SOP_Password Verifies various type ID and module setup
options supported. These options can be
accessed with a password.
SOP_Process_Hold_ Assigns a process hold to a document by
Assign creating the process hold in the
SOP_Process_Holds_WORK_HIST table.
SOP_Process_Hold_ Ascertains whether a process hold restricting a
Check particular action exists for a document.
SOP_Process_Hold_ Assigns default process holds for a document.
Default
SOP_Process_Hold_ Removes the SOP_Process_Holds_WORK_HIST
Delete records for a document.
SOP_Process_Hold_ Removes a single process hold from a
Delete_Hold document.

System Manager
Details about the procedures listed here are available in the SDK.

Category Procedure Description


Activity Check_For_Other_Users_ Ascertains whether one or multiple users are
tracking Logged_In logged into a company.
Install/startup Initialize Creates initial entries in the SY_Pathnames
table, and creates pathname translation records
for the current dictionary location ID.
Posting SY_Master_Post Posts all batches of a single batch source
entered in the Master Posting window that are
marked to post.
Table Progress_Control Checks whether the Progress_Control form is
maintenance open, and displays the table name, record
processed and percentage complete.
Taxes TX_Calculate_Taxes Calculates taxes for a document. This is the
primary gateway into the tax engine.
Transactions Check_Batch_Activity_ Determines whether a record exists in the
File SY_Batch_Activity table.
Check_Batch_Header_ Determines whether a record is locked in the
File_Locked SY_Batch_Activity table.
Delete_Batch_Activity_ Removes a record from the SY_Batch_Activity
Record table.
Utilities Translate_Pathnames Returns a pathname from the SY_Pathnames
table and converts it to the corresponding
translation entered in the SY_Pathnames_
Translate_MSTR table based on the dictionary
location ID entered in the defaults file.

INTEGRATION GUIDE 69
70 IN T E G R AT I O N G U ID E
PART 3: OBJECT TRIGGERS
Part 3: Object Triggers
Refer to Chapter 2, Use the information presented here to understand how to use object triggers in an
“Sample Integration,” integrating application. The sample integrating application (DEVELOP.DIC)
for more information available with Dexterity includes additional source code examples. We recommend
about installing and that you review this application as you’re reading about object triggers. The
using the sample following topics are discussed:
integrating application.
• Chapter 7, “Using Triggers,” provides an overview of triggers and the
guidelines necessary for using object triggers in your application.

• Chapter 8, “Form Triggers,” explains how you can create triggers that provide a
way to navigate to your application’s forms.

• Chapter 9, “Focus Triggers,” explains how you can create triggers that are
activated by focus events.

• Chapter 10, “Database Triggers,” explains how you can create triggers that are
activated by database operations.

• Chapter 11, “Procedure Triggers,” explains how you can create triggers that are
activated when procedures are called.

• Chapter 12, “Function Triggers,” explains how you can create triggers that are
activated when functions are called.

• Chapter 13, “Cross-dictionary triggers,” describes how to use triggers with


applications other than the main product.

72 IN T E G R AT I O N G U ID E
Chapter 7: Using Triggers
Triggers are functionality that allows an application to respond to events in another
dictionary. To create a trigger, you need to register it with the runtime engine. The
registration specifies which event activates the trigger and what procedure runs in
response. The procedure that runs in response is called the trigger processing
procedure. The trigger processing procedure can complete additional processing,
such as saving or deleting a third-party record, or opening or restarting a form.
Information about triggers is divided into the following sections:

• Trigger benefits
• Types of triggers
• Registering triggers
• Trigger processing procedure
• Unregistering triggers
• Enabling and disabling triggers
• Customization Status window
• Testing triggers

Keep in mind that object triggers are not the same as triggers in SQL Server, which
relational database environments commonly use. Object triggers are a Dexterity-
specific feature. They reside totally in your application and respond to events
initiated by a Dexterity application. In contrast, a SQL Server trigger invokes named
stored procedures in a SQL database in response to other database events.

Trigger benefits
Dexterity’s trigger design has the following benefits:

1. Decreases the effects of maintenance.


Refer to Chapter 3, Triggers reduce the number of modifications made directly to Microsoft
“Forms,” and Chapter Dynamics GP forms, such as adding navigational buttons or attaching form
5, “Reports,” earlier in scripts. By limiting the number of direct modifications, your application’s code
this manual for more is more independent of the products it integrates with, which will likely reduce
information about the the impact of maintenance updates on your application. Keep in mind that
impact of maintenance triggers may not totally eliminate the need to customize Microsoft Dynamics
updates. GP forms. Most likely, you’ll use a combination of triggers and form
customizations.

2. Multiple developers can trigger off of the same form.


Several third-party developers can deliver enhancements for the same form
with fewer conflicts. Without triggers, Microsoft Dynamics GP displays only
one version of an alternate form for a user, allowing a user to access
customizations by only one third-party developer at a time.

3. Initiate actions without modifying source code.


Triggers allow third-party developer actions to occur before or after specified
actions in the main application. This allows you to extend the functionality of
the accounting system without having to make modifications to the source
code.

INTEGRATION GUIDE 73
PA RT 3 O B J EC T TR I G G E R S

Types of triggers
There are five trigger types supported in Dexterity. The following sections explain
each briefly; the remaining chapters in this part explain each in more detail.

Form triggers
When a form trigger is registered for a form, an “Additional” menu is added for
windows in the form in Microsoft Dynamics GP. In the registration, you specify a
menu item that will appear in the “Additional”. When the user selects this
menu item, the form trigger is activated, allowing your application to respond.
Typically, form triggers are used to provide navigation to your form without
customizing the Microsoft Dynamics GP form with a navigational control (such as a
push button).

Focus triggers
Focus triggers are activated by focus events, such as a window opening or closing,
or the focus moving from field to field. Focus events occur in any location where
Dexterity allows you to attach a script, such as window pre and post scripts, or field
pre, change and post scripts.

A focus trigger can be activated by any focus event on the form (such as when the
user clicks the Save button, or restarts the form). This gives you the same
functionality as attaching a script directly to a form, without modifying the form
directly.

Database triggers
Database triggers are activated by successful table operations, such as a record
begin read, saved, or deleted. The procedure that runs in response to a database
trigger has access to the same table buffer contents as the script that performed the
database operation.

Database triggers are useful for maintaining referential integrity between records in
your application and related records in the accounting system. When Microsoft
Dynamics GP reads, saves or deletes a record, you can use a database trigger to
perform similar operations for a related table in your application.

Procedure triggers
A procedure trigger is activated when a specific procedure is run. The trigger
processing procedure runs either before or after the procedure being triggered from
and has access to the same parameters as the original procedure.

Function triggers
A function trigger is activated when a specific function is run. You can run a
function or procedure in response to the function being triggered from. The function
or procedure that runs in response to the function call can run before or after the
original function.

74 IN T E G R AT I O N G U ID E
C H A P T E R 7 U S I N G TR I G G E R S

Registering triggers
To create an object trigger, you must register the trigger for use with the runtime
engine. You also need to create a trigger processing procedure that runs when the
trigger is activated. Use the following functions to register each of your
application’s triggers for use with the runtime engine.

Trigger type Function and parameters


Form Trigger_RegisterForm(form form_name, menu_item_name,
accelerator_key, script processing_procedure {, tag})
Focus Trigger_RegisterFocus(anonymous (qualified_resource), focus_type,
attach_type, script processing_procedure {, tag})
Database Trigger_RegisterDatabase(anonymous(table table_name), form
form_name, table_operations, script processing_procedure {, tag})
Procedure Trigger_RegisterProcedure(script procedure_name {of form form_name},
attach_type, script processing_procedure {, tag})
Function Trigger_RegisterFunction(function function_name {of form form_name},
attach_type, [function processing_function | script processing_procedure]
{, tag})

The trigger registration specifies the conditions that will activate the trigger. For
instance, the registration for a procedure trigger includes the name of the procedure
that will activate the trigger when it is called.

When you register a trigger, a tag is assigned that uniquely identifies the trigger. The
tag is returned by the optional tag parameter for each trigger registration function.
You will use the tag when you want to enable, disable or unregister the trigger.
There is no way to get a specific trigger’s tag after the trigger has been registered. If
you need to work with an individual trigger, you must keep track of the tag
assigned when you registered the trigger. Commonly, global variables are used to
store the tag for each trigger.

When you register a trigger, the return value from the function indicates whether
the trigger was registered. The following table lists the possible return values:

Constant Value Description


SY_NOERR 0 No error occurred.
SY_UNKNOWN 1 An unknown error occurred and the trigger was not
registered.
SY_INVALID_SCRIPT 2 The trigger processing script was either not found or had the
wrong number of parameters. The trigger was not registered.
SY_INVALID_FOCUS 3 The focus_type is not valid for the resource for which the
trigger is being registered.
SY_INVALID_OBJECT 4 The object for which the trigger is being registered cannot be
found.

Refer to Chapter 20, Although you can register triggers from anywhere in your application, the
“Procedures,” in preferred method is through a startup procedure. This is a procedure that’s run
Volume 2 of the prior to the Main Menu form pre script for for the main application dictionary. You
Dexterity can create two types of startup procedures:
Programmer’s Guide
for more information • Create a procedure named “Startup” for an application that integrates with
about procedures. Microsoft Dynamics GP. For multiple applications, startup procedures run in
the order in which the applications are listed in the launch file.

INTEGRATION GUIDE 75
PA RT 3 O B J EC T TR I G G E R S

• Create a procedure named “Startup_Main” for a stand-alone application.


Although triggers are primarily a communication device between main product
dictionaries and integrating applications, you can use them to trigger events in
a stand-alone dictionary.

For example, the following procedure named “Startup” registers a form trigger. It
runs before the form pre script for the Main Menu form. The procedure named
IG_Open_Contact_History runs in response to this trigger.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterForm(form RM_Customer_Maintenance,


➥ "Contact History", "1", script IG_Open_Contact_History);
if l_result <> SYNOERR then
warning "Form trigger registration failed.";
end if;

If you make changes in how your triggers are registered, the registration code must
be run again before any changes will take effect. If your triggers are registered in the
Startup procedure, be sure you exit then restart the runtime engine (or test mode) to
reregister your triggers.

Trigger processing procedure


The script that runs in response to the trigger is called a trigger processing
procedure. This procedure must be in the same dictionary as the script that
registered the trigger. For most triggers, the trigger processing procedure must be a
global procedure. The exception is function triggers, which can run a global
function in response to the trigger.

The following example processing procedure runs in response to the form trigger
registered for the RM_Customer_Maintenance form. This procedure runs when the
user selects the Contact History menu item.

{Name: IG_Open_Contact_History}
if not isopen(form IG_Contact_History) then
open form IG_Contact_History;
'Customer Number' of window IG_Contact_History of form IG_Contact_History
➥ = 'Customer Number' of window RM_Customer_Maintenance of form
➥ RM_Customer_Maintenance;
run script 'Customer Number' of window IG_Contact_History
➥ of form IG_Contact_History;
end if;

Unregistering triggers
Once registered, a trigger remains valid until you exit the runtime engine, exit test
mode or unregister it. To unregister a trigger, use the Trigger_Unregister() function
and the tag that uniquely identifies the trigger. Remember, the tag was assigned
when you registered the trigger. When you unregister a trigger, its tag becomes
invalid. If you reregister the trigger, a new tag will be assigned.

76 IN T E G R AT I O N G U ID E
C H A P T E R 7 U S I N G TR I G G E R S

Enabling and disabling triggers


There are several methods for temporarily disabling triggers for an application. You
can enable or disable all triggers in an application, or just specific triggers. To enable
or disable all triggers in an application, use the Trigger_Enable() function or the
Customization Status window. To enable or disable specific triggers, use the
Trigger_EnableSingle() and Trigger_DisableSingle() functions.

To enable or disable specific triggers, you need to know the tag that was assigned when you
registered the trigger.

Customization Status window


You can view a list of all current applications and disable their corresponding
triggers using the Customization Status window. Open this window by choosing
Customization Status from the Tools menu. It lists currently active products and
whether each product has triggers enabled or disabled. The window is shown in the
following illustration:

When using your development dictionary in test mode, the name of the
Dynamics.dic dictionary will appear in this window. When running your
integrating application in a multidictionary environment, this window will list both
products.

You can print the Customization Status report from the Customization Status
window. This report lists information about triggers in the selected dictionary. The
following illustration shows a portion of this report:

When printed in test mode, this report lists only the triggers for the development
dictionary. When printed in a multidictionary environment, all products currently
running will be listed in the report.

INTEGRATION GUIDE 77
PA RT 3 O B J EC T TR I G G E R S

Testing triggers
Triggers are designed to work identically whether you are using your development
dictionary (in test mode), or operating in a multidictionary environment (at
runtime). However, you should test your application’s triggers in a multidictionary
environment as much as possible, because this environment most closely matches
your customers’ environment.

Triggers will allow you to change core application functionality. For example,
when using a focus trigger with a field, the reject script statement will prohibit the
change script for that field from running.

When testing and debugging your application, it’s important that you account for
all situations where you may be affecting Microsoft Dynamics GP functionality,
such as in the previous example. During the testing process, you can enable and
disable your application’s triggers appropriately to locate the source of application
errors.

78 IN T E G R AT I O N G U ID E
Chapter 8: Form Triggers
When you register a form trigger for a form, the form for which the trigger is
registered adds an “Additional” menu for each window in the form. The item you
registered will appear in this menu. When selected, the menu item activates the
trigger processing procedure you’ve written. Although you can complete any
processing you’d like with this processing procedure, its intended use is for opening
a corresponding third-party form:

The Additional menu


includes items for one or
more developer forms.

See Chapter 1, Form triggers are especially useful when you don’t want to modify a Microsoft
“Developing Dynamics GP form by adding a navigational control (such as a push button). For
Integrations,” for instance, instead of modifying the RM_Customer_Maintenance form to have a
information about “Contact History” button, the sample integrating application uses a form trigger.
installing the sample When you open the RM_Customer_Maintenance form, the Additional menu will
integrating application. display an item that opens the third-party form named IG_Contact_History.

You must redistribute alternate forms with each maintenance release of Microsoft Dynamics
GP. Rather than creating alternate forms, we recommend you provide additional
functionality using a third-party form accessed from a form trigger.

Information about form triggers is divided into the following sections:

• Registering form triggers


• Disabling form triggers
• Multiple third-party developer issues

INTEGRATION GUIDE 79
PA RT 3 O B J EC T TR I G G E R S

Registering form triggers


Before you use form triggers, you must first register them for use with the runtime
engine. The Trigger_RegisterForm() function handles the registration process for a
form trigger. Refer to the Trigger function library in the Function Library Reference
manual for a complete description of this function.

Example: Registering a form trigger


This form trigger runs when the user displays the RM_Customer_Maintenance
form. The menu item is “Contact History,” it has no accelerator key, and it calls the
procedure named IG_Open_Contact_History.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterForm(form RM_Customer_Maintenance,


➥ "Contact History", "", script IG_Open_Contact_History);
if l_result <> SY_NOERR then
warning "Form trigger registration failed.";
end if;

When the user chooses the Contact History menu item, this trigger processing
procedure opens the third-party form named IG_Contact_History, sets window
fields, and retrieves a record from the Contact History table.

{Name: IG_Open_Contact_History}
open form IG_Contact_History;

if isopen(form RM_Customer_Maintenance) then


'Customer Number' of window IG_Contact_History of form
➥ IG_Contact_History = 'Customer Number' of window
➥ RM_Customer_Maintenance of form RM_Customer_Maintenance;
run script 'Customer Number' of window IG_Contact_History of
➥ form IG_Contact_History;
end if;

Disabling form triggers


To disable all triggers in an application, use the Trigger_Enable() function or the
Customization Status window. To disable specific triggers, use the
Trigger_DisableSingle() function. If you disable a form trigger for a form that’s
currently open, the menu item in the Extras menu won’t disappear until the user
closes the form. If the user chooses the menu item before closing the form, the
message “Cannot run form trigger” will be displayed.

80 IN T E G R AT I O N G U ID E
C H A P T E R 8 F O R M T R I G G E R S

Multiple third-party developer issues


Form triggers reduce the number of “typical” customizations made to a Microsoft
Dynamics GP form, such as adding a navigational button. By reducing the number
of form customizations you make, other third-party developers can deliver
enhancements for the same form with fewer conflicts.

Multiple alternate forms


If you don’t use form triggers and more than one third-party developer customizes
a Microsoft Dynamics GP form, the accounting system is able to display only one
version of the alternate form for a given user; customizations from other third-party
developers will have no effect. However, by delivering your enhancements on a
third-party form accessed from the Additional menu, multiple third-party
developers can deliver enhancements for the same Microsoft Dynamics GP form.

We recommend that you examine the customizations you currently make to Microsoft
Dynamics GP forms, and determine whether you can provide the same functionality using
triggers.

Menu items
If more than one third-party developer adds functionality to the same Microsoft
Dynamics GP form using form triggers, the Additional menu will list several menu
items, one for each third-party form.

Duplicate menu item names from multiple third-party developers will appear in the
Additional menu with no functional conflicts. To minimize any confusion from
possible naming conflicts, we recommend that you don’t hard-code the name of the
menu item during the form trigger registration. Instead, refer to a getmsg() string in
the registration so users can modify the menu item using the Modifier.

The following example uses the getmsg() function to refer to a message (with the
resource ID of 22,233) stored in the dictionary.

local integer l_result;

l_result = Trigger_RegisterForm(form RM_Customer_Maintenance, getmsg(22233),


➥ "", script IG_Open_Contact_History);
if l_result <> SY_NOERR then
warning "Form trigger registration failed.";
end if;

INTEGRATION GUIDE 81
82 IN T E G R AT I O N G U ID E
Chapter 9: Focus Triggers
Focus triggers are activated by “focus” events, such as a window opening or
closing, or the focus moving from one field to the next. You can use focus triggers
anywhere Dexterity allows you to attach a script, such as window pre and post
scripts, or field pre, change and post scripts. Focus triggers respond to focus events
regardless of whether scripts already exist for those focus events.

You can create focus triggers that respond to the following types of objects and
focus events:

Object Available focus events


Field pre, change, post, or context menu
(Note: Button fields run triggers for change focus events only.)
Form pre or post
Window pre, post, activate, print, or context menu
Scrolling Window line pre, line change, line post, line fill, line insert, line delete, or
context menu
Menu change (for the menu item)
Commands change

Focus triggers require that you specify the object that activates the trigger (such as a
window, form or field), the focus event for that object (such as a pre, change or post
event), and the procedure you want to run in response to the trigger.

Information about focus triggers is divided into the following sections:

• Registering focus triggers


• Using reject script
• Multiple third-party developer issues
• Pending focus events
• Verifying table operations
• Form focus triggers
• Window focus triggers
• Scrolling window focus triggers
• Field focus triggers
• Menu focus triggers
• Table buffers for focus triggers

Registering focus triggers


Before you use focus triggers, you must register each for use with the runtime
engine. The Trigger_RegisterFocus() function handles the registration process for
focus triggers, typically within a startup procedure. Refer to the Trigger function
library for a complete description of this function.

Example 1: Registering a focus trigger


This example registers a focus trigger used to check required fields in a form when
the user clicks the Save button. The procedure run in response to this trigger is
IG_Verify_Contact_Save.

INTEGRATION GUIDE 83
PA RT 3 O B J EC T TR I G G E R S

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous('Save Button' of window


➥ RM_Customer_Maintenance of form RM_Customer_Maintenance),
➥ TRIGGER_FOCUS_CHANGE, TRIGGER_BEFORE_ORIGINAL, script
➥ IG_Verify_Contact_Save);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

Using reject script


A typical use for focus triggers is to verify the state of the application before
Microsoft Dynamics GP processing occurs. For example, when the user clicks the
Save button in Microsoft Dynamics GP, you may want to verify the state of the
application before allowing the save operation to proceed. This means the focus
trigger that verifies the state of the application should run before the original button
change script. If the application doesn’t meet certain conditions, you can use the
reject script statement to stop all pending script operations for your application and
for Microsoft Dynamics GP.

Multiple third-party developer issues


There are additional considerations when using the reject script statement if you
install your application with other third-party applications in the same Microsoft
Dynamics GP system. Depending on when the trigger runs relative to the button’s
change script (before or after, using the attach_type parameter), reject script has
different results. The following table shows multiple applications using triggers:

Completion order Process


1 App. 1 trigger - runs before the Save button change script
2 App. 2 trigger - runs before the Save button change script
3 App. 3 trigger - runs before the Save button change script
4 original Save button change script
5 App. 4 trigger - runs after the Save button change script
6 App. 5 trigger - runs after the Save button change script

Prior to the original Microsoft Dynamics GP change script, any application that
issues a reject script statement will cancel all processing for the current focus event.
For instance, if application 2 uses the reject script statement in a processing
procedure, it cancels all remaining focus triggers as well as the original save button
change script. This ensures that no further processing continues until all
applications meet the appropriate conditions.

Once the Microsoft Dynamics GP change script runs successfully, all following
triggers run successfully. For instance, if application 4 uses reject script, a focus
trigger for application 5 still runs.

84 IN T E G R AT I O N G U ID E
C H A P T E R 9 F O C U S T R I G G E R S

Pending focus events


In certain instances, the pending change and post scripts for the currently-focused
field need to be run so the trigger processing procedure can perform the necessary
actions. Use the Window_PullFocus() function in the trigger processing procedure
to pull the focus from the current window and cause any pending scripts to be run.
After the focus has been pulled, no item in the window will be focused.

Verifying table operations


Refer to Chapter 10, Focus triggers are useful in cases where you use a database trigger to save or delete
“Database Triggers,” a third-party record in response to a save or delete operation in Microsoft Dynamics
for more information GP (using the Save or Delete button). This type of focus trigger should run before
about using database the original button change script. If the record operation doesn’t meet certain
triggers for saving conditions (such as the user didn’t enter all required fields), you can cancel table
records. operations for your application and for Microsoft Dynamics GP using the reject
script statement.

You shouldn’t use focus triggers to save or delete a record directly, because there’s no way of
knowing whether the Microsoft Dynamics GP table operation was successful or not. Instead,
you should use database triggers to save and delete third-party records based on a successful
Microsoft Dynamics GP table operation.

Saving records
To save a third-party record with a related Microsoft Dynamics GP record, apply a
focus trigger to the Save button. This trigger can verify whether conditions required
for the save have been met, such as whether the user addressed all required fields in
the third-party window. If the save operation doesn’t meet these conditions, the
reject script statement stops processing for the Microsoft Dynamics GP save
operation.

User clicks the Save button.

Third-party focus trigger script


checks for required fields.

OK
No reject record
to
save? (third-party)

Yes

Save button change script attempts to


save the Microsoft Dynamics GP record.

Was
No abort script
the record
saved? (Microsoft Dynamics GP)

Yes

Third-party database trigger saves the


third-party record.

INTEGRATION GUIDE 85
PA RT 3 O B J EC T TR I G G E R S

Once the user addresses the required fields, then clicks Save again, the focus trigger
verifies the conditions for the save, and a database trigger can complete the save.

Example 2: Verifying a record save


This trigger is activated when the user clicks the Save button in the Customer
Maintenance window. Notice that it runs before the original save button change
script.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous('Save Button' of window


➥ RM_Customer_Maintenance of form RM_Customer_Maintenance),
➥ TRIGGER_FOCUS_CHANGE, TRIGGER_BEFORE_ORIGINAL, script
➥ IG_Verify_Contact_Save);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

This trigger processing procedure runs in response to the focus trigger on the Save
button. If the user doesn’t enter all required fields in the Contact History window,
the reject script statement cancels all processing and the user can address the
required fields. Otherwise, the Microsoft Dynamics GP save operation runs to
completion.

{Name: IG_Verify_Contact_Save}
local integer l_answer;

if isopen(form IG_Contact_History) then


if not required(form IG_Contact_History) then
l_answer = ask("Not all required contact information
➥ was entered. Do you want to enter this information?", "Yes",
➥ "No", "Cancel");
if l_answer = ASKBUTTON1 then
{The user clicked Yes, so stop all processing.}
reject script;
elseif l_answer = ASKBUTTON2 then
{The user doesn't want to save the third-party record,
so allow the Microsoft Dynamics GP save to proceed.}
clear form IG_Contact_History;
else
{The user clicked Cancel, so stop all processing.}
reject script;
end if;
end if;
end if;

86 IN T E G R AT I O N G U ID E
C H A P T E R 9 F O C U S T R I G G E R S

Deleting records
When the user deletes a record from Microsoft Dynamics GP, it may be necessary to
delete a corresponding record from a third-party table. A focus trigger on the Delete
button can verify whether the third-party record can be deleted. If the third-party
record can’t be deleted, the reject script statement cancels all processing. The
process is shown in the following illustration.

User clicks the Delete button.

Third-party focus trigger script


checks whether it can delete a
third-party record..

OK
No reject record
to
delete? (third-party)

Yes

Delete script attempts to delete the


Microsoft Dynamics GP record.

Was
No abort script
the record
deleted? (Microsoft Dynamics GP)

Yes

Third-party database trigger deletes the


corresponding third-party record.

If the third-party record can be deleted, Microsoft Dynamics GP is allowed to


continue and delete its record. The database trigger then runs in response to the
Microsoft Dynamics GP record delete, and completes the third-party record delete.

Example 3: Verifying a record delete


This focus trigger is activated when the user clicks the Delete button in the
Customer Maintenance window. Notice that it runs before the original Delete
button change script.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous('Delete Button' of window


➥ RM_Customer_Maintenance of form RM_Customer_Maintenance),
➥ TRIGGER_FOCUS_CHANGE, TRIGGER_BEFORE_ORIGINAL, script
➥ IG_Verify_Contact_Delete);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

INTEGRATION GUIDE 87
PA RT 3 O B J EC T TR I G G E R S

This trigger processing procedure attempts to read and actively lock a third-party
record. If it can, the Microsoft Dynamics GP delete continues. If it can’t obtain an
active lock, it issues a reject script statement and stops all processing.

{Name: IG_Verify_Contact_Delete}
release table IG_Contact_History;

'Customer Number' of table IG_Contact_History = 'Customer Number'


➥ of window RM_Customer_Maintenance of form RM_Customer_Maintenance;

{Read the record and try to actively lock it.}


change table IG_Contact_History by IG_Contact_History_Key1, lock;

if err() = LOCKED then


{The record is actively locked by another user and can't be
deleted. Cancel all processing.}
warning "This customer record can't be deleted. Other users are
➥ editing customer contact information.";
reject script;
end if;

Form focus triggers


Forms have two focus events with which you can use a focus trigger. The following
table explains each focus event, and the corresponding value of the focus_type
parameter required in the Trigger_RegisterFocus() function:

Focus event Description Value of focus_type


pre Occurs each time the form opens, not TRIGGER_FOCUS_PRE
each time the form restarts.
post Occurs each time the form closes. TRIGGER_FOCUS_POST

Example 4: Form focus trigger


This trigger is activated when the Customer Maintenance form closes and the
form’s post script runs (indicated by TRIGGER_FOCUS_POST).

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous(form RM_Customer_Maintenance),


➥ TRIGGER_FOCUS_POST, TRIGGER_AFTER_ORIGINAL, script
➥ IG_Close_Contact_History);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

This trigger processing procedure for the form focus trigger simply closes the third-
party form.

{Name: IG_Close_Contact_History}

close form IG_Contact_History;

88 IN T E G R AT I O N G U ID E
C H A P T E R 9 F O C U S T R I G G E R S

Window focus triggers


Windows have four focus events with which you can use a focus trigger. The
following table explains each focus event, and the corresponding value of the
focus_type parameter required in the Trigger_RegisterFocus() function:

Focus event Description Value of focus_type


pre Occurs each time the window opens or TRIGGER_FOCUS_PRE
restarts.
post Occurs each time the window closes. TRIGGER_FOCUS_POST
activate Occurs each time the window opens or TRIGGER_FOCUS_ACTIVATE
moves to the front.
print Occurs when you choose Print from TRIGGER_FOCUS_PRINT
the File menu.
context menu Occurs when the context menu for the TRIGGER_FOCUS_CONTEXT_MENU
window is displayed.

Example 5: Window focus trigger


This trigger is activated when the Customer Maintenance window restarts, and
runs the window’s pre script. The Customer Maintenance window restarts when
the user clicks the Save, Delete or Clear buttons.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous(window
➥ RM_Customer_Maintenance of form RM_Customer_Maintenance),
➥ TRIGGER_FOCUS_PRE, TRIGGER_AFTER_ORIGINAL, script
➥ IG_Restart_Contact_History);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

The trigger processing procedure simply restarts the third-party form:

{Name: IG_Restart_Contact_History}

clear form IG_Contact_History;


unlock 'Customer Number' of window IG_Contact_History
➥ of form IG_Contact_History;

Example 6: Window context menu focus trigger


This trigger is activated when the context menu for the Customer Maintenance
window is displayed.

{Name: Startup}
l_result = Trigger_RegisterFocus(anonymous(window RM_Customer_Maintenance
➥ of form RM_Customer_Maintenance), TRIGGER_FOCUS_CONTEXT_MENU,
➥ TRIGGER_AFTER_ORIGINAL,
➥ script IG_Trigger_Customer_Maintenance_Context_Menu);
if l_result<>SY_NOERR then
warning "Focus trigger registration failed.";
end if;

INTEGRATION GUIDE 89
PA RT 3 O B J EC T TR I G G E R S

The trigger processing procedure adds a command to the context menu that will
open the Contact History form. Notice how the script retrieves the tag of the context
menu command list, and then adds the command to the end of the list.

{Name: IG_Trigger_Customer_Maintenance_Context_Menu}

local integer result;


local integer command_tag;
local integer context_menu_command_list;

{Get the tag for the context menu}


context_menu_command_list = Command_GetTag(command cmdListContextMenu);

{Add a separator, if needed, in case there are other commands already


in the context menu}
if CommandList_NumCommands(context_menu_command_list) > 0 then
command_tag = Command_GetTag(command cmdSeparator);
result = CommandList_Add(context_menu_command_list, command_tag);
end if;

{Add the command to display the Contact History}


command_tag = Command_GetTag(command IG_ContactHistory_ContextMenu of form
➥ Command_IG_Sample);
result = CommandList_Add(context_menu_command_list, command_tag);

Scrolling window focus triggers


Scrolling windows have six focus events with which you can use a focus trigger.
The following table explains each focus event, and the corresponding value of the
focus_type parameter required in the Trigger_RegisterFocus() function:

Focus Event Description Value of focus_type


line pre Occurs each time the focus moves to TRIGGER_FOCUS_PRE
a new line in the scrolling window.
line change Occurs each time any field in the line TRIGGER_FOCUS_CHANGE
changes and the focus moves to a
new line in the scrolling window.
line post Occurs each time the focus moves to TRIGGER_FOCUS_POST
a new line in the scrolling window.
line fill Occurs each time a new line is TRIGGER_FOCUS_FILL
displayed in the scrolling window.
When you display the scrolling
window initially, the fill line event
runs for each line until the window is
full.
line insert Occurs each time you add a new line TRIGGER_FOCUS_INSERT
to the scrolling window by choosing
Insert Line from the Edit menu, or
using the insert line statement.
line delete Occurs each time you delete a line TRIGGER_FOCUS_DELETE
from the scrolling window by
choosing Delete Line from the Edit
menu, or using the delete line
statement.
context menu Occurs when the context menu for TRIGGER_FOCUS_CONTEXT_MENU
the scrolling window line is
displayed.

90 IN T E G R AT I O N G U ID E
C H A P T E R 9 F O C U S T R I G G E R S

Example 7: Scrolling window focus trigger


This trigger updates the Contact History window with information from the
selected line in the Customers and Prospects lookup window. The item in the
Contact History window changes when the user chooses a different item in the
Customers and Prospects lookup window. It uses the pre line focus event
(TRIGGER_FOCUS_PRE) to run a processing procedure each time the focus moves
to a new line.

{Name: Startup}
local integer l_result;

l_result = register_focus_trigger(anonymous(window
➥ Customer_Lookup_Scroll of form Customer_Lookup), TRIGGER_FOCUS_PRE,
➥ TRIGGER_AFTER_ORIGINAL, script IG_Get_Scrollwin_Information);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

When the trigger is activated, this trigger processing procedure sets values from the
current line in the Customers and Prospects scrolling window to window fields in
the Customer Contacts window.
{Name: IG_Get_Scrollwin_Information}
{If the Contact History window is open, try to update it.}
if isopen(form IG_Contact_History) then
{Update the window only if there aren't pending changes.}
if not changed(form IG_Contact_History) then
'Customer Number' of window 'Contact History' of form
IG_Contact_History = 'Customer Number' of window
➥ Customer_Lookup_Scroll of form Customer_Lookup;

'Customer Name' of window 'Contact History' of form


➥ IG_Contact_History = 'Customer Name' of window
➥ Customer_Lookup_Scroll of form Customer_Lookup;

'Contact Person' of window 'Contact History' of form


➥ IG_Contact_History = "";

run script 'Customer Number' of window 'Contact History' of


➥ form IG_Contact_History;
end if;
end if;

INTEGRATION GUIDE 91
PA RT 3 O B J EC T TR I G G E R S

Field focus triggers


Most fields have three focus events with which you can use a focus trigger.
However, button fields activate triggers for the change focus event only. The
following table explains each field focus event, and the corresponding value of the
focus_type parameter required in the Trigger_RegisterFocus() function:

Focus event Description Value of focus_type


pre Occurs when the focus moves to the field. TRIGGER_FOCUS_PRE
change Occurs when the content of the field TRIGGER_FOCUS_CHANGE
changes. If the field is a button, the focus
event occurs when the button is clicked.
post Occurs when the focus moves from the field. TRIGGER_FOCUS_POST
context menu Occurs when the context menu for the field TRIGGER_FOCUS_CONTEXT_MENU
is displayed

Example 8: Field focus trigger


This trigger is activated when the user clicks the Save button in the Customer
Maintenance window.
{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous('Save Button' of window


➥ RM_Customer_Maintenance of form RM_Customer_Maintenance),
➥ TRIGGER_FOCUS_CHANGE, TRIGGER_BEFORE_ORIGINAL, script
➥ IG_Check_Contact_Date);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;
This trigger processing procedure displays a warning dialog if the user hasn’t
contacted the customer in the prior month.
{Name: IG_Check_Contact_Date}
local integer l_days;

if isopen(window RM_Customer_Maintenance of form


➥ RM_Customer_Maintenance) then
{Retrieve a contacts record and check the last contact date.}
'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number' of
➥ window RM_Customer_Maintenance of form RM_Customer_Maintenance;
release table IG_Contact_History_MSTR;
change table IG_Contact_History_MSTR by IG_Contact_History_MSTR_Key1;
if err()=OKAY then
if not empty('Last Contact Date' of table IG_Contact_History_MSTR)
➥ then
if 'Last Contact Date' of table IG_Contact_History_MSTR
➥ <= (sysdate()-30) then
l_days = abs(integer(date('First Contact Date' of
➥ table IG_Contact_History_MSTR) - sysdate()));
warning "It's been " + str(l_days) + " days since you
➥ contacted this customer.";
end if;
end if;
end if;
end if;

92 IN T E G R AT I O N G U ID E
C H A P T E R 9 F O C U S T R I G G E R S

Menu focus triggers


You can create triggers for items in form-based menus. The menu items, not menus
themselves, respond to a change focus event only. The value of the focus_type
parameter indicates which menu item activates the trigger. For instance, if you set
focus_type to 2, the second menu item in the menu activates the trigger.

Microsoft Dynamics GP uses command-based menus. You can’t use menu triggers with
command-based menus. For Microsoft Dynamics GP, you can only use menu triggers for
form-based menus.

Example 9: Menu focus trigger


This trigger is activated when the user chooses Quick Print from the Options menu
available when the Sales Transaction Entry window is displayed. The Options menu
is part of the SOP_Entry form, and the Quick Print menu item appears as the sixth
item in the submenu.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous(menu 'Options' of form


➥ 'SOP_Entry'), 6, TRIGGER_AFTER_ORIGINAL, script IG_TrackQuickPrint);

Command focus triggers


You can create triggers for commands that have the type Script. You cannot register
triggers for built-in commands or those with outher command types. The following
table explains each command focus event, and the corresponding value of the
focus_type parameter required in the Trigger_RegisterFocus() function:

Focus event Description Value of focus_type


change Occurs whenever the command is TRIGGER_FOCUS_CHANGE
executed

Example 10: Command focus trigger


This trigger is activated before the command Backup Company is executed.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFocus(anonymous(command 'Backup Company’ of form


➥ Command_System), TRIGGER_FOCUS_CHANGE, TRIGGER_AFTER_ORIGINAL, script
➥ IG_Backup);
if l_result <> SY_NOERR then
warning "Trigger registration failed.";
end if;

Table buffers for focus triggers


When the trigger processing procedure for a focus trigger accesses a table buffer, the
table buffer is automatically attached to the form that’s active when the trigger is
activated. The table buffer remains active as long as the form remains open. The
next time any focus triggers for the form are activated, they can access the contents
of the table buffer. It will be in the state it was left by the last trigger processing
procedure that accessed it.

INTEGRATION GUIDE 93
PA RT 3 O B J EC T TR I G G E R S

Be aware that other integrating applications can instantiate table buffers as well.
There is a possibility of multiple developers trying to use the same table buffer,
especially when trigger processing procedures reference a Microsoft Dynamics GP
table. Thus, it’s a good idea to “clean up” any table buffers your trigger processing
procedures access, and not to expect a table buffer to be in a known state when a
trigger processing procedure accesses it.

94 IN T E G R AT I O N G U ID E
Chapter 10: Database Triggers
Database triggers are activated by successful table operations, such as saving a
record, deleting a record or reading a record. Database triggers are the most reliable
way of ensuring relational integrity between a third-party record and a related
Microsoft Dynamics GP record, since a database trigger is activated only if the
database operation was successful. The following table lists each type of database
trigger:

Trigger type Description


Add Activated when Microsoft Dynamics GP successfully adds a new record.
Update Activated when Microsoft Dynamics GP successfully updates an existing
record.
Delete Activated when Microsoft Dynamics GP successfully deletes an existing
record.
Read Activated when Microsoft Dynamics GP successfully reads an existing
record without locking it.
Read lock Activated when Microsoft Dynamics GP successfully reads an existing
record and either passively or actively locks it.

See Chapter 2, For example, using a single trigger activated by the add operation, the sample
“Sample Integration,” integrating application automatically creates a new third-party contact history
for information about record when a new customer record is created in the accounting system. Likewise,
installing the sample using a single delete trigger, the sample application automatically deletes a third-
integrating application. party customer contacts record when the corresponding customer record is deleted.
Information about database triggers is divided into the following sections:

• Registering database triggers


• Working with table buffers
• Restricting table operations
• Add database triggers
• Update database triggers
• Delete database triggers
• Read database triggers

Registering database triggers


Before you use database triggers, you must register each trigger for use with the
runtime engine. The Trigger_RegisterDatabase() function handles the registration
process for database triggers, typically within a startup procedure. Refer to the
Trigger function library in the Function Library Reference manual for a complete
description of this function.

Example 1: Registering a database trigger


This example registers a database trigger that is activated when a customer record is
deleted from the RM_Customer_MSTR table.
{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterDatabase(anonymous(table
➥ RM_Customer_MSTR), form RM_Customer_Maintenance,
➥ TRIGGER_ON_DB_DELETE, script IG_Delete_Contact_History;
if l_result <> SY_NOERR then
warning "Database trigger registration failed.";
end if;

INTEGRATION GUIDE 95
PA RT 3 O B J EC T TR I G G E R S

Working with table buffers


On a successful table operation, a database trigger is activated and passes the
contents of the table buffer for which the table operation occurred to the trigger
processing procedure as an inout parameter. This buffer is always available to the
trigger processing procedure, regardless of the table operation successfully
completed.

For example, if a successful delete occurs for the RM_Customer_MSTR table, a


delete trigger runs and passes the table buffer for the deleted record to the following
processing procedure as an inout parameter. This trigger processing procedure then
sets a key value for the corresponding third-party record and deletes it.
{Name: IG_Delete_Contact_History}
inout table RM_Customer_MSTR;

'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number'


➥ of table RM_Customer_MSTR;
release table IG_Contact_History_MSTR;
change table IG_Contact_History_MSTR by number 1;
if err() = OKAY then
remove table IG_Contact_History_MSTR;
if isopen(form IG_Contact_History) then
clear form IG_Contact_History;
end if;
end if;

Retrieving the table operation


You can include a second optional integer in parameter in the trigger processing
procedure. If this parameter is included, a value is automatically passed in
indicating the table operation that activated the trigger. The value corresponds to
the constants listed for the table_operations parameter for the
Trigger_RegisterDatabase() function. If you specify several table operations for a
trigger, this is useful in conditionally checking which table operation activated the
trigger.

Using ranges
Successful table operations that occur for a range of records will activate a database
trigger for each record in the range. The range operation passes each record’s buffer
to the processing procedure.

Restricting table operations


You can restrict a table operation by form using the form form_name parameter of
the Trigger_RegisterDatabase() function. A form restriction ensures that a database
trigger is activated only if the table operation originates from the specified form.
This is useful when you want to complete table operations in your application
based on actions the user takes in a Microsoft Dynamics GP form, such as browsing,
saving or deleting records. Without a form restriction, a table operation anywhere in
the system will activate a corresponding database trigger.

A restriction prohibits the trigger from activating when a database operation occurs from
other locations in the system. Therefore, you should not use a restriction if you use database
triggers to enforce referential integrity constraints between Microsoft Dynamics GP records
and third-party records.

96 IN T E G R AT I O N G U ID E
C H A P T E R 1 0 D AT A B AS E T R I G G E R S

A database trigger with a form restriction runs only if the table operation uses the
form’s record buffer. For instance, if the form’s Save button calls a procedure which
then saves a record to a table, the database trigger won’t run (you’re using the
procedure’s record buffer, not the form’s). However, if the Save button passes the
form’s record buffer to the procedure, the database trigger runs because you’re still
using the form’s record buffer.

Microsoft Dynamics GP forms typically don’t delete or save records using a procedure. They
use either a field change script or a form procedure, where a script passes the record buffer to
the form procedure.

Add database triggers


A database trigger responds to a new record created in Microsoft Dynamics GP if
you specify TRIGGER_ON_DB_ADD in the table_operations parameter of the
Trigger_RegisterDatabase() function. If successful, the database operation passes
the added record’s buffer to your trigger processing procedure as an inout
parameter.

Example 2: Adding records


This trigger creates a new third-party contact history record whenever the user adds
a new customer record to the RM_Customer_MSTR table.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterDatabase(anonymous(table RM_Customer_MSTR), form


➥ RM_Customer_Maintenance, TRIGGER_ON_DB_ADD, script
➥ IG_Create_Contact_History);
if l_result <> SY_NOERR then
warning "Database trigger registration failed.";
end if;

This trigger processing procedure sets key values and default values, then saves a
new contact history record corresponding to the new customer record.

{Name: IG_Create_Contact_History}
inout table RM_Customer_MSTR;

if not isopen(form IG_Contact_History) then


'Customer Number' of table IG_Contact_History_MSTR =
➥ 'Customer Number' of table RM_Customer_MSTR;
'Customer Name' of table IG_Contact_History_MSTR =
➥ 'Customer Name' of table RM_Customer_MSTR;
First_Contact_Date of table IG_Contact_History_MSTR = sysdate();
Contact_Salesperson_ID of table IG_Contact_History_MSTR =
➥ 'Salesperson ID' of table RM_Customer_MSTR;
save table IG_Contact_History_MSTR;
end if;

INTEGRATION GUIDE 97
PA RT 3 O B J EC T TR I G G E R S

Update database triggers


A database trigger responds to an existing record that’s updated if you specify
TRIGGER_ON_DB_UPDATE in the table_operations parameter of the
Trigger_RegisterDatabase() function. If successful, the database operation passes
the updated record’s buffer to your processing procedure as an inout parameter.

Example 3: Updating records


This database trigger updates a contact history record when the user saves an
existing customer record in the RM_Customer_MSTR table.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterDatabase(anonymous(table
➥ RM_Customer_MSTR),form RM_Customer_Maintenance,
➥ TRIGGER_ON_DB_UPDATE, script IG_Save_Contact_History);
if l_result <> SY_NOERR then
warning "Database trigger registration failed.";
end if;

This trigger processing procedure saves the third-party contact history record with
any new information the user may have added to the corresponding customer
record.

{Name: IG_Save_Contact_History}
inout table RM_Customer_MSTR;

'Customer Number' of table IG_Contact_History_MSTR =


➥ 'Customer Number' of table RM_Customer_MSTR;
change table IG_Contact_History_MSTR by number 1;
if err() = OKAY then
'Customer Name' of table IG_Contact_History_MSTR = 'Customer Name'
➥ of table RM_Customer_MSTR;
save table IG_Contact_History_MSTR;
end if;

Delete database triggers


A database trigger responds to a successful record delete if you specify
TRIGGER_ON_DB_DELETE in the table_operations parameter of the
Trigger_RegisterDatabase() function. If successful, the database operation passes
the removed record’s buffer to your processing procedure as an inout parameter.

There are two ways in which you can use delete database triggers; responding to a
record deleted from a Microsoft Dynamics GP form, and responding to a record
deleted from a Microsoft Dynamics GP procedure.

Records deleted from a form


Refer to the Verifying Database triggers are useful for deleting a corresponding third-party record in
table operations response to a delete operation completed using a Microsoft Dynamics GP form
section of Chapter 9, (when the user clicks the Delete button). Prior to deleting the third-party record, use
“Focus Triggers,” for a focus trigger to verify that the table operation can occur for your record as well.
more information
about verifying table
delete operations.

98 IN T E G R AT I O N G U ID E
C H A P T E R 1 0 D AT A B AS E T R I G G E R S

Example 4: Deleting records from a form


This database trigger is activated by a successful delete of a customer record from
the RM_Customer_Maintenance form. In this case, it runs only when the user clicks
the Delete button in the RM_Customer_Maintenance form. A focus trigger (not
shown here) on the Delete button first checks to be sure the it can read the
corresponding third-party record before it deletes the record. If the trigger can’t
read the record, it issues a reject script statement and all processing stops. If it can
read the record, the Microsoft Dynamics GP delete occurs, and this delete trigger is
activated.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterDatabase(anonymous(table
➥ RM_Customer_MSTR), form RM_Customer_Maintenance,
➥ TRIGGER_ON_DB_DELETE, script IG_Delete_Contact_History);
if l_result <> SY_NOERR then
warning "Database trigger registration failed.";
end if;

This trigger processing procedure deletes the third-party contact history record that
corresponds to the deleted RM_Customer_MSTR record.

{Name: IG_Delete_Contact_History}
inout table RM_Customer_MSTR;

'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number'


➥ of table RM_Customer_MSTR;
release table IG_Contact_History_MSTR;
change table IG_Contact_History_MSTR by number 1;
if err() = OKAY then
remove table IG_Contact_History_MSTR;
if isopen(form IG_Contact_History) then
clear form IG_Contact_History;
unlock 'Customer Number' of window IG_Contact_History
➥ of form IG_Contact_History;
end if;
end if;

Records deleted from a procedure


Database triggers are also useful for responding to a delete operation completed by
a Microsoft Dynamics GP procedure. The difficulty here is that you cannot verify
the delete operation for a related third-party record using a focus trigger. A
Microsoft Dynamics GP record deleted by a procedure will simply run the delete
trigger on the third-party table.

To handle this situation, delete a related third-party record conditionally within the
processing procedure that responds to the database delete trigger. This will also
work in cases where a Microsoft Dynamics GP procedure removes a range of
records. The trigger then runs for each successful record delete in the range.

INTEGRATION GUIDE 99
PA RT 3 O B J EC T TR I G G E R S

Example 5: Deleting records from a procedure


This trigger processing procedure responds to a record deleted in the
RM_Customer_MSTR table by a Microsoft Dynamics GP procedure. It sets key
values, then attempts to delete the third-party record. If the delete operation isn’t
successful (because another user has locked the record) the trigger writes the record
to a log file.

{Name: IG_Delete_Contact_History}
inout table RM_Customer_MSTR;

'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number'


➥ of table RM_Customer_MSTR;
change table IG_Contact_History_MSTR by number 1;
remove table IG_Contact_History_MSTR;
if err() = LOCKED then
{Write the records to a log file.}
'Customer Number' of table IG_Contact_Error_Log =
➥ 'Customer Number' of IG_Contact_History_MSTR;
'Customer Name' of table IG_Contact_Error_Log =
➥ 'Customer Name' of IG_Contact_History_MSTR;
save table IG_Contact_Error_Log;
end if;

Read database triggers


A read database trigger responds to a record that’s successfully read. A record read
database trigger runs in response to the following table operations:

Value of table_operation Description


TRIGGER_ON_DB_READ Responds to a record that’s successfully read but not locked.
TRIGGER_ON_DB_READ_LOCK Responds to a record that’s successfully read and passively or
actively locked.

You can specify either of these table operations in the table_operations parameter of
the Trigger_RegisterDatabase() function. If successful, the record’s buffer is passed
to your processing procedure as an inout parameter.

Example 6: Record read database trigger


This database trigger runs when the user displays a new record in the
Customer_Maintenance window, using either a lookup or browse buttons. The
IG_Update_Contact_History procedure runs in response to this trigger.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterDatabase(anonymous(table
➥ RM_Customer_MSTR), form RM_Customer_Maintenance,
➥ TRIGGER_ON_DB_READ_LOCK, script IG_Update_Contact_History);
if l_result <> SY_NOERR then
warning "Database trigger registration failed.";
end if;

100 IN T E G R AT I O N G U ID E
C H A P T E R 1 0 D AT A B AS E T R I G G E R S

This processing procedure updates the Contact History window with the same key
value as the one displayed in the RM_Customer_Maintenance form. It then
attempts to retrieve an existing record using the script for the Customer Number
field.

{Name: IG_Update_Contact_History}
inout table RM_Customer_MSTR;

if isopen(form IG_Contact_History) then


clear form IG_Contact_History;
'Customer Number' of window IG_Contact_History of form
➥ IG_Contact_History = 'Customer Number' of table
➥ RM_Customer_MSTR;
'Customer Name' of window IG_Contact_History of form
➥ IG_Contact_History = 'Customer Name' of table RM_Customer_MSTR;
run script 'Customer Number' of window IG_Contact_History
➥ of form IG_Contact_History;
end if;

INTEGRATION GUIDE 101


102 IN T E G R AT I O N G U ID E
Chapter 11: Procedure Triggers
Procedure triggers are activated when a specific procedure is run using the call
statement. The trigger processing procedure that runs in response to the call can run
before or after the original procedure runs, and it has access to the same parameters
as the original procedure.

Procedure triggers are especially useful if you want to react to certain processes in
Microsoft Dynamics GP, such as posting, by completing additional processes.
Information about procedure triggers is divided into the following sections:

• Registering procedure triggers


• Working with parameters
• Disabling procedure triggers

Registering procedure triggers


Before you use procedure triggers, you must first register them for use with the
runtime engine. The Trigger_RegisterProcedure() function handles the registration
process for a procedure trigger. Refer to the Trigger function library in the Function
Library Reference manual for a complete description of this function.

Example 1: Registering a procedure trigger


This example registers a procedure trigger that runs when the
RM_Delete_Sales_Document procedure is called. When Microsoft Dynamics GP
deletes a sales document using this procedure, the trigger processing procedure
named IG_Log_Record_Deletes adds a record to an activity tracking table.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterProcedure(script RM_Delete_Sales_Document,


➥ TRIGGER_AFTER_ORIGINAL, script IG_Log_Record_Deletes);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed";
end if;

Working with parameters


There are two ways in which your trigger processing procedure can use parameters
for the original procedure:

• It can use no parameters, thereby ignoring values from the original procedure.
This is the recommended method of using a procedure trigger.

• It can use the same parameters as the original procedure. However, the
parameters in the trigger processing procedure must match the parameter list of
the original procedure script.

INTEGRATION GUIDE 103


PA RT 3 O B J EC T TR I G G E R S

Ignoring parameters
If you choose to When using procedure triggers, we strongly recommend that you do not alter
reference a procedure’s parameters passed from the original script. Using this method, a third-party
parameters, see Using developer’s procedure trigger simply runs when the specified Microsoft Dynamics
original parameters on GP procedure is called. The values of a Microsoft Dynamics GP procedure’s
page 105, for more parameters are difficult to determine unless you can accurately predict where and
information. how the procedure will be called. Furthermore, changing parameter values in a
Microsoft Dynamics GP procedure is also more likely to unexpectedly alter the
results of other procedures called in a Microsoft Dynamics GP process.

Example 2: Ignoring parameters


This example runs when a user attempts to log into the accounting system. It checks
whether the user registered the Contact History application, and if not, displays a
message.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterProcedure(script System_Login,


➥ TRIGGER_AFTER_ORIGINAL, script IG_Check_Login);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed";
end if;

This trigger processing procedure runs when the System_Login procedure is called.
This procedure runs when the user initially logs into Microsoft Dynamics GP.

{Name: IG_Check_Login}

get first table IG_Setup by number 1;


if 'Company ID' of globals = -1 and not Registered of table
➥ IG_Setup then
{The user is logging into the sample company., but hasn't
registered the application yet.}
warning "The Customer Contacts application is enabled for
➥ the sample company only. Be sure to register sample for all
➥ other companies.";
elseif 'Company ID' of globals <> -1 and not Registered of
➥ table IG_Setup then
{The user is logging into a company other than the sample,
and hasn't registered the application yet.}
warning "The sample application won't be enabled for
➥ this company until you register it using the Sample Setup
➥ window.";
end if;

104 IN T E G R AT I O N G U ID E
C H A P T E R 1 1 PR O C E D U R E TR I G G E R S

Using original parameters


Refer to the SDK for If you choose to use the parameter values from the original procedure, the trigger
more information processing procedure must match exactly the type (in, out or inout), order and data
about each procedure’s type of the parameters in the original procedure. If the parameter list doesn’t match,
parameters. the registration for the processing procedure will fail.

Original procedure Trigger processing


procedure

in string name; in string name;


in integer index; in integer index;
out string ID; out string ID;

We recommend that you avoid changing parameter values in Microsoft Dynamics GP


procedures. The values of a procedure’s parameters are difficult to determine unless you can
accurately predict where and how the Microsoft Dynamics GP procedures will be called.

There are additional considerations you should take into account when working
with parameters from an original procedure, depending on whether it’s called in
the background or the foreground. Note that the differences are based on how the
procedure was called (using either the call or call background statements), not how
it’s actually running.

Scenario 1 – Background keyword not included


In this scenario, a script calls the Microsoft Dynamics GP procedure for which
triggers have been registered. The call does not include the background keyword.
The following illustration shows how the original procedure and the trigger
processing procedures run.

A script calls the original procedure


for which triggers have been
registered. A set of parameters is call OrigProc, parameters
passed to the procedure.
The procedure triggers and runs in
the following manner:
The pre trigger processing
call PreTriggerProc, parameters
procedure runs first.

Next, the original procedure runs. The


parameters from the pre trigger processing
procedure are passed to the original call OrigProc, parameters
procedure. Any changes the pre trigger
processing procedure made to the parameters
will be seen in the original procedure.

Then, the post trigger processing procedure


runs. The parameters from the original
procedure are passed to the post trigger
processing procedure. Any additional changes
call PostTriggerProc, parameters
the original procedure made to the parameters
will be seen in the post trigger processing
procedure.
Finally, the resulting parameter set is
returned to the original calling script.

INTEGRATION GUIDE 105


PA RT 3 O B J EC T TR I G G E R S

Scenario 2 – Background keyword included


In this scenario, a script calls the Microsoft Dynamics GP procedure for which
triggers have been registered. The call includes the background keyword. A set of
parameters is passed to the procedure. The following illustration shows how the
original procedure and trigger processing procedures run.

A script calls the original procedure for


which triggers have been registered.
call background OrigProc, parameters
The call includes the background
keyword. A set of parameters is passed
to the procedure.
The procedure triggers and runs in the
following manner:

The pre trigger processing procedure


runs first. It gets its own copy of the call background PreTriggerProc, parameters_copy
roiginal set of parameters.

Next, the original procedure runs. It


also gets its own copy of the original call background OrigProc, parameters_copy
set of parameters.

Then, the post trigger processing


procedure runs. Like the other scripts,
call background PostTriggerProc, parameters_copy
it gets its own copy of the original set
of parameters.

Example 3: Using parameters


This example logs master posting activity to an activity table. The trigger processing
procedure responds to the SY_Master_Post procedure, which posts all batches of a
given batch source.

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterProcedure(script SY_Master_Post,


➥ TRIGGER_AFTER_ORIGINAL, script IG_Log_Posting_Activity);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed";
end if;

This trigger processing procedure uses the same parameters as the SY_Master_Post
procedure. It uses the in parameters to set values in a log table used for tracking
posting activity.

{Name: IG_Log_Posting_Activity}
in string batch_source;
in integer source_window;
in 'Print Report Flag Array' l_report;
in 'Print To Printer Array' l_printer;
in 'Print To Screen Array' l_screen;
in 'Export File Type Array' export_file_type;
in 'File Export Name Array' export_file_name;

set 'Batch Source' of table IG_Posting_Activity to batch_source;


set 'Posting Time' of table IG_Posting_Activity to systime();

106 IN T E G R AT I O N G U ID E
C H A P T E R 1 1 PR O C E D U R E TR I G G E R S

set 'Posting Date' of table IG_Posting_Activity to sysdate();


if source_window = 4 then
{The posting occurred from the Master Posting window.}
set 'IG Source Window' of table IG_Posting_Activity to "Master Posting";
else
{The posting occurred from the Series Post window.}
set 'IG Source Window' of table IG_Posting_Activity to "Series Posting";
end if;
save table IG_Posting_Activity;

Disabling procedure triggers


If you disable procedure triggers and a Microsoft Dynamics GP procedure is in the
background queue, all triggers for that procedure will still run, since the triggers are
also in the queue. However, if the Microsoft Dynamics GP background script calls
another procedure, triggers on that procedure won’t run because you disabled them
before they were added to the background queue.

INTEGRATION GUIDE 107


108 IN T E G R AT I O N G U ID E
Chapter 12: Function Triggers
Function triggers are activated when a specific function is called. You can write a
trigger processing procedure or function that runs in response to the original
function. You can also set up the trigger to be activated either before or after the
original function. Information about function triggers is divided into the following
sections:

• Registering function triggers


• Working with parameters

Registering function triggers


Before you use function triggers, you must register each trigger for use with the
runtime engine. The Trigger_RegisterFunction() function handles the registration
process for function triggers, typically within a startup procedure. Refer to the
Trigger function library in the Function Library Reference manual for a complete
description of this function.

Example 1: Registering a function trigger


This example registers a trigger that runs a third-party procedure named
IG_Check_Save in response to the Microsoft Dynamics GP form-level function
named SaveRecord:

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFunction(function SaveRecord of form


➥ CM_Checkbook_Maintenance, TRIGGER_AFTER_ORIGINAL, script IG_Check_Save);

Example 2: Registering a function trigger


This example registers a trigger that runs a third-party function named
IG_Verify_Checkbook in response to the Microsoft Dynamics GP form-level
function named SaveRecord:

{Name: Startup}
local integer l_result;

l_result = Trigger_RegisterFunction(function SaveRecord of form


➥ CM_Checkbook_Maintenance, TRIGGER_AFTER_ORIGINAL, function
➥ IG_Verify_Checkbook);

INTEGRATION GUIDE 109


PA RT 3 O B J EC T TR I G G E R S

Working with parameters


A procedure that runs in response to a function trigger can’t have any parameters.
The procedure does not have access to the parameters for the original function. A
function that runs in response to a function trigger must have the same set of
parameters as the original Microsoft Dynamics GP function. As a result, the
function has access to the original function’s parameters. The following illustration
shows how function parameters and return values are used for function triggers.

A script calls the original function for


which triggers have been registered.
set result to OrigFunction(parameters)
The function triggers and function
run in the following manner:

The pre trigger processing


return_value PreTriggerFunction(parameters)
function runs.
Next, the original function runs. The
parameters from the pre trigger
function are passed to the original
function. Any changes the pre trigger return_value OrigFunction(parameters)
function made to the parameters will
be seen in the original function.

Then, the post trigger processing


function runs and the parameters
from the original function are passed
return_value PostTriggerFunction(parameters)
to it. Any changes the original
function made to the parameters will
be seen by the post trigger function.

Finally, the resulting parameter set


and return value are returned to the
original calling script. If the post
trigger function doesn’t set the return
value, the original function’s return
value will be returned.

110 IN T E G R AT I O N G U ID E
C H A PT E R 1 2 F U N C T I O N TR I G G E R S

Example 3: Using a trigger processing function


The following trigger processing function runs in response to the form-level function
named SaveRecord (registered in example 2). Since this is a function rather than a
procedure, it must have the same parameters as the original function. It also has
access to those parameters.

The SaveRecord function includes two parameters: a boolean parameter named


Status that specifies whether the checkbook record saved, and an inout parameter
for the current checkbook record. The following trigger processing function uses
these same parameters, and has access to the values of both.

It first checks the Status parameter to ascertain whether the function successfully
saved the checkbook record. It then checks the Maximum Check Dollar in the
current record; if it’s greater than $10,000, it displays a warning, then opens a third-
party form for setting security access to the checkbook:

{Name: IG_Verify_Checkbook}
function returns boolean Status;

inout table CM_Checkbook_MSTR;

if Status = true then


{The table save occurred.}
if 'Maximum Check Dollar' of table CM_Checkbook_MSTR > 10000 then
warning "Please set up checkbook passwords for this checkbook.";
open form IG_Checkbook_Security;
end if;
end if;

INTEGRATION GUIDE 111


112 IN T E G R AT I O N G U ID E
Chapter 13: Cross-dictionary triggers
Cross-dictionary triggers allow you to respond to events in any Dexterity-based
product, not just the main product. They work much like standard triggers, but use
different functions when being registered. There are also special techniques
required in the trigger processing procedures for cross-dictionary triggers.
Information about cross-dictionary triggers is divided into the following sections:

• Registering cross-dictionary triggers


• Responding to cross-dictionary triggers
• Helper functions
• Cross-dictionary database triggers

Registering cross-dictionary triggers


Dexterity has several functions that allow registering cross-dictionary triggers.
These functions are very similar to the functions used for registering standard
triggers. The primary difference is that you must refer by name to the resources for
which cross-dictionary triggers will be registered. No compile time checking is
performed, so it’s important that you type the names accurately to prevent runtime
errors when registering triggers. The following functions are used to register cross-
dictionary triggers:

• Trigger_RegisterDatabaseByName()
• Trigger_RegisterFocusByName()
• Trigger_RegisterFormByName()
• Trigger_RegisterFunctionByName()
• Trigger_RegisterProcedureByName()

Refer to the Trigger function library in the Function Library Reference manual for a
complete description of the functions used to register cross-dictionary triggers.

Responding to cross-dictionary triggers


When a cross-dictionary trigger is activated, a trigger processing procedure in your
dictionary is run. Because the processing procedure is running in a different
dictionary, responding to a cross-dictionary trigger isn’t as easy as a standard
trigger. In your trigger processing procedure, you may have to use the execute()
function to execute sanScript code in the dictionary in which the trigger occurred.
You will use this “pass-through” sanScript code to get or set values in the dictionary
in which the trigger occurred.

Using the execute() function


To set and retrieve values with the execute() function, you must use its parameter
passing capability. For example, to retrieve the value of the FFirst Name field in the
dictionary whose product ID is 414, you could use the following sanScript code in
the trigger processing procedure.

local text code;


local string compile_message;
local integer error_count;
local string field_val;

INTEGRATION GUIDE 113


PA RT 3 O B J EC T TR I G G E R S

{Build the sanScript code to execute.}


code = "inout string ret_val.";
code = code + "if isopen(form HR_Applicant) then ";
code = code + "ret_val = 'FFirst Name' of window HR_Applicant_Tracking
➥ of form HR_Applicant.";
code = code + "end if.";

{Execute the code.}


error_count = execute(414, code, compile_message, ret_val);
if error_count <> 0 then
{Errors in the pass-through sanScript.}
error "Error in pass-through sanScript code.";
end if;

Helper functions
Rather than write all of this code every time you want to retrieve a value from a
window in another dictionary, consider writing a general-purpose routine. For
example, the following function retrieves the value from the specified window.

Function name: GetWindowValue

function returns integer status;

in integer prod_id;
in string form_name;
in string window_name;
in string field_name;
out anonymous field ret_val;
optional out integer storagetype;
optional out string compile_errors;

local text code;


local string compile_message;
local integer error_count;

{Build the sanScript code to execute.}


code = "inout anonymous ret_val.";
code = code + "if isopen(form " + form_name + ") then ";
code = code + "ret_val = " + field_name + " of window " + window_name
➥ + " of form " + form_name + ".";
code = code + "end if.";

{Execute the code.}


error_count = execute(prod_id, code, compile_message, ret_val);
if error_count = 0 then
{Success. Return the value.}
if missing(storagetype) = false then
storagetype = datatype(ret_val);
end if;
status = error_count;
else
{Errors in the pass-through sanScript.}
status = error_count;
if missing(compile_errors) = false then
compile_errors = compile_message;
end if;
end if;

114 IN T E G R AT I O N G U ID E
C H A PT E R 1 3 C R O S S - D I C T I O N A R Y T R I G G E R S

The following example uses the GetWindowValue() function to retrieve the value
of the Applicant Number field in the HR_Applicant_Tracking window of the
HR_Applicant form.

local string appl_number;


local integer result;
local integer datatype;

{Get the Applicant Number.}


result = GetWindowValue(414, "HR_Applicant", "HR_Applicant_Tracking",
➥ "'Applicant Number'", appl_number, datatype);

Cross-dictionary database triggers


When you respond to cross-dictionary database triggers, you will typically need to
retrieve values from the table for which the trigger occurred. Because this table isn’t
available when you write your trigger processing procedure, it must be passed into
the procedure as an anonymous table. You can then use the column() function to
retrieve specific field values from the table.

For example, the following script is the trigger processing procedure for the delete
trigger on the Applicants table. Notice that the table is passed to the trigger
processing procedure as an anonymous table. Also notice that the column()
function is used to retrieve the value of the Applicant Number field in the table.

inout anonymous table 'Triggered Table';

release table Appl_Internet_Info;


'Applicant Number' of table Appl_Internet_Info = column("Applicant Number")
➥ of table 'Triggered Table';
change table Appl_Internet_Info;
if err() = OKAY then
remove table Appl_Internet_Info;
end if;

INTEGRATION GUIDE 115


116 IN T E G R AT I O N G U ID E
PART 4: WINDOW ELEMENTS
Part 4: Window Elements
By using the window components described here, you can provide your
application’s windows with the same “look and feel” as windows in Microsoft
Dynamics GP. Each component is described in detail, and provides steps for
implementing the component in your application. If you’d like, you can refer to the
maintenance form available with the sample application (DEVELOP.DIC) for source
code examples you can use directly in your application.

The following illustration shows the sample maintenance form and some of the
different components described:

lookup button note button (record-level)

push buttons

password padlock
button

browse buttons

sort list note button


(form-level)

The following window elements are discussed:

• Chapter 14, “Browse Controls,” explains how to use and implement browse
controls and sort lists in your application.

• Chapter 15, “Push Buttons,” explains the types of push buttons used in a typical
window.

• Chapter 16, “Lookups,” explains how to implement lookup buttons in your


application. It also explains how to use show and hide controls for scrolling
windows.

• Chapter 17, “Expansions And Zooms,” explains how to use and implement
expansion and zoom controls in your application.

• Chapter 18, “Notes,” explains how to implement window- and record-level


notes in your application.

• Chapter 19, “Password Control,” explains how to implement record-level


passwords in your application.

• Chapter 20, “Data Entry Conventions,” explains how to use prompts, required
fields, a tab sequence and field groups to organize information in a window.

118 IN T E G R AT I O N G U ID E
Chapter 14: Browse Controls
Browse controls allow users to sequentially scan records in a window. These
controls accompany any window where a user can add, view, or change one of
several records at a given time. The following illustration shows a typical browse
control, as well as a sort list that usually accompanies such a control.

browse buttons sort list

Information about browse controls is divided into the following sections:

• Browse buttons
• Sort lists

Browse buttons
Browse buttons include four push button fields that allow the user to move to the
first record in the table, to the previous record, the next record or to the last record in
the table:

previous record
first record

last record
next record

Use browse buttons with almost any “parent,” or main window. Do not use browse
buttons with a true “child” window (a window only accessible from a parent
window), or with a window used to maintain a single record only (such as a setup
window).

Creating browse buttons


To add browse buttons to a window in your application, display the window’s
layout and perform the following steps:

1. Add browse buttons to the window status area.


Add the following four global fields, positioned from left to right in the order
listed, to the window’s status area (the lower-left corner of the window):

Global field Control


Top of File Button - Toolbar

Previous Button - Toolbar

Next Button - Toolbar

End of File Button - Toolbar

INTEGRATION GUIDE 119


PA RT 4 W I N D O W E L EM EN T S

2. Add a sort list.


If the table you’re browsing has multiple keys, add a sort list (a drop-down list).
The sample script shown in step 3 uses the field named ‘Sort By’ as the sort list.
This list specifies the key by which the user can browse records. Refer to Sort
lists on page 121 for more information.

3. Attach scripts to each browse button.


Attach a change script similar to the following example to each control. Be sure
to substitute the change first clause of the change statement for the appropriate
browse button.

• For the top of file button, use change first


• For the previous button, substitute change prev
• For the next button, substitute change next
• For the end of file button, substitute change last

local integer l_answer;

if changed (window 'Lead Maintenance') then


l_answer = ask("Save the current record?", "Yes", "No", "Cancel");
if l_answer = ASKBUTTON1 then
{The user clicked Yes.}
if required(window 'Lead Maintenance') then
copy to table IG_Leads_MSTR;
save table IG_Leads_MSTR;
else
warning "Not all required fields have been entered.";
abort script;
end if;
elseif l_answer = ASKBUTTON2 then
{The user clicked No.}
release table IG_Leads_MSTR;
clear changes window 'Lead Maintenance';
else
{The user clicked Cancel.}
abort script;
end if;
end if;

release table IG_Leads_MSTR;


change first table IG_Leads_MSTR by number 'Sort By';
if err() = OKAY then
copy from table IG_Leads_MSTR;
clear changes form IG_Lead_Maintenance;
lock 'Lead ID' of window 'Lead Maintenance';
enable 'Delete Button';
else
beep WARNSOUND;
end if;

4. Set the value of the sort list field.


Add a window pre script to set the value of the sort list field prior to the
window opening. In the following example, the script sets the default position
of the sort list field to 1 (By Lead ID).

'Sort By' = 1;

120 IN T E G R AT I O N G U ID E
C H A P T E R 1 4 B R O W S E C O N T R O L S

Sort lists
For information about Typically, a sort list is included with browse buttons. The list specifies the key by
sort lists used in a which the user views records when using browse buttons. In the following
lookup window, refer illustration, the sort list includes items that correspond to the two keys for the Leads
to Chapter 16, Master table. The default selection in the sort list (By Lead ID) allows a user to
“Lookups.” browse the Leads Master table by the first key in the table:

The sort list specifies the


key used to browse the
records.

The items in the sort list should always correspond to the order and number of keys
in the table being browsed. If the table being browsed has a single key, don’t use a
sort list; display browsed records according to that key.

Creating a sort list


To add a sort list for a browse control in your application, display the window’s
layout and complete the following steps.

1. Add a sort list field.


Add the global field named ‘Sort By’ to the window. Position the sort list field in
the window’s status area, to the right of the browse controls. Set the following
properties for the field:

SavedOnRestart True
SetChangeFlag False
VisibleItems The maximum number of items to display in the list.
We recommend that you set the value to six.

2. Attach a script that adds list items.


Attach a form pre script similar to the following example. This script adds items
to the sort list, then sets the default item in the sort list.

If you intend to distribute your product internationally, you should fill a sort list with
message resources using the getmsg() function. You can translate message resources
using Dexterity Utilities, or your users can change them using the Modifier.

{Fill the sort list.}


add item "By Lead ID" to 'Sort By' of window 'Lead Maintenance';
add item "By Lead Name" to 'Sort By' of window 'Lead Maintenance';

{Set the default position of the sort list.}


'Sort By' of window 'Lead Maintenance' = 1;

INTEGRATION GUIDE 121


122 IN T E G R AT I O N G U ID E
Chapter 15: Push Buttons
Push buttons in the window’s control area determine the actions that apply to the
current window, and to the record that appears in it. Although there are several
push buttons used throughout Microsoft Dynamics GP, the information presented
here describes the most common. It is divided into the following sections:

• Adding push buttons


• Cancel button
• Clear button
• Delete button
• OK button
• Save button

Adding push buttons


Depending on the type of window you’re developing, it should have the following
push buttons:

Window type Buttons (in left-to-right order)


Maintenance Save, Clear, Delete
Transaction entry Save, Delete, Post (for transaction-level posting)
Modal dialog OK, Cancel
(editable)
Modal dialog (display- OK
only)
Inquiry OK, Clear
Preferences/Setup OK, Cancel

After the push button has been added to the window, you must set its properties for
proper display in the control area. Set the following Visual properties for the field:

Appearance 3D Highlight
BackColor System - Toolbar
Border True
Font System
FontColor System
Size-Height 24
Size-Width 72
Style Text on Right

The vertical separators that appear between the push buttons in the control area are
individual lines that you must add using the line tool. Each vertical line has the
following Visual properties:

Appearance 3D Border
LineColor System
LineSize 1
Position-Top 3
Size-Height 16
Size-Width 0

INTEGRATION GUIDE 123


PA RT 4 W I N D O W E L EM EN T S

Cancel button
Use a Cancel button only with windows that use an OK button. A cancel operation
should allow the user to close a window without being subjected to any “side
effects” of the window’s dismissal. Typically, this means that no warning dialogs
should appear asking whether the user wants to save changes, nor should any
requests appear that the user provide more information prior to the window
closing.

In addition, observe the following guidelines when adding a Cancel button:

• Don’t use a Cancel button with windows that display an editable scrolling
window. Dexterity saves changes made in an editable scrolling window to the
linked table automatically, and you cannot reverse, or roll back these changes
once a cancel operation occurs for the window.

• Set the Cancel button’s Hyperspace property to True. This prevents the change
script for the currently focused window field from running when the user clicks
the Cancel button.

Example 1: Cancel button change script


The following Cancel button script in the RM_Aging window simply closes the
RM_Aging form:

close form RM_Aging;

Clear button
Always use Clear buttons in combination with Save and Delete buttons. A clear
operation should clear the window and place the focus on the first field in the tab
sequence. It should never remove any information currently stored in a table, nor
should it close the window.

The Clear button should allow the user to clear changes made in the window
without any “side effects” of the clear operation. Typically, no warning dialogs
should appear asking whether the user wants to save changes, nor should any
requests appear requesting that the user provide more information prior to the
window clearing. Use an accelerator key of ALT+L to clear the contents of the widow
using the keyboard.

You shouldn’t use a Clear button with windows that display an editable scrolling
window. Dexterity automatically saves changes to the linked table, and you cannot
reverse, or roll back these changes once a clear operation occurs for the window.

Example 2: Clear button change script


The following example releases the current table and restarts the form:

release table IG_Leads_MSTR;


restart form;

124 IN T E G R AT I O N G U ID E
C H A P T E R 1 5 P U S H B U T T O N S

Delete button
Use a Delete button in combination with a Save and Clear button. A delete
operation should clear the window after the user deletes a record, but should not
close the window. The operation should clear the window, then place the focus on
the first field in the tab sequence.

Refer to Chapter 18, • Use the err() function to trap table operation errors that may occur during the
“Multiuser delete operation. This is extremely important in multiuser environments.
processing,” in Volume
2 of the Dexterity • Delete record notes you’ve assigned to a new, unsaved record using the
Programmer’s Guide Delete_Record_Note procedure available in Microsoft Dynamics GP.
for information about
handling multiuser • An access key of ALT+D should be used to delete a record using the keyboard.
processing issues.
• Enable the Delete button only when the user displays an existing record. Do not
enable the Delete button when the user creates a new record.

Example 3: Delete button change script


The following example displays an ask() message, allowing the user to cancel the
delete operation. If the user chooses to delete, the record is removed, along with its
corresponding note record using the Delete_Record_Note procedure:

if ask("Delete this lead record?", "Delete", "Cancel", "") = ASKBUTTON1 then


remove table IG_Leads_MSTR;
if err() = OKAY then
call Delete_Record_Note, 'Note Index';
restart form;
elseif err() = LOCKED then
warning "This lead record is already locked. Changes won't be saved.";
else
restart form;
end if;
end if;

OK button
Use an OK button on windows used solely for viewing information (such as an
inquiry window) or on setup or preferences windows, used in maintaining a single
record. For windows whose contents are display only, an OK button can appear by
itself.

For setup and preferences windows, use a Cancel button with an OK button. The
OK button should always save changes to a preferences file or a setup table. In
addition, always run the OK button change script when the user presses the ENTER
key. To do this, set the OK button’s Default property to True.

Example 4: OK button change script


The following example saves changes made to the User Preferences window. It
saves preferences for the current user to the SY_Users_MSTR table, and sets global
variables.

INTEGRATION GUIDE 125


PA RT 4 W I N D O W E L EM EN T S

{Save the record.}


copy to table SY_Users_MSTR;
save table SY_Users_MSTR;
clear changes window User_Preferences;
{Set global variables.}
'Print to Printer' of globals = 'Print to Printer';
'Print to Screen' of globals = 'Print to Screen';
'Distributed Processes' of globals = 'Distributed Processes';

close form SY_User_Preferences;

Save button
Always use a Save button with Clear and Delete buttons. The Save button should
save the displayed information to one or more tables, clear the window after it saves
the record, and should never close the window. When it completes the save
operation, the save operation should focus the cursor in the window’s key field.

• Always run the Save button’s change script when the user presses the ENTER
key. To do this, set the Save button’s Default property to true.

Refer to Chapter 18, • Use the err() function to trap table operation errors that may occur during the
“Multiuser save operation. This is extremely important in multiuser environments.
processing,” in Volume
2 of the Dexterity Example 5: Save button change script
Programmer’s Guide The following example checks whether required fields have been addressed by the
for information about user, and attempts to save the record. The err() function ascertains which error
handling multiuser occurred, so that the script can display the appropriate message and prompt the
processing issues. user to carry out a specific action.

if required (form IG_Lead_Maintenance) then


{All required fields have been entered.}
copy from window 'Lead Maintenance' to table IG_Leads_MSTR;
save table IG_Leads_MSTR;
{Find out whether the save was successful.}
if err()=OKAY then
restart form;
focus 'Lead ID' of window 'Lead Maintenance';
{Find out whether another user changed the record.}
elseif err()=RECORDCHANGED then
warning "This record was changed. It will be read again.";
release table IG_Leads_MSTR;
change table IG_Leads_MSTR;
copy from table IG_Leads_MSTR;
elseif err()=LOCKED then
{Find out whether another user locked the record.}
warning "This record is locked by another user.";
end if;
else
{Not all required fields have been entered.}
warning "Please enter all required fields before
➥ attempting to save this record.";
end if;

126 IN T E G R AT I O N G U ID E
Chapter 16: Lookups
Refer to Chapter 10, Lookups are a combination of a lookup button, a lookup field, and a lookup
“Scrolling Windows,” window that opens when the user clicks the lookup button. The following
in Volume 2 of the illustration shows a lookup control and a lookup window:
Dexterity
Programmer’s Guide
for more information
about scrolling
windows and lookups. lookup button

lookup window

Information about implementing lookups is divided into the following sections:

• Using existing lookups


• Lookup types
• Adding a lookup control
• Adding records on the fly
• Creating a lookup
• Scrolling window
• Sort by/View options
• Column headers
• Refresh button
• Show/Hide Detail button
• Find
• Select and Cancel buttons
• Open and New buttons
• Note

INTEGRATION GUIDE 127


PA RT 4 W I N D O W E L EM EN T S

Using existing lookups


You can use an existing Microsoft Dynamics GP lookup form in exactly the same
manner as you use lookup forms in your own application. Each lookup form
returns one or more values using the return statement. The third-party form then
retrieves this value using the return to clause of the open form statement.

open form Salesperson_Lookup return to 'Salesperson ID';

return 'Salesperson ID';

Keep in mind that many Microsoft Dynamics GP lookup forms require that you
complete some preprocessing prior to opening the lookup form.

Opening an existing lookup form


To use an existing lookup form in your application, complete the following steps.

1. Find out the lookup form’s table.


Find which table is used to fill the scrolling window in the lookup form you
want to use, and attach that table to your form. For instance, if you open the
Salesperson lookup form, attach the RM_Salesperson_MSTR table to your form.

2. Add a return field to your table and window.


Add the Microsoft Dynamics GP field that holds the value returned from the
lookup window to one of your application’s tables. This field should be a key
from the table you attached in step 1. For the RM_Salesperson_MSTR table, this
field is ‘Salesperson ID’. Open your window’s layout, then add this field to the
layout.

3. Add a lookup button.


Add the global field named ‘Lookup Buttons’ to the window and place it
directly to the right of the lookup field.

Global field Control


Lookup Buttons

This field is an array of push buttons. When you add this field to the layout,
Dexterity will assign it the next available array index.

128 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

4. Attach a lookup button script.


Attach a change script to the lookup button that’s similar to the following
example. This example opens the lookup form, and returns the selected
salesperson ID using the return to clause of the open form statement.

{Return the salesperson ID selected in the window.}


open form Salesperson_Lookup return to 'Salesperson ID';
'Salesperson ID' of window Salesperson_Lookup of form
➥ Salesperson_Lookup = 'Salesperson ID';
run script 'Redisplay Button' of window Salesperson_Lookup
➥ of form Salesperson_Lookup;

A typical Microsoft Dynamics GP lookup window uses an invisible field to hold


a key value passed from your window (if the user entered one), so set this field.
In the previous script example, this invisible field is ‘Salesperson ID’ in the
Salesperson Lookup window. Running the change script for the Redisplay
button in the lookup window then fills the scrolling window using that key
value with the fill window statement.

Using the from current clause in the fill window statement allows the lookup
form to properly focus on a record currently displayed in your form. For
instance, if a user entered a salesperson ID, then clicked the lookup button, the
lookup window would place the scrolling window focus on the record with that
salesperson ID.

5. Add an accelerator key.


To enable the accelerator key for the lookup button (CTRL+L), choose Link
Lookup from the Tools menu. Click the lookup button, drag the pointer to the
lookup field, and release the mouse button; a highlight will flash to indicate that
the link was successful.

Lookup types
Lookup controls include an editable field and a lookup push button. The following
illustration shows the salesperson lookup control. When the user clicks the lookup
button, the Salesperson lookup window will appear:

lookup field lookup button


(key field)

Most lookup fields are a key for a table, such as a salesperson ID, a customer ID or a
document number. The lookup button’s change script displays a lookup window
listing all the records associated with the lookup field. When the user selects a
record and the lookup window closes, the lookup window returns the value to the
lookup field.

INTEGRATION GUIDE 129


PA RT 4 W I N D O W E L EM EN T S

Two types of lookup controls are used in a primary window: primary lookups and
secondary lookups.

primary lookup

secondary lookup

Primary lookups
The primary lookup is the first lookup control on a window. This lookup control
should allow the user to view records entered and maintained in the current
window (such as master records entered in a maintenance window).

Once the user enters data


and moves the focus, lock
the lookup field.

You should never disable a primary lookup button, but you should lock the lookup
field. This includes times when the user adds a new, unsaved record or when the
user retrieves an existing record.

Secondary lookups
Secondary lookups display related records (such as checkbook, salesperson or class
IDs related to a customer record) and associate them with the record displayed in
the current window.

Use a zoom control with Always allow the user to


all secondary lookups. add a record on the fly
for a secondary lookup.

See the Adding records Secondary lookup controls work similarly to a primary lookup; however, secondary
on the fly on page 132 lookup fields should provide the ability to zoom to a maintenance form and display
for more information. the entire record, and should allow the user to add records on the fly.

130 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

Adding a lookup control


To add a lookup control to a window in your application, complete the following
steps:

1. Add the lookup button.


Add the global field named ‘Lookup Buttons’ to the window and place it
directly to the right of the lookup field.

Global field Control


Lookup Buttons

This field is an array of push buttons. When you add this field to the layout,
Dexterity assigns it the next available array index.

2. Attach a lookup button script.


Attach a change script to the lookup button similar to the following example. In
this example, the Lead Lookup form will appear when the user clicks the
lookup button. The return to clause of the open form statement retrieves the
value passed by the lookup form using the return statement.

open form IG_Lead_Lookup return to 'Lead ID';

{Set the invisible key fields in the lookup window.}


'Lead ID' of window 'Lead Lookup' of form IG_Lead_Lookup = 'Lead ID';
'Lead Name' of window 'Lead Lookup' of form IG_Lead_Lookup = 'Lead Name';
'Salesperson ID' of window 'Lead Lookup' of form IG_Lead_Lookup =
➥ 'Salesperson ID';
run script 'Redisplay Button' of window 'Lead Lookup' of form
➥ IG_Lead_Lookup;

The script sets invisible key fields on the lookup form, then runs the script for
the Redisplay button. This script uses the fill window statement with the from
current keyword to place the scrolling window focus on a record currently
displayed in the Lead Maintenance form.

In your development dictionary, you can also open an existing Microsoft Dynamics GP
lookup form, returning any valid return values to the lookup field. See Using existing
lookups on page 128 for more information.

3. Add an accelerator key.


To enable the accelerator key for the lookup button (CTRL+L) choose Link
Lookup from the Tools menu. Click the lookup button, drag the pointer to the
lookup field, and release the mouse button. A highlight will flash to indicate
that the link succeeded.

INTEGRATION GUIDE 131


PA RT 4 W I N D O W E L EM EN T S

Adding records on the fly


Secondary lookup fields allow users to create new, related records while entering
information for a primary record. This is called adding records “on the fly” and is
typically implemented for any field that also functions as a secondary lookup.

For example, when entering customer information in the Customer Maintenance


window, the user can specify a salesperson ID assigned to the customer. If there’s no
salesperson record associated with the salesperson ID entered, a message is
displayed asking whether the user wants to create the new salesperson record.

When a new value is


entered in a lookup field,
an alert message asks
whether the user wants to
add a new record.

If the user chooses to add the salesperson record, the Salesperson Maintenance
window is displayed, and the key field (Salesperson ID) is set to the new ID entered
in the Customer Maintenance window.

Example: Adding records on the fly


You can add records on the fly using a field change script similar to the following
example. In this example, when the user enters a new salesperson ID, the change
script for the ‘Salesperson ID’ field checks whether a record exists in the
RM_Salesperson_MSTR table with the same key value. If not, it displays a message
asking the user whether they want to add the new record.

if not empty('Salesperson ID') then


{An entry was made in the field, so find out whether a record
with this key value exists.}
'Salesperson ID' of table RM_Salesperson_MSTR = 'Salesperson ID';
get table RM_Salesperson_MSTR;
if err()<>OKAY then
{A record with this salesperson ID doesn't exist, so ask the user
whether they want to create a new one.}
if ask("Do you wish to add this salesperson record?", "Add",
➥ "Cancel","") = ASKBUTTON1 then
{Open the Salesperson window and set the key field.}
open form RM_Salesperson;
'Salesperson ID' of window RM_Salesperson of form
➥ RM_Salesperson = 'Salesperson ID' of window 'Lead Maintenance';
end if;
end if;
end if;

132 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

Creating a lookup
Lookup windows typically include a scrolling window, a find field, a view options/
sort by list, a show/hide detail button and a form-level note button. The following
illustration shows the Leads lookup window included in the sample integrating
application.

Find Open button


View options Show/Hide detail
Column headers Refresh

Scrolling window

Note button

Select Cancel
button button

The remaining sections describes the elements of a typical lookup window.

Scrolling window
A lookup window contains a scrolling window that displays the records that can be
selected with the lookup. Normally, the scrolling window displays one line of
information for each record in the table linked to the lookup.

The scrolling window


typically displays one line
for each record in the
table linked to the lookup.

If additional information needs to be displayed in the lookup, the scrolling window


can display additional detail, as shown in the following illustration.

The scrolling window can


also display additional
information for each
record.

The contents of the scrolling window is controlled by the Sort by/View options
button drop list. The mode of the scrolling window is controlled by the Show/Hide
detail button.

INTEGRATION GUIDE 133


PA RT 4 W I N D O W E L EM EN T S

Sort by/View options


The Sort by/View options button drop list allows the user to specify the order in
which records will be displayed in the lookup window. It also allows the contents of
the scrolling window to be refreshed and toggled between normal and detail
modes. A typical Sort by/View options menu is shown in the following illustration.

Items in the sort list


correspond to keys in the
linked table.

The contents of this button drop list is specified dynamically through sanScript
code. The items correspond to keys in the scrolling window’s linked table. When
the user selects an item in the sort list, the lookup window’s scrolling window is
filled using the selected key.

Adding a Sort by/View options list


To add a Sort by/View options button drop list to a lookup window, use the
following procedure.

1. Create the sort list/view options field.


Create a local field named ‘Sort By’ for your lookup form. This local field has
the following characteristics:

Field Name Sort By


Control Type Button Drop List
Static Type Text

Use the image named SortBy_DownArrow from the Dynamics.dic dictionary as


the Up, Down and Over Image for the button drop list field.

2. Add the Sort By field to the lookup window.


Set the following Object properties for the field:

SavedOnRestart True
SetChangeFlag False
TabStop False

Set the following Visual properties for the field:

Alignment Left
Appearance 3D Highlight
BackColor System - List Header1
Border True
FontColor System - List Header1 Text
Style Text on Right

134 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

3. Attach a change script.


Attach a change script to the Sort By field similar to the following example. This
script sets the Sort By field to indicate what key to use when displaying records
in the lookup window. It also handles refreshing the contents of the scrolling
window and toggling between normal and detail mode.

local boolean result;


local integer i;

{Which group of items was selected? If it's less than 4, a sorting item
was selected.}
if '(L) Sort By' < 4 then
{Set the Sort By button drop list.}
result = Field_SetCaption('(L) Sort By', "&View: All " +
➥ itemname('(L) Sort By', '(L) Sort By'));

{Set the caption for the 'Find'.}


'(L) Find Prompt' = "Find " + itemname('(L) Sort By', '(L) Sort By');

{Mark the appropriate item in the Sort By button drop list.}


for i = 1 to countitems('(L) Sort By') do
uncheck field '(L) Sort By', i;
end for;
check field '(L) Sort By', '(L) Sort By';

{Fill the scrolling window.}


fill window Lead_Lookup_Scroll by number '(L) Sort By';
else
{One of the display options was selected.}
if '(L) Sort By' = 5 then
{Redisplay}
'(L) Sort By' = old();
run script 'Redisplay Button';
elseif '(L) Sort By' = 7 then
{Show detail}
'(L) ShrinkExpandSwitch' = 2;
run script '(L) ShrinkExpandSwitch';
elseif '(L) Sort By' = 8 then
{Hide detail}
'(L) ShrinkExpandSwitch' = 1;
run script '(L) ShrinkExpandSwitch';
end if;
end if;

4. Attach a form pre script.


Attach a form pre script to the lookup form similar to the following example.
This script adds items to the Sort List, then runs the sort list’s change script,
automatically filling the lookup window’s scrolling window.

local boolean result;

add item "by Lead ID" to '(L) Sort By' of window 'Lead Lookup';
add item "by Lead Name" to '(L) Sort By' of window 'Lead Lookup';
add item "by Salesperson" to '(L) Sort By' of window 'Lead Lookup';
add item "-" to '(L) Sort By' of window 'Lead Lookup';
add item "Refresh" to '(L) Sort By' of window 'Lead Lookup';
add item "-" to '(L) Sort By' of window 'Lead Lookup';
add item "Show Detail" to '(L) Sort By' of window 'Lead Lookup';
add item "Hide Detail" to '(L) Sort By' of window 'Lead Lookup';

INTEGRATION GUIDE 135


PA RT 4 W I N D O W E L EM EN T S

set '(L) Sort By' of window 'Lead Lookup' to 'Sort By' of window
➥ 'Lead Maintenance' of form IG_Lead_Maintenance;
run script '(L) Sort By' of window 'Lead Lookup';

{Set the Shrink/Expand button.}


set '(L) ShrinkExpandSwitch' of window 'Lead Lookup' to 1;
redraw field '(L) ShrinkExpandSwitch' of window 'Lead Lookup';
result = Field_SetToolTip('(L) ShrinkExpandSwitch' of window
➥ 'Lead Lookup' ,"Show Details");

Column headers
The column headers indicate what information is displayed in the scrolling window
when it’s in normal mode. Typically, each header is a push button that the user can
click to indicate how the lookup should be sorted.

The column headers are


push buttons the user can
click to specify the sorting
order for the contents of
the loolup.

Adding column headers


To add column headers to a lookup window, use the following procedure.

1. Create the column header fields.


The column header fields are typically local fields for the lookup form. They
have the following characteristics:

Control Type Push Button


Static Type Text

Specify a text caption that is appropriate for each column of the lookup.

2. Add the column header fields to the lookup window.


Set the following Object properties for each field:

TabStop False

Set the following Visual properties for each field:

Alignment Left
Appearance 3D Highlight
BackColor System - List Header2
Border True
FontColor System - List Header2 Text
Style Text Only

136 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

3. Add divider lines for the header fields.


Using the line tool, add a vertical divider line between each header field. Also
add a vertical divider line at the beginning and end of the header row. Set the
following Visual properties for each divider line:

Appearance 2D Border
LineColor System

4. Attach a change script.


Attach a change script to each column header field, similar to the following
example. This script sets the Sort By field to indicate what key to use when
displaying records in the lookup window, then runs the change script for that
field.
'(L) Sort By' = 1;
run script '(L) Sort By';

Refresh button
The Refresh (Redisplay) button contains the code that actually fills the scrolling
window for the lookup. When the user clicks the Refresh button or chooses the
Refresh item in the Sort by/View options button drop list, the contents of the
scrolling window is refreshed based on the sort order specified and the contents of
the Find field.

The Refresh (Redisplay)


button actually fills the
scrolling window with records
from the linked table.

Adding a refresh button


To add a refresh button to a lookup window, use the following procedure.

1. Add key fields to the layout.


Add all key fields from the linked table to the layout for the lookup window
and set the following properties for each:

Visible False
Editable False

You’ll use these fields in the change script you attach to the refresh button.

2. Add the Redisplay button.


Drag the global field named ‘Redisplay Button’ onto the lookup window
layout. Set the following Object properties for the button:

TabStop False

Set the following Visual properties for the field:

Appearance 3D Highlight
BackColor Transparent
Border True
Style Graphic Only

INTEGRATION GUIDE 137


PA RT 4 W I N D O W E L EM EN T S

3. Attach a change script.


Attach a change script to the field, similar to the following example. This script
fills the scrolling window based on the sort order chosen, the contents of the
hidden key fields, and the contents of the Find field.

if '(L) Sort By' = 1 then


{The sort list is set to Lead ID.}
if empty('Search Text') and empty('Lead ID') then
fill window Lead_Lookup_Scroll by number '(L) Sort By';
elseif empty('Search Text') and (not empty('Lead ID')) then
'Lead ID' of table IG_Leads_MSTR = 'Lead ID';
fill window Lead_Lookup_Scroll from current by number
➥ '(L) Sort By';
else
'Lead ID' of table IG_Leads_MSTR = upper(substring(
➥ 'Search Text', 1, 15));
fill window Lead_Lookup_Scroll from current by number
➥ '(L) Sort By';
focus field 'Lead ID' of window Lead_Lookup_Scroll;
end if;
elseif '(L) Sort By' = 2 then
{The sort list is set to Lead Name.}
if empty('Search Text') and empty('Lead Name') then
fill window Lead_Lookup_Scroll by number '(L) Sort By';
elseif empty('Search Text') and (not empty('Lead Name')) then
'Lead Name' of table IG_Leads_MSTR = 'Lead Name';
fill window Lead_Lookup_Scroll from current by number
➥ '(L) Sort By';
else
'Lead Name' of table IG_Leads_MSTR = substring(
➥ 'Search Text', 1, 30);
fill window Lead_Lookup_Scroll from current by number
➥ '(L) Sort By';
focus field 'Lead Name' of window Lead_Lookup_Scroll;
end if;
elseif '(L) Sort By' = 3 then
{The sort list is set to Salesperson ID.}
if empty('Search Text') and empty('Salesperson ID') then
fill window Lead_Lookup_Scroll by number '(L) Sort By';
elseif empty('Search Text') and (not empty('Salesperson ID'))
➥ then
'Salesperson ID' of table IG_Leads_MSTR='Salesperson ID';
fill window Lead_Lookup_Scroll from current by number
➥ '(L) Sort By';
else
'Salesperson ID' of table IG_Leads_MSTR = substring(
➥ 'Search Text',1,30);
fill window Lead_Lookup_Scroll from current by number
➥ '(L) Sort By';
focus field 'Salesperson ID' of window Lead_Lookup_Scroll;
end if;
end if;

138 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

Show/Hide Detail button


The Show/Hide Detail button toggles the lookup’s scrolling window between
normal and expanded mode.

The Show/Hide Detail button


toggles the scrolling window
between normal and
expanded mode.

When the scrolling window is displaying details, the items shown in normal mode
are displayed in bold text. The additional items are shown in plain text. If they
require additional explanation, the additional items can have prompts. These
prompts are also displayed in plain text.

When displaying details,


the main items in the
scrolling window are
displayed in bold text.

Adding a Show/Hide Details button


To add a show/hide details button to a lookup window, use the following
procedure.

1. Create the show/hide details field.


Create a local field named ‘ShrinkExpandSwitch’ for your lookup form. This
local field has the following characteristics:

Field Name ShrinkExpandSwitch


Control Type Visual Switch
Static Type Picture

Use the images named SW_ShowSummary_PB_Up and


SW_ShowDetail_PB_Up from the Dynamics.dic dictionary as the two pictures
for the visual switch.

2. Add the show/hide details field.


Drag the local field onto the lookup window layout. Set the following Object
properties for the field:

TabStop False
Tooltip Show Details

Set the following Visual properties for the field:

Appearance 3D Highlight
BackColor Transparent
Border False

INTEGRATION GUIDE 139


PA RT 4 W I N D O W E L EM EN T S

3. Attach a change script.


Attach a change script to the field, similar to the following example. This script
sets the mode of the scrolling window in the lookup. It also dynamically
changes the style of the text displayed in the lookup window, based on whether
details are being shown.

local boolean result;

if '(L) ShrinkExpandSwitch' = 1 then


{Make the first line of fields in the scrolling window plain.}
result = Field_SetFontStyle('Lead ID' of window
➥ Lead_Lookup_Scroll, FONT_STYLE_PLAIN);
result = Field_SetFontStyle('Lead Name' of window
➥ Lead_Lookup_Scroll, FONT_STYLE_PLAIN);
result = Field_SetFontStyle('Salesperson ID' of window
➥ Lead_Lookup_Scroll, FONT_STYLE_PLAIN);

{Shrink the scrolling window.}


expand window Lead_Lookup_Scroll, false;

{Set the tooltip for the button.}


result = Field_SetToolTip('(L) ShrinkExpandSwitch', "Show Details");
else
{Make the first line of fields in the scrolling window bold.}
result = Field_SetFontStyle('Lead ID' of window
➥ Lead_Lookup_Scroll, FONT_STYLE_BOLD);
result = Field_SetFontStyle('Lead Name' of window
➥ Lead_Lookup_Scroll, FONT_STYLE_BOLD);
result = Field_SetFontStyle('Salesperson ID' of window
➥ Lead_Lookup_Scroll, FONT_STYLE_BOLD);

{Expand the scrolling window.}


expand window Lead_Lookup_Scroll, true;

{Set the tooltip for the button.}


result = Field_SetToolTip('(L) ShrinkExpandSwitch', "Hide Details");
end if;

Find
The Find allows you to search the contents of the scrolling window, based on the
sorting order specified in the Sort by/View options button drop list.

The Find field allows you


to search the contents of
the scrolling window.

The prompt for the Find is actually a string field whose content is specified through
sanScript code when a sorting method is chosen in the Sort by/View options button
drop list.

140 IN T E G R AT I O N G U ID E
C H A P T E R 1 6 L O O K U P S

Adding a Find
To add a Find to a lookup window, use the following procedure.

1. Create the prompt for the Find.


Create a local field named ‘Find Prompt’ for your lookup form. This local field
has the following characteristics:

Field Name Find Prompt


Control Type String
Keyable Length 50

2. Add the find prompt to the window.


Drag the local field onto the lookup window layout. Set the following Object
properties for the field:

Editable False
TabStop False

Set the following Visual properties for the field:

Alignment Left
Appearance 3D Highlight
BackColor System - Button Face
Border True
FontColor System - Window Text

3. Add the Find field to the window.


Drag the global field named ‘Search Text’ onto the lookup window layout. Set
the following Object properties for the field:

TabStop True
Tooltip Enter the value to search for

4. Attach a change script.


Attach a change script to ‘Search Text’ field, similar to the following example.
This script causes the Redisplay button’s script to run, refilling the scrolling
window based on the text the user is searching for.
run script field 'Redisplay Button' of window 'Lead Lookup';

Select and Cancel buttons


Always use a Select button on lookup windows. The Select button should return a
value to the original window using the return statement. The following example
script returns a value from the Leads lookup window.
if empty('Lead ID' of window Lead_Lookup_Scroll) then
warning "Please select a record first.";
else
return 'Lead ID' of window Lead_Lookup_Scroll;
close form IG_Lead_Lookup;
end if;

A lookup window should also have a Cancel button that simply closes the window.

INTEGRATION GUIDE 141


PA RT 4 W I N D O W E L EM EN T S

Open and New buttons


Lookup windows can also contain Open and New buttons. An Open button opens
the item currently selected in the lookup window, allowing you to edit it in the
appropriate maintenance window. Clicking the Open button doesn’t close the
lookup.

The Open button opens


the item selected in the
lookup, but doesn’t close
the lookup window.

The script for the Open button will be similar to the following example.

{Open the Lead Maintenance form and display the current selection.}
open form IG_Lead_Maintenance;

if empty('Lead ID' of window Lead_Lookup_Scroll) then


warning "Please select a record first.";
else
'Lead ID' of window 'Lead Maintenance' of form IG_Lead_Maintenance
➥ = 'Lead ID' of window Lead_Lookup_Scroll;
run script 'Lead ID' of window 'Lead Maintenance' of form
➥ IG_Lead_Maintenance;
end if;

The New button is similar to the Open button. It opens the appropriate maintenance
window, allowing you to create a new item. It shouldn’t close the lookup window.

Note
Lookup windows should include window-level notes, if your application already
supports them. Window-level notes let the user attach information to the lookup
window that can be shared with other users.

Refer to Chapter 18, “Notes,” for more information about adding window-level and
record-level note support to your application.

142 IN T E G R AT I O N G U ID E
Chapter 17: Expansions And Zooms
Refer to Chapter 16, Along with lookups, expansions and zooms are the primary methods of accessing
“Lookups,” for additional information in a Microsoft Dynamics GP window. The following
additional information illustration shows how expansions and zooms appear in a typical window:
about using lookup
fields and lookup
zoom expansion
windows in your
application.

Information about expansions and zooms is divided into the following sections:

• Expansions
• Zooms

Expansions
Expansions extend, or expand the functionality of a primary window. Microsoft
Dynamics GP uses expansion windows when the current window isn’t large
enough to display all relevant fields. Use an expansion window only if you cannot
add its functionality to the parent window.

An expansion window includes two objects; an expansion field and an expansion


window. For instance, the expansion button for the Credit Card expansion field in
the Payables Transaction Entry window displays a window allowing the associated
card name, receipt number, date and payment number to be specified for the Credit
Card amount.

expansion field

expansion window

Creating an expansion window


To create an expansion window in your application, complete the following steps.

1. Create a new window.


Add a new window to an existing form, then display the window’s layout.
When you design the window’s layout, add fields from the form’s auto-linked
table that are relevant, but not necessary to save the record properly. An
expansion window should never include required fields.

When you save the record from the main window, the copy to table statement
will automatically copy the contents from both the main and expansion
windows to the current table buffer. When retrieving a record, the copy from
table statement will retrieve the current record and fill both the main window
and the expansion window.

INTEGRATION GUIDE 143


PA RT 4 W I N D O W E L EM EN T S

2. Add an OK button.
An expansion window typically has an OK button. The OK button should
simply close the window.

close window RM_Sales_Entry_Credit_Card;

Even though the expansion window will close, information in the expansion
window will persist until you clear the form. This information allows the save
operation to save the contents of both the main and expansion windows.

3. Add an expansion button.


In the main window, add the global field named ‘Expansion Button 1’ to the
right of the expansion field.

Global field Control


Expansion Button 1

4. Attach an expansion button script.


Attach a change script to the expansion button similar to the following example.
The change script should open another window for the current form.
open window RM_Sales_Entry_Credit_Card;

Zooms
A zoom allows a user to “drill down” to a lower level of detail for a given record. A
zoom control includes a zoom field and a zoom pointer. The following illustration
shows a typical zoom control:

prompt

zoom pointer zoom field


(key field)

The Salesperson zoom field in the sample application’s Lead Maintenance window
allows the user to zoom to the Salesperson Maintenance window, where the user
can view the entire salesperson record. The zoom field must provide a key value
(Salesperson ID) to display a salesperson record.

The zoom pointer


indicates that the user can
zoom to a window
displaying this record.

Always allow a zoom operation, regardless of whether the zoom field is empty or not. If the
field is empty, open the maintenance form with no record displayed.

144 IN T E G R AT I O N G U ID E
C H A P T E R 1 7 EX P A N S I O N S A N D Z O O M S

Refer to Chapter 16, Be sure to review the following points when adding a zoom field to your window:
“Lookups,” for
information about • A zoom field should always have a lookup button and the ability to add records
creating a lookup and on the fly.
adding records on the
fly. • The value of the zoom field should never change because of changes the user
makes in the window they zoomed to. To change the value of a zoom field,
allow the user to enter a new value and add a new record on the fly, or select an
existing record using a lookup.

Adding a zoom field


To add a zoom field to a window in your application, display the window’s layout
and complete the following steps.

1. Create a zoom button.


Create a local push button field and add it to the window layout. Position this
field directly over the prompt for the field on which you’re zooming. Set the
following field properties:

Visible False
Zoom True

2. Attach the zoom button script.


Attach a change script to the zoom button similar to the following example.
This example zooms from the Lead Maintenance window’s ‘Salesperson ID’
field to the RM_Salesperson form. If the user entered an existing salesperson ID
in the Lead Maintenance window, the script sets the ‘Salesperson ID’ field in the
RM_Salesperson window. Issuing a run script statement for that field displays
the associated record in that window.
open form RM_Salesperson;
'Salesperson ID' of window RM_Salesperson of form
➥ RM_Salesperson = 'Salesperson ID' of window 'Lead Maintenance';
{Check to see whether an existing ID was entered.}
if not empty('Salesperson ID') then
{The user zoomed when an existing ID was displayed, so
retrieve the record.}
run script 'Salesperson ID' of window RM_Salesperson of
➥ form RM_Salesperson;
end if;

INTEGRATION GUIDE 145


146 IN T E G R AT I O N G U ID E
Chapter 18: Notes
Notes provide users with two separate ways of sharing information:

• Window-level notes are attached to a given window and are available on a


company-wide basis.

• Record-level notes are attached to a given record and are available for a specific
record for a given company.

record-level note
button

window-level note
button

Information about notes is divided into the following sections:

• Window-level notes
• Record-level notes

Window-level notes
Window-level notes provide the user with a means of attaching information to a
window, such as detailed procedures for using the window, that can be shared with
other users.

Window-level note buttons are actually made up of two different button fields that
indicate whether a note is attached to the record currently displayed. The note
button with a “clean sheet” should appear if there isn’t a window-level note
attached to the window.

When the user attaches a note to the window, the note button with the “filled sheet”
should appear.

Global field Description Button


Note Absent Button - Toolbar Indicates the absence of a note for the window.

Note Present Button - Toolbar Indicates the presence of a note for the window.

A window-level note button should appear in the lower-right corner of the window,
in the window status area.

INTEGRATION GUIDE 147


PA RT 4 W I N D O W E L EM EN T S

Accessing window-level notes


Window-level notes are available on a company-wide basis, meaning that a note
applied to a window in company A can be viewed by all users who access that
window in company A, but not in company B. A different note can be applied to the
same window in company B.

When the user clicks the window-level note button, one of five note windows
should appear, allowing the user to change or delete an existing note or add a new
note to the current window. The note window that’s displayed when one of the note
forms is opened is shown in the following illustration:

You can display this window by opening one of five forms; Form_Note_1,
Form_Note_2, Form_Note_3, Form_Note_4 or Form_Note_5. Microsoft Dynamics
GP uses multiple forms in order to allow users to enter or edit multiple instances of
window-level and record-level notes at a given time. When a note is entered or
changed and the user clicks Attach, the note ID, date, time and note text and will be
stored in the SY_Notes_MSTR table.

Storing window-level notes


Window-level notes are stored in the SY_Notes_MSTR table (SY00700). The layout
of this table is shown in the following table:

Field Control Storage Description


type size
Note Name String 46 Stores the display name of the window. This field is
the key for the table.
Date Date 4 Stores the system date when the note record was
last updated by the user. This date is displayed in the
Note window.
Time Time 5 Stores the system time when the note record was
last updated by the user. This time is displayed in the
Note window.
Display Name String 82 Stores the window’s display name that’s returned by
the Window_GetTitle() function. This is the window
name that’s displayed in the Note window.
Text Field Text 0...32,000 Stores the note text entered by the user in the Note
window.

148 IN T E G R AT I O N G U ID E
C H A P T E R 1 8 N O T E S

Using procedures
Refer to the Procedure The following table explains each of the Microsoft Dynamics GP procedures used to
Design Documents implement window-level notes.
available with the SDK
for more information Name Description
about procedures used Check_Note_ID_String This script ascertains which of five possible note forms are currently
for notes. open. If one is open, it ascertains whether it’s displaying the note
record for the current window. If it is, the window is brought to the
front, allowing the user to view or edit the note.
Get_Next_Form_Note_ This script ascertains which note form is currently open (if any) and
To_Open returns an integer indicating the next available note form. There can be
a maximum of five note forms open. For example, if Form_Note_1 and
Form_Note_3 are open, a 2 will be returned (indicating Form_Note_2).
Check_For_Note This script checks the SY_Notes_MSTR table to ascertain whether a
note record exists for the window.

Adding window-level notes


To add window-level notes to a window in your application, display the window’s
layout and complete the following steps.

1. Add note fields to the window.


Add the following fields to the window’s layout:

Global field Position Field properties


Note Absent Button - Position this field in the window NA
Toolbar status area in the lower-right
corner of the window.
Note Present Button - Position this field directly over the NA
Toolbar Note Absent Button - Toolbar field.
Dummy Note Show Hide Position this field off the window Visible=False
layout area. Editable=False
SetChangeFlag=False

2. Attach a change script to the Note Absent Button - Toolbar field.


This script determines whether a note record exists in the SY_Notes_MSTR
table for the current window:
local string l_Note_ID, l_Display_Name;
local boolean isthere;
local integer l_exists, form_number;

{Retrieve the current display name of the window. This


will be displayed in the Note window when it's opened.}
l_Display_Name = Window_GetTitle(window Lead_Maintenace of form
➥ IG_Lead_Maintenance);

{Use the window display name as the key for the SY_Notes_MSTR table.}
l_Note_ID = "Lead Maintenance";

{Checks for multiuser conflicts}


call Check_For_Note, l_Note_ID, l_exists;
if 'Dummy Note Show Hide' = 1 and l_exists = 0 then
warning "This note has been deleted since you opened the window.";
elseif 'Dummy Note Show Hide' = 0 and l_exists = 1 then
warning "This note has been created since you opened the window.";
end if;
isthere = false;
form_number = 0;

INTEGRATION GUIDE 149


PA RT 4 W I N D O W E L EM EN T S

{---------------------------------------------------------
This section checks whether a note form for the current window is already
open. If a note form is already open, it's brought to the front. If no
note form is open for this window, the Get_Next_Form_Note_To_Open
procedure is used to return the next available note form. If none is
available (form_number=0), the user is warned to close available note
forms.
----------------------------------------------------------}
call Check_Note_ID_String, l_Note_ID, isthere, form_number;
if isthere = false then
call Get_Next_Form_Note_To_Open, form_number;
if form_number = 0 then
warning "Too many notes are currently open. Close
➥ available notes windows prior to attaching a note.";
abort script;
end if;
end if;

{---------------------------------------------------------
If a note form is available, each of five possible instances must be
examined. This section checks the value of form_number from the
Get_Next_Form_Note_To_Open procedure, and opens the first available note
form.
----------------------------------------------------------}
if form_number = 1 then
open form Form_Note_1 return to 'Dummy Note Show Hide';
'Note ID' of window Form_Note_1 of form Form_Note_1 = l_Note_ID;
'Display Name' of window Form_Note_1 of form
➥ Form_Note_1 = l_Display_Name;
if not isthere then
run script '(L) Dummy WIN PRE' of window Form_Note_1
➥ of form Form_Note_1;
end if;

elseif form_number = 2 then


open form Form_Note_2 return to 'Dummy Note Show Hide';
'Note ID' of window Form_Note_2 of form Form_Note_2 = l_Note_ID;
'Display Name' of window Form_Note_2 of form Form_Note_2 =
➥ l_Display_Name;
if not isthere then
run script '(L) Dummy WIN PRE' of window Form_Note_2
➥ of form Form_Note_2;
end if;
elseif form_number = 3 then
open form Form_Note_3 return to 'Dummy Note Show Hide';
'Note ID' of window Form_Note_3 of form Form_Note_3 = l_Note_ID;
'Display Name' of window Form_Note_3 of form Form_Note_3 =
➥ l_Display_Name;
if not isthere then
run script '(L) Dummy WIN PRE' of window Form_Note_3
➥ of form Form_Note_3;
end if;

elseif form_number = 4 then


open form Form_Note_4 return to 'Dummy Note Show Hide';
'Note ID' of window Form_Note_4 of form Form_Note_4 = l_Note_ID;
'Display Name' of window Form_Note_4 of form Form_Note_4 =
➥ l_Display_Name;
if not isthere then
run script '(L) Dummy WIN PRE' of window Form_Note_4 of
➥ form Form_Note_4;
end if;

150 IN T E G R AT I O N G U ID E
C H A P T E R 1 8 N O T E S

elseif form_number = 5 then


open form Form_Note_5 return to 'Dummy Note Show Hide';
'Note ID' of window Form_Note_5 of form Form_Note_5 = l_Note_ID;
'Display Name' of window Form_Note_5 of form Form_Note_5 =
➥ l_Display_Name;
if not isthere then
run script '(L) Dummy WIN PRE' of window Form_Note_5
➥ of form Form_Note_5;
end if;
end if;

3. Attach a change script to the Note Present Button - Toolbar field.


The following script runs for script on the ‘Note Absent Button - Toolbar’ field.
It retrieves an existing note record, then determines which note form to open.

run script 'Note Absent Button - Toolbar';

4. Attach a change script to the Dummy Note Show Hide field.


This script runs each time the window pre script runs (see step 5), and checks
for an existing note record for the window. If one exists, it sets the window-level
note button to display a “filled sheet.” Otherwise, it displays a “clean sheet.”

local string str_note_ID;


str_note_ID = "Lead Maintenance";

{----------------------------------------------------------
This section checks the SY_Notes_MSTR table for an existing record. If one
is present, it hides the Note Absent button and shows the Note Present
button.
----------------------------------------------------------}

call Check_For_Note, str_note_ID, 'Dummy Note Show Hide';

if 'Dummy Note Show Hide' = 1 then


hide 'Note Absent Button - Toolbar ';
show 'Note Present Button - Toolbar';
else
hide 'Note Present Button - Toolbar';
show 'Note Absent Button - Toolbar ';
end if;

5. Attach a window pre script.


This script runs the change script attached to the ‘Dummy Note Show Hide’
field, which determines whether a note record exists for the window and
displays the appropriate note button.

disable 'Delete Button';


set 'Sort By' to 1;

hide 'Note Present Button - Toolbar';


show 'Note Absent Button - Toolbar ';
run script 'Dummy Note Show Hide';

focus 'Lead ID';

INTEGRATION GUIDE 151


PA RT 4 W I N D O W E L EM EN T S

Record-level notes
Record-level notes provide the user with a means of attaching comments to a
specific record that can be shared with other users. The following illustration shows
how a note button appears in a window.

key field note button

Record-level notes are available on a company-wide basis, meaning that a note


applied to a record in company A can be viewed only by users who access that
record in company A.

Record-level note buttons are actually made up of two different button fields that
indicate whether a note is attached to the current record. The note button with a
“clean sheet” should appear if there isn’t a record-level note attached to the record.
The note button with the “filled sheet” should appear once the user attaches a note
to a record.

Global field Description Button


Note Absent Button - Window Area Indicates the absence of a note for the
record.
Note Present Button - Window Area Indicates the presence of a note for the
record.

A note button should appear to the right of the lookup button for a record’s key
field. If no lookup button is present, no note button should be present either.

Accessing record-level notes


When the user clicks the note button, one of five note windows should appear,
allowing the user to enter a new note or edit an existing one. After the user enters a
note and clicks Attach, the note text and its index are stored in the
SY_Record_Notes_MSTR table. This window is shown in the following illustration.

You can display this window by opening one of five forms; Form_Note_1,
Form_Note_2, Form_Note_3, Form_Note_4 and Form_Note_5. Microsoft Dynamics
GP uses multiple forms in order to allow users to enter or edit multiple instances of
notes at any given time. When a note is entered or changed and the user clicks
Attach, the note ID, date, time and note text and will be stored in the
SY_Record_Notes_MSTR table.

152 IN T E G R AT I O N G U ID E
C H A P T E R 1 8 N O T E S

Storing record-level notes


Record-level notes are stored in the SY_Record_Notes_MSTR table (SY03900). The
layout of this table is shown in the following table.

Field Control Storage Description


type size
Note Index Currency 14 The key field for this table. It stores a unique index for
the note record. The developer table must have this
field present in order to save and retrieve
corresponding note records.
Date Date 4 Stores the system date when the note record was last
updated by the user. This date is displayed in the Note
window.
Time Time 5 Stores the system time when the note record was last
updated by the user. This time is displayed in the Note
window.
Text Field Text 0...32,000 Stores the note text entered by the user in the Note
window.

Using the note index


Refer to Adding record- To add record-level notes to developer records, you must add the ‘Note Index’ field
level notes on to the developer table that you want to use record-level notes with. When you save
page 154 for a script a new developer record with a record-level note, you assign a unique note index to
example of adding and the ‘Note Index’ field in the developer record, then create a new note record in the
retrieving record-level SY_Record_Notes_MSTR table with the same index.
notes.
Retrieving notes
When the developer record is retrieved, its note index is used as a key for the
SY_Record_Notes_MSTR table to retrieve its corresponding note record.

Using procedures
Refer to the Procedure The following table explains each of the procedures used to implement record-level
Design Documents notes.
available with the SDK
for additional Name Description
information about Check_Note_Index This script ascertains which (if any) of the five note forms is
these procedures. open. If one is open, it determines if the record note
displayed is the one for the current developer record.
Get_Next_Form_Note_To_Open This script ascertains which note form (if any) is currently
open and returns an integer indicating the next available
note form. There can be a maximum of five note forms
open. For example, if Form_Note_1 and Form_Note_3 are
open, a 2 will be returned (indicating Form_Note_2).
Check_For_Record_Note This script reads the SY_Record_Notes_MSTR table based
on the note index for the current developer record. If no
matching record is found, 0 is returned. If a matching
record is found, 1 is returned. The table is closed at the
completion of the script.
Get_Next_Note_Index This script retrieves a note index for a new developer
record. This must be stored with the developer record and
the note record.
Delete_Record_Note This script removes a record-level note from the
SY_Record_Notes_MSTR table.

INTEGRATION GUIDE 153


PA RT 4 W I N D O W E L EM EN T S

Adding record-level notes


To add record-level notes for a window in your application, complete the following
steps.

1. Add a note index to your table.


Add the global field named ‘Note Index’ to the developer table whose records
you want to assign notes to. You must use this field to store a unique note index
for the developer record; the same index is also stored in the
SY_Record_Notes_MSTR table. When a user displays a developer record, you
can search the SY_Record_Notes_MSTR table for a note index that matches the
index stored with the developer record.

2. Add note fields to the window.


Open the window’s layout and add the following global fields to the window
where you want to assign record-level notes.

Global field Position Field properties


Note Absent Button - Position this field to the right of the N/A
Window Area lookup button for the key field.
Note Present Button - Position this field directly over the N/A
Window Area Note Absent Button - Window Area
field.
Note Index Position this field off the window Visible=False
layout area. SetChangeFlag=False
Editable=False
Dummy Record Note Position this field off the window Visible=False
Show Hide layout area. SetChangeFlag=False

3. Add a change script to the Note Absent Button - Window Area


button.
This script ascertains whether an existing Note window is open for the current
note index. If a Note window is already open for the current record (for
instance, if it’s minimized or positioned behind other windows), it’s maximized
or brought to the front. If no Note window is open, the first available one is
found and opened, and window fields are set to retrieve the note record.
local string l_Note_ID;
local integer l_Form_Number;
local boolean l_Found;

l_Note_ID = 'Lead ID';


if empty(l_Note_ID) then
warning "Enter a Lead ID prior to attaching a note.";
focus 'Lead ID';
abort script;
end if;

{----------------------------------------------------------
This portion of the script checks to see whether a note
form with the current note index is already open.
----------------------------------------------------------}
call Check_Note_Index, 'Note Index', l_Found, l_Form_Number;
if not l_Found then
call Get_Next_Form_Note_To_Open, l_Form_Number;
if l_Form_Number = 0 then
{Too many note forms are open. A message will appear.}
abort script;
end if;
end if;

154 IN T E G R AT I O N G U ID E
C H A P T E R 1 8 N O T E S

{----------------------------------------------------------
This portion of the script opens the next available notes
form and sets its window fields. There are five forms
available.
----------------------------------------------------------}
if l_Form_Number = 1 then
open form Form_Note_1 return to 'Dummy Record Note Show Hide';
'Record Note' of window Form_Note_1 of form Form_Note_1 = true;
'Note ID' of window Form_Note_1 of form Form_Note_1 = l_Note_ID;
'Note Index' of window Form_Note_1 of form Form_Note_1 = 'Note Index';
if not l_Found then
run script '(L) Dummy WIN PRE' of window Form_Note_1
➥ of form Form_Note_1;
end if;

elseif l_Form_Number = 2 then


open form Form_Note_2 return to 'Dummy Record Note Show Hide';
'Record Note' of window Form_Note_2 of form Form_Note_2 = true;
'Note ID' of window Form_Note_2 of form Form_Note_2 = l_Note_ID;
'Note Index' of window Form_Note_2 of form Form_Note_2 = 'Note Index';
if not l_Found then
run script '(L) Dummy WIN PRE' of window Form_Note_2
➥ of form Form_Note_2;
end if;

elseif l_Form_Number = 3 then


open form Form_Note_3 return to 'Dummy Record Note Show Hide';
'Record Note' of window Form_Note_3 of form Form_Note_3 = true;
'Note ID' of window Form_Note_3 of form Form_Note_3 = l_Note_ID;
'Note Index' of window Form_Note_3 of form Form_Note_3 = 'Note Index';
if not l_Found then
run script '(L) Dummy WIN PRE' of window Form_Note_3
➥ of form Form_Note_3;
end if;

elseif l_Form_Number = 4 then


open form Form_Note_4 return to 'Dummy Record Note Show Hide';
'Record Note' of window Form_Note_4 of form Form_Note_4 =true;
'Note ID' of window Form_Note_4 of form Form_Note_4 = l_Note_ID;
'Note Index' of window Form_Note_4 of form Form_Note_4 = 'Note Index';
if not l_Found then
run script '(L) Dummy WIN PRE' of window Form_Note_4
➥ of form Form_Note_4;
end if;

else
open form Form_Note_5 return to 'Dummy Record Note Show Hide';
'Record Note' of window Form_Note_5 of form Form_Note_5 = true;
'Note ID' of window Form_Note_5 of form Form_Note_5 = l_Note_ID;
'Note Index' of window Form_Note_5 of form Form_Note_5 = 'Note Index';
if not l_Found then
run script '(L) Dummy WIN PRE' of window Form_Note_5
➥ of form Form_Note_5;
end if;
end if;

INTEGRATION GUIDE 155


PA RT 4 W I N D O W E L EM EN T S

4. Add a change script to the Note Present Button - Window Area


field.
This script attempts to display the note currently applied to the record and runs
only if a note is attached to the current record, and the ‘Note Present Button -
Window Area’ field is displayed (see the example in step 5).

run script 'Note Absent Button - Window Area';

5. Add a change script to the Dummy Record Note Show Hide field.
This script runs when the user initially displays the record (see step 6). The
procedure Check_For_Record_Note attempts to read the
SY_Record_Notes_MSTR table based on the note index for the displayed
record. If a note record is found, this script sets the ‘Dummy Record Note Show
Hide’ field to 1 to display the button fields appropriately.

call Check_For_Record_Note, 'Note Index', 'Dummy Record Note Show Hide';


if 'Dummy Record Note Show Hide' = 1 then
hide 'Note Absent Button - Window Area';
show 'Note Present Button - Window Area';
else
hide 'Note Present Button - Window Area';
show 'Note Absent Button - Window Area';
end if;

6. Modify the change script for the window’s key field.


This script retrieves an existing developer record; if there is no associated note
index for the developer record, one is assigned to the record using the
Get_Next_Note_Index procedure. If a note index exists, run the script for the
‘Dummy Record Note Show Hide’ field is run to ascertain whether a note
record exists for the developer record.

'Lead ID' of table IG_Leads_MSTR = 'Lead ID' of window 'Lead Maintenance';


release table IG_Leads_MSTR;
change table IG_Leads_MSTR by IG_Leads_MSTR_Key1;

if err() = OKAY then


if empty ('Note Index' of table IG_Leads_MSTR) then
{Retrieve a new note index and assign it.}
call Get_Next_Note_Index, 'Note Index' of table IG_Leads_MSTR;
save table IG_Leads_MSTR;
change table IG_Leads_MSTR;
end if;
copy from table IG_Leads_MSTR;
clear changes form IG_Lead_Maintenance;
enable 'Delete Button';
{Check to see whether the lead record has a note attached.}
run script 'Dummy Record Note Show Hide';
end if;
lock 'Lead ID';

156 IN T E G R AT I O N G U ID E
C H A P T E R 1 8 N O T E S

7. Modify the Delete button change script.


This script calls the Delete_Record_Note procedure, which deletes the note
record associated with current note index from the SY_Record_Notes_MSTR
table.

if ask("Delete this lead record?", "Cancel", "Delete", "") = ASKBUTTON2


➥ then
{The user chose to delete the record.}
remove table IG_Leads_MSTR;
call Delete_Record_Note,'Note Index';
restart form;
end if;

8. Add a window pre script.


In this script, the show field and hide field statements ensure that the note
button will display a “clean sheet” when the form is opened or restarted.

show 'Note Absent Button - Window Area';


hide 'Note Present Button - Window Area';

INTEGRATION GUIDE 157


158 IN T E G R AT I O N G U ID E
Chapter 19: Password Control
Password control allows users to assign or change passwords for access to a given
record in your application. Microsoft Dynamics GP uses the password padlock
button to display the password dialog. The password padlock button works with a
window’s key field to assign a password to given records. The following illustration
shows a password button.

key field password button

Using passwords
The User Password Setup dialog allows users to apply a new password, or change a
password for access to a given record. This dialog appears when the user clicks the
password padlock button. The following illustration shows the User Password
Setup dialog.

You can assign a


password, or change an
existing password using
the User Password Setup
window.

Password control requires that you store the password entered in this dialog with
the record, and allow access to the record only if the user enters its corresponding
password.

Once the user saves the record and attempts to access the record again, another
dialog appears (invoked from the getstring() function), asking the user to enter the
password assigned previously.

A password dialog
appears if there is a
password for a given
record.

INTEGRATION GUIDE 159


PA RT 4 W I N D O W E L EM EN T S

Enabling password protection


Complete the following steps to add password protection for records in a given
window. Once you’ve enabled password protection, you can use the User Password
Setup dialog to change an existing password for a record, or assign a new password
to a previously non-passworded record:

1. Create a global password field.


Create a password field, and add it to the table whose records you want
accessed through password control. Use the Microsoft Dynamics GP Password
data type as the basis for this field. This is a string data type with a keyable
length of 10, and which forces uppercase characters.

2. Add a password button to your window.


Open the layout for the window, then drag the global field named ‘Password
Button’ to the window area. Position this field next to the right edge of the
window’s key field.

Global field Control


Password Button

3. Add the password field to the window.


Add the new password field created in step 1 to the window, and position it
outside the window area. This allows you to save the password with the record.
With the password field selected, set the following properties:

Visible False
Editable False

4. Attach a password button script.


Attach a change script to the Password Button field similar to the following
example. This script will open the User Password Setup window and return the
new or changed password to the invisible password field (IG_Lead_Password,
in the following example). This is the password that’s stored with the lead
record.

if empty('Lead ID') then


focus field 'Lead ID';
warning "You must enter a lead ID before assigning a password.";
abort script;
end if;
open form SY_Set_Change_Password return to 'Lead Password';
{Set a flag that indicates whether the password is being changed.}
'(L) Changed' of window Set_Change_Password of form
➥ SY_Set_Change_Password = false;

{----------------------------------------------------------------
If there is an existing password for the lead record, set a field to that
password, allowing the user to enter the old password in the User Password
Setup window prior to entering a different one.
----------------------------------------------------------------}
'Dummy Password' of window Set_Change_Password of form
➥ SY_Set_Change_Password = 'Lead Password' of table IG_Leads_MSTR;

160 IN T E G R AT I O N G U ID E
C H A P T E R 1 9 P AS S WO R D C O N TR O L

5. Modify the key field’s change script.


Use a change script in the window’s key field similar to the following example.
Upon the successful retrieval of a record, this script ascertains whether a
password exists for the current record. If there is one, the getstring() function
prompts the user for a password.
The script then compares the entry from the getstring() dialog to the string
stored with the record. If they don’t match, a dialog prompts the user to retry
until they enter the correct password or click Cancel.
local string l_Password;
local boolean l_Correct_Password;

'Lead ID' of table IG_Leads_MSTR = 'Lead ID' of window 'Lead Maintenance';


release table IG_Leads_MSTR;
change table IG_Leads_MSTR by IG_Leads_MSTR_Key1;

if err() = OKAY then


{Check to see if a password was applied to this lead record.}
if not empty('Lead Password' of table IG_Leads_MSTR) then
{A password was applied to this lead record.}
if not getstring("Enter a password for this Lead ID", true,
➥ l_Password) then
{The user clicked Cancel in the dialog box, so release
the table and abort the script.}
release table IG_Leads_MSTR;
clear field 'Lead ID';
focus field 'Lead ID';
abort script;
else
if upper(l_Password) <> upper('Lead Password' of table
➥ IG_Leads_MSTR) then
clear field l_Password;
while not l_Correct_Password do
if not getstring("You've entered the wrong password,
➥ please reenter.", true, l_Password) then
{The user clicked Cancel.}
release table IG_Leads_MSTR;
abort script;
else
{User clicked OK.}
if upper(l_Password) = upper('Lead Password' of
➥ table IG_Leads_MSTR) then
l_Correct_Password = true;
end if;
end if;
end while;
end if;
end if;
end if;

{Retrieve the record.}


copy from table IG_Leads_MSTR to window 'Lead Maintenance';
clear changes form IG_Lead_Maintenance;
enable 'Delete Button';
lock 'Lead ID';

INTEGRATION GUIDE 161


PA RT 4 W I N D O W E L EM EN T S

{Set the note index.}


if empty('Note Index' of table IG_Leads_MSTR) then
call Get_Next_Note_Index, 'Note Index' of table IG_Leads_MSTR;
save table IG_Leads_MSTR;
change table IG_Leads_MSTR;
end if;
else
{No record exists. Allow the user to create a new one.}
enable 'Delete Button';
lock 'Lead ID';
run script 'Dummy Record Note Show Hide';
call Get_Next_Note_Index, 'Note Index';
end if;

162 IN T E G R AT I O N G U ID E
Chapter 20: Data Entry Conventions
Microsoft Dynamics GP uses several data entry conventions for organizing how
information appears on a window. The following conventions are discussed:

• Required fields
• Prompts
• Auto-complete
• Field groups
• Tab sequence
• Using product names

Required fields
Required fields are window fields that must contain information in order to save a
record properly. Set the Required property to True for any field that functions as a
primary key or key segment. This ensures that the user enters the key information
required to store the record.

Displaying required field prompts


Microsoft Dynamics GP can display prompts for required fields in a different
typeface (bold, italic or both) or a different color than prompts for non-required
fields. You can specify this format using the options available in the User
Preferences window. Once you’ve specified the format, choose Show Required
Fields from the Help menu. Required field prompts will then appear in the selected
format. The following illustration shows required field prompts in bold.

required field prompt


standard field prompt

required field

Creating required fields


To create required fields and the corresponding prompt display, open a window’s
layout and complete the following steps.

1. Mark the field as required.


In the layout window, select the field you want to make required, then set its
Required property to True.

2. Link the prompt.


Choose Link Prompt from the Tools menu. Click the field, and drag the pointer
to the prompt you want the field linked to.

Once you’ve positioned the pointer over the prompt, release the mouse button;
a highlight will flash to indicate that the link was successful. Link the remainder
of the required fields. When you’ve finished, choose Link Prompt again to
unmark the menu item.

INTEGRATION GUIDE 163


PA RT 4 W I N D O W E L EM EN T S

3. Attach a Save button change script.


Attach a change script to the window’s Save button similar to the following
example. This example uses the required() function to ascertain whether all
required fields contain data. If the user hasn’t entered all required fields, the
script displays a warning dialog.

if not required (form IG_Lead_Maintenance) then


warning "Please enter all required fields before attempting to save
➥ this record.";
else
'Lead ID' of table IG_Leads_MSTR = 'Lead ID';
copy to table IG_Leads_MSTR;
save table IG_Leads_MSTR;
restart form;
focus 'Lead ID' of window 'Lead Maintenance';
end if;

4. Change the prompt display.


Start Microsoft Dynamics GP. Point to Setup in Tools menu and choose User
Preferences. Click Display to display the User Display Preferences window.
Select font options and color options you want to use for required fields. Click
OK.

5. Show required fields.


Choose Show Required Fields from the Help menu, then display your window.
The prompts you linked to fields will appear in the format you specified.

Date fields
When using date fields in the windows for your integration, be sure to account for
the size of the calendar drop-down that appears within the date field. We
recommend that date fields be 101 pixels wide for optimal display. This allows a full
4-digit year to display with large fonts.

Date fields should be 101


pixels wide.

If you don’t have this much space available, we recommend that date fields be a
minimum of 85 pixels wide.

Prompts
A prompt provides a label for a field. All fields or controls displayed in a window
must have a prompt; however, push buttons, single check box controls and radio
buttons store prompts as static text within the data type definition for each. The
following illustration shows a typical prompt.

prompt field

164 IN T E G R AT I O N G U ID E
C H A PT E R 2 0 D AT A E N T R Y C O N V E N T IO N S

Creating prompts
Use the following procedure when creating prompts so they appear like standard
prompts in Microsoft Dynamics GP.

1. Create the prompt.


Using the text tool, type the name of the prompt, then link it to its associated
field.

2. Set properties for the prompt.


Using the Arrow tool, select the prompt and set the following properties:

Appearance 3D Highlight
BackColor System - Button Face
Border True
FontColor System - Button Text
Pattern None
PatternColor Black

3. Resize the prompt.


Select the prompt using the arrow tool. Drag the resize handles until the right
edge of the prompt touches the left edge of its associated field.

Linking prompts to fields


The Link Prompt menu item available when the Dexterity Layout window is open
allows you to link a field to its associated prompt. There are three primary reasons
for linking fields to their prompts:

Refer to Required fields • Prompts for fields that you’ve marked as required (the field’s Required
on page 163 for more property is true) will appear in the required fields format when linked. Users
information about can specify this format using the User Display Preferences window in Microsoft
creating required Dynamics GP.
fields.
• Prompts that you’ve linked to fields will appear dimmed when you use the
disable statement to disable the field.

To link a prompt to its field, open the Layout window and choose Link Prompt from
the Tools menu. Click the field you want linked, and drag the pointer to the prompt
you want the field linked to. Once you’ve positioned the pointer over the prompt,
release the mouse button; a highlight will flash to indicate that the link was
successful. Link the remainder of the fields, then choose Link Prompt again to
unmark the menu item.

General prompt guidelines


The following standards apply to all prompts in a window.

Standard Description
Naming Fields should use short prompts (such as “Name” instead of “Lead Name”)
only when a previous prompt has used the full name within the same window.
Abbreviations Use abbreviations consistently. If an abbreviation could also be another word,
use a period after the abbreviation. For example, use “No.” as the abbreviation
for “Number,” but “Acct” for “Account”.
Punctuation Prompts should never use punctuation other than a colon (:). Use a colon after
prompts for list fields, radio button groups and check box groups.
Capitalize the first letter of each word in the prompt.

INTEGRATION GUIDE 165


PA RT 4 W I N D O W E L EM EN T S

Standard Description
General Prompt text should appear left-justified in all cases.
By default, prompts use the System font. Prompts should be wide enough to
display properly when the operating system is set to display large fonts.
International Design your prompts to allow for translation into other languages. Since
translating prompts can result in longer prompts, always make the prompt
approximately 30% wider than the size required to accommodate the text.
Positioning Position prompts no less than 8 pixels from the left edge of the window area.

Auto-complete
To be consistent with Microsoft Dynamics GP, the control field for any maintenance
window you create should have its AutoComplete property set to true. This allows
the user to easily access data by selecting previously entered values from a list.
Users can control whether they use auto-complete by setting the appropriate user
preference.

For example, Lead ID field in the Lead Maintenance window has auto-complete
enabled. If the user chooses to use auto-complete, the auto-complete list will
automatically be displayed for this field.

AutoComplete is set to
true for the Lead ID field.

Field groups
A field group is an area of the window that contains closely related fields. In most
Microsoft Dynamics GP windows, field groups are used to clearly delineate header,
detail and summary information in the window. The following illustration shows a
typical division of a window’s workable area based on the information each area
contains.

header field group

detail field group

summary field group

Be sure to allow enough space between the groups to clearly indicate which fields
belong to each group.

166 IN T E G R AT I O N G U ID E
C H A PT E R 2 0 D AT A E N T R Y C O N V E N T IO N S

Tab sequence
A tab sequence moves the focus from one field to the next field in the sequence
when a user presses the TAB key. The tab sequence helps reduce unnecessary
keystrokes, enables users to enter data in a logical order and increases keyboard
efficiency.

Use the following procedure when setting a tab sequence for windows that will
appear in Microsoft Dynamics GP.

1. Be sure all fields are included in the tab sequence.


To ensure the tab sequence is set consistently, be sure that the TabStop property
is set to True for all fields in the window.

2. Set data entry sequence.


Set all fields in the window area beginning with the first field in the window
and continuing in logical order until you’ve included all data entry fields. For
field groups, the tab sequence moves from top to bottom and from left to right.

1 3
2 4

5 11
6 12
7 13
8
9 10 14

15
16
17

If there are any push button controls within the window area, set push button
controls beginning with the top (or leftmost) button, and ending with the
bottom (or rightmost) button.

3. Set window control area sequence.


Set all controls in the window control area.

18 19 20

4. Set the window status area sequence.


Set the controls in the window status area.

21

INTEGRATION GUIDE 167


PA RT 4 W I N D O W E L EM EN T S

5. Remove fields from the tab sequence.


Set the TabStop property to False for the following fields:

• Lookups
• Notes
• Browse buttons
• Help buttons
• Password buttons
• Print button
• Zoom buttons

Using product names


In some cases, you may find it necessary to use a product name in a message. Rather
than hard-coding the product name in your messages, we recommend that you use
a token instead.

The token to indicate the product name in a message or static string is


@PRODprodID@ where prodID is the product ID of the product whose name you
want to include in the message. The product name will be read automatically from
the launch file. For example, the following message includes the name of the
currently-active product, which has a product ID 0:

Message ID: 22001


Message: The current product is @PROD0@.

If the token specifies a product for which a product name cannot be found, the
string [unknown] is substituted.

You can also use product tokens to include the name of a product in static strings.
The following static string will include the name of the sample integrating
application, which has the product ID 3333:

@PROD3333@ Options:

If you need to use product names in strings you create, you can use the
Utility_SubstituteTokens() function to replace the product tokens with the
corresponding product names.

168 IN T E G R AT I O N G U ID E
PART 5: NAVIGATION
Part 5: Navigation
Use the information in this portion of the documentation to learn about adding
navigation elements to your integration. The following is a list of the topics
discussed, along with a brief explanation of each:

• Chapter 21, “Commands,” describes how work with commands and command
forms for your integration.

• Chapter 22, “Menus in Microsoft Dynamics GP,” explains how to add items to
menus in Microsoft Dynamics GP.

• Chapter 23, “Toolbars in Microsoft Dynamics GP,” describes how to add items
to toolbars in Microsoft Dynamics GP.

• Chapter 25, “Shortcuts,” explains how to add shortcuts to the Navigation pane.

170 IN T E G R AT I O N G U ID E
Chapter 21: Commands
Commands are an essential part of the navigation for your integration. They allow
navigation items for your integration to appear seamlessly with the navigation
items for Microsoft Dynamics GP. Information about commands is divided into the
following sections:

• Command overview
• Command forms
• Defining commands
• Opening the command form
• Closing the command form

Command overview
Commands are used to define actions for your application. A command can open a
form, or can execute a script attached to the command. A command can also be
used to contain a list of other commands.

In Microsoft Dynamics GP, commands are used to define the contents of the menus
and toolbars displayed to the user. Special windows in Microsoft Dynamics GP
allow the user to customize the menus and toolbars. Users can specify how the
various commands are organized and displayed.

You will define commands for your integrating application, and add them to the
menus and toolbars that are displayed in the Microsoft Dynamics GP interface. It’s
important that you do this using the capabilities provided within the Microsoft
Dynamics GP application, rather than by directly using commands such as
CommandList_Add(). Using the methods and functions provided by the Microsoft
Dynamics GP application allows your application’s commands to participate in the
customization and security features of the application.

Command forms
Commands are a form-level resource. For your integrating application, we
recommend that you create a separate form that will contain the commands you
define for your integration. To make it easy to find the commands that are defined
within Microsoft Dynamics GP, consider using the following naming scheme for
your command form:

Command_name

For the name portion, substitute something that uniquely identified your
application. For example, the command form for the sample integrating application
is named Command_IG_Sample.

The command form should contain one window with the following names:

Technical Name Dummy


Title ~internal~

These names prevent the command form from appearing in the Security Setup
window and from being included in activity tracking.

Be sure that you set the AutoOpen property for the window to False to prevent the dummy
window from being displayed when you open the command form.

INTEGRATION GUIDE 171


PA RT 5 N A V IG A TI O N

Defining commands
When you define the commands for your integration, use the following guidelines
to maintain consistency within the application.

Commands to create
Create commands for the following items in your integration:

• Any forms that are opened directly from a menu or a toolbar. This includes any
forms that a user may want to explicitly open, even if they are not part the
integration’s default navigation.

• Any actions or processes that a user can start independently, or that you want to
specifically control access to.

• Any groups of commands that will appear as a submenu or toolbar in the


application.

• Commands for actions that will be performed for list items.

Naming commands
When naming commands, use the following conventions:

Command type Command name Display name


Form The technical name of the form The display name for the main
that is being opened. window that is being opened.
Script A name that describes the The name of the action, with
purpose of the command, spaces allowed.
typically without spaces.
Command List A name that identifies the group The name of the group. This
of commands, beginning with name will be used for the menu
CL_. or submenu name.

Images
Native pictures or icon resources are used for command images. In Microsoft
Dynamics GP, several images used for commands are defined as native pictures in
the Dynamics.dic dictionary. Several other images used for commands are defined
as icon resources in the GPIcons.dll file that is installed with Microsoft Dynamics
GP.

Various native pictures for commands are already defined in the Dynamics.dic
dictionary, and may be appropriate for your commands. If you have implemented
standard windows for your integration, such as transaction, inquiry, or list
windows, we recommend that you use the standard images for the corresponding
commands. The images are listed in the following table.

Image Name Image Name


Cmd_Cards Cmd_Routines

Cmd_Inquiry Cmd_Setup

Cmd_List Cmd_Transactions

Cmd_Reports Cmd_Utilities

172 IN T E G R AT I O N G U ID E
C H A P T E R 2 1 C O M M A N D S

If you create your own command images, the images should be 20 pixels by 20
pixels to display properly on a toolbar. Native pictures used for commands typically
have Cmd_ as the prefix for their name.

The icon images included in the GPIcons.dll are typically used when creating
commands that are used as actions for lists. The Dynamics.dic dictionary already
contains a reference to this icon assembly, so the icon resources in this resource
assembly are easily available for your. You will learn more about creating
commands for list actions in Commands for the Action Pane on page 212.

Opening the command form


The command form for your integration must be open for the commands to be
accessible. To open your command form, use a procedure trigger that is activated
after the OpenCommandForms procedure is run within Microsoft Dynamics GP.

The following example shows the registration for the trigger that opens the
Command_IG_Sample command form in the sample integrating application:
l_result = Trigger_RegisterProcedure(script OpenCommandForms,
➥ TRIGGER_AFTER_ORIGINAL, script IG_OpenCommandForm);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The following script runs when the trigger is activated, and opens the
Command_IG_Sample form.
open form Command_IG_Sample;

Closing the command form


The command form for your integration should be closed when the Microsoft
Dynamics GP application is closed. To do this, use a procedure trigger that is
activated after the CloseCommandForms procedure is run within Microsoft
Dynamics GP. The following example shows the registration for the trigger that
closes the Command_IG_Sample command form in the sample integrating
application:
l_result = Trigger_RegisterProcedure(script CloseCommandForms,
➥ TRIGGER_AFTER_ORIGINAL, script IG_CloseCommandForm);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The following script runs when the trigger is activated, and closes the
Command_IG_Sample form.
close form Command_IG_Sample;

Command security
You control access to the functionality in your application by specifying whether
commands are visible and enabled. When you disable or hide commands for you
integration, users cannot access the functionality provided by those commands.

INTEGRATION GUIDE 173


PA RT 5 N A V IG A TI O N

One common location for integrations to control access to commands is in the form
pre script for the command form. Access (such as registration keys) can be checked
at the time the command form is opened. If access shouldn’t be allowed, the
commands on the form can be hidden and disabled.

Microsoft Dynamics GP provides two procedures that you can use to control access
to the commands for your integration. The Command_HideAndDisable and
Command_ShowAndEnable procedures provide a standard way for integrations
to enable and disable commands. By using common procedures, Microsoft
Dynamics GP can choose to display the commands, but leave them in the disabled
state so they cannot be used. This can be useful so that all commands can be seen,
such as when testing an application.

174 IN T E G R AT I O N G U ID E
Chapter 22: Menus in Microsoft Dynamics GP
Menus in the Area Pages are the primary method of navigation within the Microsoft
Dynamics GP application. As an alternative, these same menu items are also
available in the “Main” toolbar and from “Tools” submenu of the Microsoft
Dynamics GP menu. You will add commands for your integration to the menus
already defined in Microsoft Dynamics GP. Information about menus is divided
into the following sections:

• Menu overview
• Menu implementation
• Menu structure in Microsoft Dynamics GP
• Viewing the menu structure
• Adding to Microsoft Dynamics GP menus
• Menu creation procedure

Menu overview
The menus in Microsoft Dynamics GP are created dynamically, each time a user logs
into the accounting system. Security settings control what items appear in the set of
menus displayed for a specific user. This prevents users from trying to access items
they do not have permission to see, and reduces clutter in the menu structure.

The menu items in the Area Pages are the primary method of navigation in
Microsoft Dynamics GP. To display an Area Page, the user selects it in the
Navigation Pane. For example, the following is the Sales Area Page. It displays the
various menu items that are available to complete sales-related tasks.

Your integration will add


menu items that will
appear in the Area Page.

As an alternative means of navigation, these same menu items for Transactions,


Inquiry, Cards, and Reports are available from the “Main” toolbar in Microsoft
Dynamics GP. The menu items for Routines, Utilities, and Setup are available from
the “Tools” submenu in the Microsoft Dynamics GP menu.

INTEGRATION GUIDE 175


PA RT 5 N A V IG A TI O N

You will create commands for the items in your integration that you want to access
from the Area Pages or the alternative menus. When you add commands to the
Area Pages, they will automatically be included in the corresponding alternative
menus.

These same commands you create for menu items will typically be used for toolbar
items as well. Refer to Chapter 21, “Commands,” for more information about
creating commands for your integration. Code in your integrating application will
add the commands to the appropriate locations in the menu structure.

Menu implementation
To understand how to structure the code that adds menu items for your integration,
it is useful to know how menus are implemented. Microsoft Dynamics GP stores a
default set of menus in the syMenuMstr (SY07110) table. If a user customizes the
menus, their customized menu set is saved in the syMenuMstr table.

The menu structure displayed for a user is built each time that user logs into
Microsoft Dynamics GP. If the user has made customizations to the menus, the
user’s customized set of menu items is used. Otherwise the default set of menus is
used.

Every integrating dictionary that will have menu items must contain sanScript code
that defines the default menu items for that application. Each time a user logs into
Microsoft Dynamics GP, this code to define the default menus will be run, ensuring
that the default menu structure is always up-to-date.

Once the default menu structure has been updated, Microsoft Dynamics GP is ready
to load the appropriate set of menus for the current user. Either the default set or the
user’s customized set will be used, depending on whether the user has made menu
customizations.

Menus built from sanScript code that is run directly from a dictionary can be
constructed more quickly than those built from information stored in a SQL table.
Microsoft Dynamics GP uses this fact to optimize how the menu structure for a user
is built.

• If the user has customized their set of menus, the menu information from the
syMenuMstr table will be used.

• If the user has not made any menu customizations, the default menu set is used.
Rather than load this default menu set from the syMenuMstr table, the
sanScript code that defines the default menu items for each dictionary is called
again. This will load the default menu set more quickly.

When you write the sanScript code to define your integration’s menu items, the
code must be able to work with both of these cases. The code from the sample
integrating application will show you how to structure your code to create menu
items.

176 IN T E G R AT I O N G U ID E
C H A P T E R 2 2 M EN U S I N M I C R O S O F T D Y N A M I C S G P

Menu structure in Microsoft Dynamics GP


To add your menu items to the set of menus in Microsoft Dynamics GP, you need to
know how the menus are structured. The following table shows the menu structure
for the core application. These are the menus you see in the Area Pages, in the
Microsoft Dynamics GP menu, and the “Main” toolbar. You will use this
information when you add the menu items for your integration.

Top-level menu Submenu Form Command


Navigation Pane Administration Navigation Command_NavBar AdministrationButton
Pane
Field Service Navigation Command_NavBar FieldServiceButton
Pane
Financial Navigation Pane Command_NavBar FinancialButton
HR Payroll Navigation Pane Command_NavBar HRPayrollButton
Inventory Navigation Pane Command_NavBar InventoryButton
Manufacturing Navigation Command_NavBar ManufacturingButton
Pane
Project Navigation Pane Command_NavBar ProjectAccountingButton
Purchasing Navigation Pane Command_NavBar PurchasingButton
Sales Navigation Pane Command_NavBar SalesButton
Tools* Command_System CL_Tools
Tools >> Setup Command_System CL_Setup
System Command_System CL_System_Setup
Company Command_System CL_Company_Setup
Posting Command_System CL_Posting_Setup
Financial Command_Financial CL_Financial_Setup
Sales Command_Sales CL_Sales_Setup
Purchasing Command_Purchasing CL_Purchasing_Setup
Inventory Command_Inventory CL_Inventory_Setup
Payroll Command_Payroll CL_Payroll_Setup
Tools >> Utilities Command_System CL_Utilities
System Command_System CL_System_Utilities
Company Command_System CL_Company_Utilities
Financial Command_Financial CL_Financial_Utilities
Sales Command_Sales CL_Sales_Utilities
Purchasing Command_Purchasing CL_Purchasing_Utilities
Inventory Command_Inventory CL_Inventory_Utilities
Payroll Command_Payroll CL_Payroll_Utilities
Tools >> Routines Command_System CL_Routines
Company Command_System CL_Company_Routines
Financial Command_Financial CL_Financial_Routines
Sales Command_Sales CL_Sales_Routines
Purchasing Command_Purchasing CL_Purchasing_Routines
Inventory Command_Inventory CL_Inventory_Routines
Payroll Command_Payroll CL_Payroll_Routines

INTEGRATION GUIDE 177


PA RT 5 N A V IG A TI O N

Top-level menu Submenu Form Command


Transactions Command_System CL_Transactions
Financial Command_Financial CL_Financial_Transactions
Sales Command_Sales CL_Sales_Transactions
Purchasing Command_Purchasing CL_Purchasing_Transactions
Inventory Command_Inventory CL_Inventory_Transactions
Payroll Command_Payroll CL_Payroll_Transactions
Inquiry Command_System CL_Inquiry
System Command_System CL_System_Inquiry
Financial Command_Financial CL_Financial_Inquiry
Sales Command_Sales CL_Sales_Inquiry
Purchasing Command_Purchasing CL_Purchasing_Inquiry
Inventory Command_Inventory CL_Inventory_Inquiry
Payroll Command_Payroll CL_Payroll_Inquiry
Reports Command_System CL_Reports
System Command_System CL_System_Reports
Company Command_System CL_Company_Reports
Financial Command_Financial CL_Financial_Reports
Sales Command_Sales CL_Sales_Reports
Purchasing Command_Purchasing CL_Purchasing_Reports
Inventory Command_Inventory CL_Inventory_Reports
Payroll Command_Payroll CL_Payroll_Reports
Cards Command_System CL_Cards
System Command_System CL_System_Cards
Financial Command_Financial CL_Financial_Cards
Sales Command_Sales CL_Sales_Cards
Purchasing Command_Purchasing CL_Purchasing_Cards
Inventory Command_Inventory CL_Inventory_Cards
Payroll Command_Payroll CL_Payroll_Cards
Layout* Toolbars Built-in Command cmdToolbarContextMenu
Help* Built-in Command cmdListShellHelpMenu
*We recommend not adding items directly to this top-level menu

178 IN T E G R AT I O N G U ID E
C H A P T E R 2 2 M EN U S I N M I C R O S O F T D Y N A M I C S G P

Viewing the menu structure


To view the menu structure for Microsoft Dynamics GP as well as all of the
integrating products you have installed, you can use the Menu Inquiry Utility
sample that is included with Dexterity. To use this utility, complete the following
procedure:

1. Open the Dynamics.dic dictionary.


With Dexterity, open the Dynamics.dic dictionary.

2. Import an item from a text file.


In the Explorer menu, choose Import From Text File.

3. Select the Menu Inquiry utility file.


Click the lookup button in the Import From Text File window. Using the dialog
displayed, select the syMenuInquiryUtility.form located in the Develop folder
inside the Samples folder for Dexterity.

4. Import the form.


Click Import to import the Menu Inquiry Utility.

5. Compile the form.


Select the form syMenuInquiryUtility in the Resource Explorer. Click Compile
on the toolbar.

6. Start Microsoft Dynamics GP and access the utility.


To access the Menu Inquiry Utility, add the window for the utility to the
Shortcut Bar in Microsoft Dynamics GP. You are adding a window named
Microsoft Dynamics GP Menu Inquiry. It will be found in the Microsoft
Dynamics GP dictionary, in the core that was specified in the Options window
in Dexterity.

Use this information


when determining
where to add menus and
menu items.

7. View the menu information.


Use the tree view at the top of the window to navigate the menu structure. Use
the information at the bottom of the window when adding menus and menu
items to the menu structure.

INTEGRATION GUIDE 179


PA RT 5 N A V IG A TI O N

Adding to Microsoft Dynamics GP menus


We recommend that you add menu items for your integration to only the following
menus:

• Tools submenus for Setup, Utilities, and Routines


• Transactions
• Inquiry
• Reports
• Cards

The other menus are managed by the Microsoft Dynamics GP application, and
should not contain any third-party menu items.

Adding commands
Refer to Part 11, Script Microsoft Dynamics GP provides the AddCommandToMenu() global function that
Reference, for more you will use to add commands to menus. Use the table in the section Menu structure
information about in Microsoft Dynamics GP on page 177 to find the form name and command list
these procedures and (menu or submenu) to which you want to add the command. You will also use the
functions. resourceid() function to look up the resource IDs of the command forms and
commands.

For example, the following code adds the IG_Lead_Maintenance command to the
end of the CL_Sales_Cards command list.

Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
Seq,
3333,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true,
LoadMode);

Notice that the resourceid() function is used to look up the resource IDs of the
commands and command forms accessed, such as the CL_Sales_Cards command
and the Command_Sales form.

Microsoft Dynamics GP also provides the AlreadyExistsOnMenu() function


defined on the syMenuObj form that you will use to determine wether a specific
command has already been added to a menu. This is useful when your integration
is creating the default set of menus, and you want to avoid creating duplicate menu
items.

180 IN T E G R AT I O N G U ID E
C H A P T E R 2 2 M EN U S I N M I C R O S O F T D Y N A M I C S G P

Adding separators
Separarators are a special built-in command that you can add to menus. Like other
commands, you add them using the AddCommandToMenu() function. The
following special constants are used to refer to the separator command:

Constant Description
CMD_BUILTINCMD_DICTID Specifies the ID of the dictionary that contains the separator
built-in command.
CMD_BUILTINCMD_FORMID Specifies the resource ID of the form that defines the
separator built-in command.
cmdSeparator The built-in separator command.

For example, the following code adds a separator to the end of the CL_Sales_Cards
command list.

Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
Seq,
CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdSeparator),
true,
LoadMode);

When you add your menu items, we recommend that you add them to the end of the menu or
submenu. You should also consider using a separator to separate your items from the default
items.

Adding submenus
To add a submenu, you will use the AddCommandToMenu() function to add a
command list command to an existing menu. Once the command list has been
added, use this same function to add commands to the new submenu.

Menu creation procedure


To create the menus for your integrating application, you need to write a procedure
that defines the default set of menu items. This procedure will run in response to a
procedure trigger you will add for the CreateDefaultMenuStructure procedure in
Microsoft Dynamics GP.

Registering the menu creation trigger


The following example shows the registration in the sample integrating application
for the trigger that runs in response to the CreateDefaultMenuStructure procedure
in Microsoft Dynamics GP. When the trigger is activated, the IG_CreateMenuItems
procedure is run.

l_result = Trigger_RegisterProcedure(script CreateDefaultMenuStructure,


TRIGGER_AFTER_ORIGINAL, script
➥ IG_CreateMenuItems);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

INTEGRATION GUIDE 181


PA RT 5 N A V IG A TI O N

Parameters
Your integration will have one procedure that will create the default set of menu
items for the integration. This procedure will run in response to the trigger
registered for the CreateDefaultMenuStructure procedure.

The menu creation procedure has two parameters:

in integer LoadMode;
optional in boolean ShowProgress;

The LoadMode parameter indicates what action the menu creation procedure will
be performing, based on the value passed in through the parameter. It will
correspond to one of the following constants:

Constant Description
MENULOAD_TOTABLE The menu items are being added to the default menu set in the
syMenuMstr table.
MENULOAD_TOMEMORY The menu items are being added directly to the menu set displayed
in Microsoft Dynamics GP.

The ShowProgress parameter is not used.

Execution
The menu creation procedure for your integration will run once when the user logs
into Microsoft Dynamics GP. The LoadMode parameter will correspond to the
MENULOAD_TOTABLE constant, indicating that the menu creation procedure
should examine the default menu items for the integration. If they do not exist, the
menu creation procedure should add them to the default menu set.

If the user has not customized their menu set, the menu creation procedure will be
run again. The LoadMode parameter will correspond to the
MENULOAD_TOMEMORY constant, indicating that the menu creation procedure
should add its default menu items directly to the menu structure in Microsoft
Dynamics GP.

Menu creation example


The following is the menu creation procedure for the sample integrating
application. It creates these default menu items for the sample integration:

• A separator and command to the Cards menu for sales


• A separator and command to the Inquiry menu for sales
• A command to the Reports menu for sales
• A command to the Setup menu for sales
• A toolbar item in the Toolbars submenu for the sample toolbar

For the items added to the Cards and Inquiry menus, the sequence number is set to
0 so the items are added to the end of the specified menu. The other items are added
to specific locations in the menus, using the FindCommandInMenu() function.

If menu items are being added to the default menu set stored in the syMenuMstr
table, the MenusExistForProduct() function is used to verify whether the menu
items already exist. If they do, no items are added. Notice that the LoadMode
parameter passed into the procedure is used within the AddCommandToMenu()
function to load the menu commands appropriately to either the syMenuMstr table
or to the menu set for the current user.

182 IN T E G R AT I O N G U ID E
C H A P T E R 2 2 M EN U S I N M I C R O S O F T D Y N A M I C S G P

in integer LoadMode;
optional in boolean ShowProgress;

local CmdSequence Seq;


local integer Status;
local boolean AddMenuItems;

{Set the flag indicating that menu items should be added}


AddMenuItems = true;

if LoadMode = MENULOAD_TOTABLE then


{Find out whether the menu items exist in the Menu Master table.}

if MenusExistForProduct(IG_PROD_ID) of form syMenuObj = true then


{Do not need to add the menu items}
AddMenuItems = false;
end if;
end if;

if AddMenuItems = true then


{-- Add the Lead Maintenance item to the Cards>>Sales submenu--}
{Add a separator, which is a built-in command}
Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
Seq,
CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdSeparator),
true,
LoadMode);

if Status <> OKAY then


error "Could not add separator item.";
end if;

{Add the IG_Lead_Maintenance command}


Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true,
LoadMode);

if Status <> OKAY then


error "Could not add command IG_Lead_Maintenance.";
end if;

{-- Add the Lead Inquiry item to the Inquiry>>Sales submenu--}


{Add a separator, which is a built-in command}
Seq = 0;

INTEGRATION GUIDE 183


PA RT 5 N A V IG A TI O N

Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Inquiry of form Command_Sales),
Seq,
CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdSeparator),
true,
LoadMode);

if Status <> OKAY then


error "Could not add separator item.";
end if;

{Add the IG_Lead_Inquiry command}


Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Inquiry of form Command_Sales),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Inquiry of form Command_IG_Sample),
true,
LoadMode);

if Status <> OKAY then


error "Could not add command IG_Lead_Maintenance.";
end if;

{Add the Contact History Setup command}


{Find the appropriate location to add the item, after Customer Class}
Seq = FindCommandInMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command RM_Class_Maintenance of form Command_Sales),
LoadMode,
"");
Seq = Seq + 1;

Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History_Setup of form
➥ Command_IG_Sample),
true,
LoadMode);

if Status <> OKAY then


error "Could not add command Contact History Setup.";
end if;

184 IN T E G R AT I O N G U ID E
C H A P T E R 2 2 M EN U S I N M I C R O S O F T D Y N A M I C S G P

{Add the items for the Leads reports}


{Find the appropriate location is the Sales group of the Reports menu}
Seq = FindCommandInMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Reports of form Command_Sales),
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command SOP_Activity_Reports of form Command_Sales),
LoadMode,
"");
Seq = Seq + 1;

Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Reports of form Command_Sales),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Reports of form Command_IG_Sample),
true,
LoadMode);

if Status <> OKAY then


error "Could not add command IG Lead Reports.";
end if;

{Add the item to display the sample toolbar}


{Find the appropriate location of the Custom toolbar item}
Seq = FindCommandInMenu(CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdToolbarContextMenu),
DYNAMICS,
resourceid(form Command_System),
resourceid(command Toolbar_Custom of form Command_System),
LoadMode,
"");

Status = AddCommandToMenu(CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdToolbarContextMenu),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command Toolbar_IGSample of form Command_IG_Sample),
true,
LoadMode);

if Status <> OKAY then


error "Could not add command Toolbar-IGSample.";
end if;
end if;

INTEGRATION GUIDE 185


186 IN T E G R AT I O N G U ID E
Chapter 23: Toolbars in Microsoft Dynamics GP
Toolbars provide an additional method of navigation within Microsoft Dynamics
GP. Items that appear on the toolbars are typically shortcuts to items that appear in
the menus. You can create toolbars for your integrations. You can also add
commands to existing Microsoft Dynamics GP toolbars. Information about toolbars
is divided into the following sections:

• Toolbar overview
• Toolbar implementation
• Toolbars in Microsoft Dynamics GP
• Adding to Microsoft Dynamics GP toolbars
• Toolbar creation procedure

Toolbar overview
Toolbars display groups of commands in the form of a toolbar. The toolbars in
Microsoft Dynamics GP are created dynamically each time a user logs into the
accounting system. Security settings and user preferences control what items
appear on each toolbar. Each user can customize the toolbars to have their own
specific arrangement.

You can add items to existing Microsoft Dynamics GP toolbars. You can also create
new toolbars for your integrating application. For example, the following toolbar is
defined in the sample integrating application:

This toolbar is defined for


the sample integrating
application.

You will create commands for the items in your integration that you want to appear
on toolbars. These same commands will typically be used for menu navigation as
well. Refer to Chapter 21, “Commands,” for more information about creating
commands for your integration. Code in your integrating application will add the
commands to the appropriate locations for each toolbar.

Toolbar implementation
A default toolbar configuration is stored by Microsoft Dynamics GP. Each user
begins with a copy of this default configuration, which they can customize to meet
their needs. When a user logs into the system, their personal toolbar configuration is
used.

When you add toolbars and toolbar items, you will add them to the default
configuration. The items you add can also be replicated for each user defined in the
system, allowing all users to have access to the toolbars and toolbar commands.

It’s important that you add your toolbars and toolbar items for your integration
only once. You should not add items each time Microsoft Dynamics GP is launched.
Use the ExistsForUserID() function in Microsoft Dynamics GP to verify whether
toolbars have been defined for your product. Use the ButtonsExistForProduct()
function to verify whether toolbar items have been defined for your products.

INTEGRATION GUIDE 187


PA RT 5 N A V IG A TI O N

Toolbars in Microsoft Dynamics GP


Several toolbars are predefined in the Microsoft Dynamics GP application. The
following table lists them. You will use this information if you add items to them for
your integration.

Toolbar Form Command list


Custom Command_System Toolbar_Custom
Main Command_System Toolbar_Main
Financial Command_System Toolbar_Financial
HRPayroll Command_System Toolbar_HRPayroll
Inventory Command_System Toolbar_Inventory
Manufacturing Command_System Toolbar_Manufacturing
Project Command_System Toolbar_Project
Purchasing Command_System Toolbar_Purchasing
Sales Command_System Toolbar_Sales
Standard Command_System Toolbar_Standard

Adding to Microsoft Dynamics GP toolbars


Refer to Part 11, Script We recommend that you limit the number of items you add to the predefined
Reference, for more Microsoft Dynamics GP toolbars. If you have more than one or two items to display
information about on the toolbar, consider defining your own toolbar and adding the items to it.
these procedures and
functions. Toolbar items are typically shortcuts to items defined in the application’s menus. Avoid
adding toolbar items without a corresponding menu items.

Adding commands
Microsoft Dynamics GP provides the AddCommandToCmdBar() global function
that you will use to add commands to toolbars. Use the table in the section Toolbars
in Microsoft Dynamics GP on page 188 to find the form name and command list for
the toolbar to which you want to add the command. You will also use the
resourceid() function to look up the resource IDs of the command forms and
commands.

For example, the following code adds the IG_Lead_Maintenance command to the
end of the Sales toolbar.

Seq = 0;
status = AddCommandToCmdBar(DYNAMICS,
resourceid(form Command_System),
resourceid(command Toolbar_Sales of form Command_System),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true,
MENULOAD_TOTABLE);

Notice that the resourceid() function is used to look up the resource IDs of the
commands and command forms accessed, such as the Toolbar_Sales command and
the Command_System form.

188 IN T E G R AT I O N G U ID E
C H A P T E R 2 3 T O O L B AR S I N M I C R O S O F T D Y N A M I C S G P

Adding separators
Separarators are a special built-in command that you can add to toolbars. Like other
commands, you add them using the AddCommandToCmdBar() function. The
following special constants are used to refer to the separator command:

Constant Description
CMD_BUILTINCMD_DICTID Specifies the ID of the dictionary that contains the separator
built-in command.
CMD_BUILTINCMD_FORMID Specifies the resource ID of the form that defines the
separator built-in command.
cmdSeparator The built-in separator command.

For example, the following code adds a separator to the end of the Sales toolbar,
defined by the Toolbar_Sales command list.

Seq = 0;
Status = AddCommandToCmdBar(DYNAMICS,
resourceid(form Command_System),
resourceid(command Toolbar_Sales of form Command_System),
Seq,
CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdSeparator),
true,
MENULOAD_TOTABLE);

Toolbar creation procedure


To create a toolbar for your integrating application, you need to define a command
list that will contain the toolbar items. You must also write a procedure that defines
the toolbar. This procedure runs in response to a trigger you will add for the
CreateDefaultCommandBars procedure in Microsoft Dynamics GP. You will also
write a procedure that defines the commands that will appear on the toolbar. This
procedure runs in response to a trigger you will add for the
CreateDefaultCmdBarButtons procedure in Microsoft Dynamics GP.

Toolbar command list


Each toolbar displayed in Microsoft Dynamics GP has a command list defined that
contains the items shown on the toolbar. You will create a command list (command
resource) for your toolbar that will contain the items displayed by the toolbar.
Define the toolbar command list on the command form that contains the other
commands used for your integration.

For example, the sample integrating application defines the


CL_IG_Sample_CMDBAR command on the Command_IG_Sample form. This
command list will contain the commands displayed by the toolbar for the sample
integration.

INTEGRATION GUIDE 189


PA RT 5 N A V IG A TI O N

Registering the toolbar creation triggers


The following example shows the registration in the sample integrating application
for the trigger that runs in response to the CreateDefaultCommandBars procedure
in Microsoft Dynamics GP. When the trigger is activated, the IG_CreateToolbars
procedure is run.

l_result = Trigger_RegisterProcedure(script CreateDefaultCommandBars,


➥ TRIGGER_AFTER_ORIGINAL, script IG_CreateToolbars);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The following example shows the registration in the sample integrating application
for the trigger that runs in response to the CreateDefaultCmdBarButtons procedure
in Microsoft Dynamics GP. When the trigger is activated, the
IG_CreateToolbarItems procedure is run.

l_result = Trigger_RegisterProcedure(script
➥ CreateDefaultCmdBarButtons, TRIGGER_AFTER_ORIGINAL, script
➥ IG_CreateToolbarItems);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

Trigger processing procedures


This is the trigger The following is the IG_CreateToolbars procedure for the sample integrating
processing procedure application. It runs in response to the trigger for the CreateDefaultCommandBars
that creates the new procedure. It uses the ExistsForUserID() function in Microsoft Dynamics GP to
toolbar. verify whether a toolbar has already been added for the default set. If one hasn’t, it
uses the AddCommandBar() function to add the toolbar and clone it for each user.
local integer status;
local integer pos;

{Add command bar only if it doesn't exist for the user}


if ExistsForUserID("",
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample)) of
➥ form syCmdBarObj = true then
abort script;
end if;

{Add the toolbar and clone for each user who has toolbars}
pos = 0; {Place at the beginning of the row}
status = AddCommandBar("",
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
true, {visibility}
2, {row number}
pos, {position}
true) of form syCmdBarObj;

190 IN T E G R AT I O N G U ID E
C H A P T E R 2 3 T O O L B AR S I N M I C R O S O F T D Y N A M I C S G P

The following is the toolbar command creation procedure for the sample integrating
application. It runs in response to the trigger for the CreateDefaultCmdBarButtons
procedure. The trigger processing procedure uses the ButtonsExistForProduct()
function to find whether commands have already been added to the toolbar. If they
have not, it uses the AddCommandToCmdBar() function to add two items that will
appear on the toolbar.

This is the trigger local integer status;


processing procedure local integer Seq;
that creates the toolbar
{Add default items to the toolbar if they don't already exist}
commands that will
if ButtonsExistForProduct(IG_PROD_ID) of form syCmdBarBtnObj = true then
appear on the new
abort script;
toolbar.
end if;

Seq = 1;
status = AddCommandToCmdBar(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true, {available for all users}
MENULOAD_TOTABLE);

increment Seq;
status = AddCommandToCmdBar(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Inquiry of form Command_IG_Sample),
true, {available for all users}
MENULOAD_TOTABLE);

Toolbar menu item


Access to toolbars is controlled through the Toolbars context menu that is accessed
through the Layout menu. The Toolbars context menu can also be accessed by right-
clicking in the toolbar area in Microsoft Dynamics GP. Add an entry to the Toolbars
context menu for each toolbar you create to allow the user to hide or show it.

Each toolbar you create


should have an item in
the Toolbars submenu.

INTEGRATION GUIDE 191


PA RT 5 N A V IG A TI O N

Create a command for the item to add to the Toolbars context menu, just as you
would any other command for your integration. The Toolbars context menu is a
built-in command defined by Dexterity. For example, the Toolbar_IGSample
command (a script command) is defined in the Command_IG_Sample command
form for sample integrating application. The command is added to the the Toolbars
context menu to control access to the sample toolbar.

Typically, the menu item is added by the same procedure used to add the other
menu items for your integraiton. For example, the following is a portion of the
IG_CreateMenuItems procedure in the sample integration. It adds the command for
the sample toolbar to the Toolbars context menu.
{Add the item to display the sample toolbar}
{Find the appropriate location of the Custom toolbar item}
Seq = FindCommandInMenu(CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdToolbarContextMenu),
DYNAMICS,
resourceid(form Command_System),
resourceid(command Toolbar_Custom of form Command_System),
LoadMode,
"");

Status = AddCommandToMenu(CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdToolbarContextMenu),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command Toolbar_IGSample of form Command_IG_Sample),
true,
LoadMode);

The script attached to the command performs two actions when the item is chosen
from the Toolbars context menu. It retrieves the tags for the menu item and the
toolbar the command is controlling. It uses these tags to toggle the state of the
toolbar and the check mark for the menu item. The following is the script for the
Toolbar_IGSample command for the sample integration.

local integer nMenuTag, nCmdBarTag, nStatus;

nMenuTag = Command_GetTag(command Toolbar_IGSample);


nCmdBarTag = Command_GetTag(command CL_IG_Sample_CMDBAR);

nStatus = ToggleCommandBar(nMenuTag, nCmdBarTag) of form syCmdBarObj;

Toolbar menu state


When Microsoft Dynamics GP is started, it will automatically display the toolbars
that the user had displayed when they last ran the application. Code for your
integration must set the state of the toolbar menu item to be checked or unchecked,
depending on whether the toolbar is currently displayed. You will use a trigger for
the LoadCommandBars procedure in Microsoft Dynamics GP, which will set the
Toolbar menu item state for your toolbar. The following example is the trigger
registration that creates the trigger which will update the state for the sample
toolbar menu item.

192 IN T E G R AT I O N G U ID E
C H A P T E R 2 3 T O O L B AR S I N M I C R O S O F T D Y N A M I C S G P

l_result = Trigger_RegisterProcedure(script LoadCommandBars,


TRIGGER_AFTER_ORIGINAL, script IG_SetToolbarMenuState);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The following is the IG_SetToolbarMenuState procedure that runs in response to


this trigger. It uses the CmdBarIsVisible() function to find out whether the toolbar
is displayed. The checked property of the menu item is set accordingly.

local boolean visible;


local integer tag;

{Get the visible state of the sample toolbar}


visible = CmdBarIsVisible('User ID' of globals,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample))
➥ of form syCmdBarObj;

{Set the menu item appropriately}


if visible = true then
{Mark the menu item}
tag = Command_GetTag(command Toolbar_IGSample of form Command_IG_Sample);
Command_SetBooleanProperty(tag, COMMAND_PROP_CHECKED, true);
end if;

INTEGRATION GUIDE 193


194 IN T E G R AT I O N G U ID E
Chapter 24: Navigation Pane Categories and Area
Pages
The Navigation pane in Microsoft Dynamics GP has several predefined categories.
Each category contains links to the area page and lists for that category. When
possible, you should add items to the predefined categories. You can add additional
categories to the Navigation pane. If you add a new category, you must also define
the Area Page and lists for the category.

Microsoft Dynamics GP can have a maximum of 20 Navigation pane buttons.

Information about defining a Navigation Pane category and Area Page is divided
into the following sections:

• Area Page
• Navigation pane category

Area Page
The first item in each Navigation pane category is a link to the Area Page for that
category. The Area Page displays links that allow the user to navigate to various
windows and reports that are part of the category.

Area Page command


A command is used to define the Area Page content for a Navigation pane category.
Typically, you will add the command for the Area Page to the same command form
that you are using for the other commands in your integration. Refer to Chapter 21,
“Commands,” for more information about commands for an integrating
application.

The command used for the Area Page should have the following characteristics:

Command Name The command name should indicate that the command is
being used for an area page. For instance, the command for the sample integrating
application is named AreaPage_IGSample.

Display Name This name is used for the text of the Area Page link that appears
in the Navigation Pane.

Type The command type must be set to Script. The script defines what items are
displayed in the Area Page. Details of this script are found in the next section.

Image Type This should be set to Icon.

Normal Image This should be set to AreaPage.

Area Page content


The content of the Area Page is defined by the script attached to the command used
for it. You will use procedures described in Area Page scripts on page 493 to create
the content for the Area Page. The command script performs the following actions:

• Hides the link to customize the Home page.


• Creates the XML document used for the Area Page.
• Adds content areas for the Area Page.

INTEGRATION GUIDE 195


PA RT 5 N A V IG A TI O N

• Adds commands and command lists for items that appear on the page.
• Displays the Area Page.
The following example shows the code for command that defines the sample Area
Page in the sample integrating application.

local AreaPageXMLState XMLState;

call Command_HideAndDisable, command CustomizeHomePage of form


Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";

{Add items if needed}


if not empty(XMLState:XMLDoc) then
{Cards}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(9823) {Cards}, IMAGE_CARDS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Lead_Maintenance of form Command_IG_Sample;

{Reports}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(451) {Reports}, IMAGE_REPORTS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Reports
➥ of form Command_IG_Sample;

{Inquiry}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(4426) {Inquiry}, IMAGE_INQUIRY of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Inquiry
➥ of form Command_IG_Sample;

{Setup}
call AddContentArea of form syAreaPageXML, XMLState, getmsg(860) {Setup},
➥ IMAGE_SETUP of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Contact_History_Setup of form Command_IG_Sample;
end if;

{Display the Area Page}


call Display of form syAreaPageXML, XMLState;

Navigation pane category


The Navigation pane category is defined by a command that you add to your
integration. You will register triggers to add the Navigation Pane category and its
content.

Navigation pane command list


A command list is used to define the Navigation Pane category. Typically, you will
add the command list for the Navigation pane to the same command form that you
are using for the other commands in your integration. The command list should
have the following characteristics:

196 IN T E G R AT I O N G U ID E
C H A P T E R 2 4 N A V IG A TI O N P A N E C A T EG O R I E S A N D A R E A P A G E S

Command Name The command name should indicate that the command is
being used for a Navigation pane category. For instance, the command for the
sample integrating application is Navigation_IGSample.

Display Name This name is used for the button in the Navigation Pane.

Type The command type must be set to Command List.

Image Type This should be set to Icon.

Normal Image This should be set to an image that represents the Navigation
pane category.

Toolbar Item Options This should be set to Image + Text.

Adding the Navigation pane category


To add the Navigation pane category, you will register a procedure trigger for the
CreateDefaultNavBarButtons procedure. The trigger processing procedure verifies
whether the Navigation pane category already exists. If it doesn’t, the category is
added.

The following example is a portion of the Startup script for the sample integrating
application. It registers the trigger for the CreateDefaultNavBarButtons procedure.
l_result = Trigger_RegisterProcedure(script CreateDefaultNavBarButtons,
➥ TRIGGER_AFTER_ORIGINAL, script IG_CreateNavigationBarButton);
if l_result <> SY_NOERR then
warning "Trigger registration for CreateDefaultNavBarButtons failed.";
end if;

The following is the trigger processing procedure that adds the Navigation pane
category for the sample integrating application. It uses the AddNavBarButton()
function to add the new category, but only if categories haven’t been added already.
local string sWhere;
local integer nStatus, nSeq;

sWhere = physicalname('CmdParentDictID' of table syNavBarButtons) + CH_SPACE


+ CH_EQUAL + CH_SPACE + str(IG_PROD_ID);

{Find out whether the Navigation pane categories for this product have already
been added}
range clear table syNavBarButtons;
range table syNavBarButtons where sWhere;
get first table syNavBarButtons;
if err() = OKAY then
abort script;
end if;

nSeq = 0;
{Add the button to navigation}
nStatus = AddNavBarButton("",
nSeq,
true,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command Navigation_IGSample of form Command_IG_Sample),
0, 0, 0,
true) of form syNavBarBtnObj;

INTEGRATION GUIDE 197


PA RT 5 N A V IG A TI O N

Defining Navigation Pane content


To add the content of the new Navigation pane category, you will register a
procedure trigger for the CreateDefaultNavButtonMenuStructure procedure. The
trigger processing procedure adds links for the Area Page and lists that appear in
the Navigation pane. Adding items to the Navigation pane is similar to adding
them to any other menu in Microsoft Dynamics GP.

The following example is a portion of the Startup script for the sample integrating
application. It registers the trigger for the CreateDefaultNavButtonMenuStructure
procedure.

l_result = Trigger_RegisterProcedure(script
CreateDefaultNavButtonMenuStructure, TRIGGER_AFTER_ORIGINAL, script
IG_CreateNavigationBarItems);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for
CreateDefaultNavButtonMenuStructure failed.";
end if;

The following is the trigger processing procedure that adds the items to the new
Navigation pane for the sample integrating application. It adds the Area Page and
the Leads list to the navigation.

in integer nLoadMode;
optional in boolean fShowProgress = false;

local CmdSequence nSeq;


local integer nStatus;

{Add Area Page}


nSeq = 1;
nStatus = AddCommandToMenu(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command Navigation_IGSample of form Command_IG_Sample),
nSeq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command AreaPage_IGSample of form Command_IG_Sample),
false,
nLoadMode);

{Add Leads Card List}


nSeq = nSeq + 1;
nStatus = AddCommandToMenu(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command Navigation_IGSample of form Command_IG_Sample),
nSeq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command ListObj_Leads of form Command_IG_Sample),
false,
nLoadMode);

198 IN T E G R AT I O N G U ID E
Chapter 25: Shortcuts
The Navigation pane in Microsoft Dynamics GP has a Shortcuts area that allows the
user to create shortcuts for navigation. Your integrating applications can add
shortcuts to the Navigation pane. Information about adding shortcuts is divided
into the following sections:

• Adding Shortcuts
• Restricting shortcuts

Adding Shortcuts
All of the functions and constants used to add items to the Shortcut Bar are part of
the syScBarObj form. When you use these functions or constants, you will need to
use the “of form” qualifier to indicate they are part of the syScBarObj form.

For details about the If an integrating application adds shortcuts, it typically does so during installation.
functions used for For example, the following code is an optional part of the installation procedure
shortcuts, refer to used for the sample integrating application.
Shortcut scripts on
page 623. if ask("Do you want to add shortcuts for the sample integrating application?",
➥ "Yes","No","") = ASKBUTTON1 then
{Add shortcuts for every user in the system.}
get first table SY_Users_MSTR;
while err() <> EOF do
call IG_Add_Shortcuts, 'User ID' of table SY_Users_MSTR;
get next table SY_Users_MSTR;
end while;
end if;

This code displays a dialog, asking whether shortcuts should be added. If the user
clicks Yes, the IG_Add_Shortcuts procedure is run. This procedure adds shortcuts
for two of the forms in the sample integrating application.

Name: IG_Add_Shortcuts

in string UserID;

local boolean result;


local integer node_id;
local integer res_id;

{Add the "Sample" folder to the Shortcut Bar.}


node_id = ScBar_AddFolder(scgPERSONAL of form syScBarObj, UserID, 0,
➥ "Sample") of form syScBarObj;

{Add the additional shortcuts.}


res_id = Resource_GetID(IG_PROD_ID, 2, "IG_Lead_Maintenance");
result = ScBar_AddDexForm(scgPERSONAL of form syScBarObj, UserID,
➥ node_id, "Lead Maintenance", res_id, IG_PROD_ID) of form syScBarObj;
res_id = Resource_GetID(IG_PROD_ID, 2, "IG_Lead_Inquiry");
result = ScBar_AddDexForm(scgPERSONAL of form syScBarObj, UserID,
➥ node_id, "Lead Inquiry", res_id, IG_PROD_ID) of form syScBarObj;

INTEGRATION GUIDE 199


PA RT 5 N A V IG A TI O N

Restricting shortcuts
Users can add shortcuts to windows by choosing Current Window or Other
Window from the Add menu on the Navigation pane. In some cases, you may not
want the user to be able to add an item as a shortcut. You can add a form-level
constant to control how the form can be added as a shortcut.

To control the shortcut behavior for a form, define a constant with the following
name:

~SHORTCUT~

The integer value of this contant specifies whether a shortcut can be created if it’s
the current form, or if the form will appear in the Add Other Windows list. The
following table lists the possible values:

Value Add Current Window Add Other Windows


0 No No
1 Yes No
2 No Yes
3 Yes Yes

If a form does not have any auto-open windows, it cannot be added as a shortcut.

200 IN T E G R AT I O N G U ID E
PART 6: LISTS
Part 6: Lists
Use the information in this portion of the documentation to learn about using lists
in your Microsoft Dynamics GP integration. The following is a list of the topics
discussed, along with a brief explanation of each:

• Chapter 26, “List Overview,” describes lists in Microsoft Dynamics GP and how
you can use them for your integration.

• Chapter 27, “Action Pane,” explains how to add actions to lists in Microsoft
Dynamics GP.

• Chapter 28, “Information Pane,” explains how to add content to the information
displayed for the item selected in the list.

• Chapter 29, “Card Lists,” describes how to create a card list for your integration.

• Chapter 30, “Transaction Lists,” describes how to create a transaction list for
your integration.

• Chapter 31, “Report Lists,” explains how to integrate with the Report List in
Microsoft Dynamics GP.

202 IN T E G R AT I O N G U ID E
Chapter 26: List Overview
The various lists in Microsoft Dynamics GP provide an efficient method of
navigation, and allow users to easily perform common tasks. You can integrate with
existing lists, or define your own lists for your integration. Information about lists is
divided into the following sections:

• List features
• List types
• Categories and navigation
• Opening lists by using code
• List Debugging Tools

List features
List in Microsoft Dynamics GP provide several features that make them easy to use.
Any list windows you create will also have these features.

Customization
Lists have many customization capabilities available. These include:

• Configurable columns
• Content display options
• Action Pane organization

Any lists you create or extend with customizations will be configurable through the
customization options.

Actions
Each list has an Action Pane at the top that displays the predefined actions that can
be performed for items the user has marked in the list.

Integrating applications can add actions to existing lists in Microsoft Dynamics GP.
They will also define actions for their own lists.

Search and filtering


Users can search for items in the list by entering a search keywork in the Find field.
The entire content of the list is searched, and only those records that match the
search criteria are displayed. Users can also create sets of filter criteria that limit the
amount of information displayed in the list.

INTEGRATION GUIDE 203


PA RT 6 LI ST S

List types
Three types of lists are available in Microsoft Dynamics GP to display data.

Card lists
Card lists are used to view card items, such as customers, vendors, or accounts.

Transaction lists
Transaction lists are used to view date-sensitive information, such as payables
transactions or receivables transactions.

204 IN T E G R AT I O N G U ID E
C H A P T E R 2 6 L I S T O V E R V I E W

Report lists
Report lists are used to organize and generate reports for the data managed by
Microsoft Dynamics GP.

Categories and navigation


Lists are accessed through the Navigation Pane on the left side of the Microsoft
Dynamics GP main window.

Lists are accessed


through the Navigation
Pane.

INTEGRATION GUIDE 205


PA RT 6 LI ST S

The various types of lists are divided into the following categories:

• Financial
• Sales
• Purchasing
• Administration
• Inventory
• Human Resources and Payroll
• Manufacturing
• Project
• Field Service

If you create new lists for your integration, you will have to assign them to one of
these categories. You could also create your own category. Refer to Chapter 24,
“Navigation Pane Categories and Area Pages,” for details about how to do this.

Opening lists by using code


Typically, lists are opened by the user choosing an item in the Navigation Pane on
the left side of the Microsoft Dynamics GP main window. You can also open lists by
using sanScript code.

When a user opens a list through the Navigation Pane, the list content is displayed
in the main window. When a list is opened through code, it can be displayed in the
main window or in a separate window for the list. Restrictions can also be passed to
the list to restrict the information being displayed.

Opening a list
Microsoft Dynamics GP can display one card list, one trasaction list, and one report
list at a time. The lists can be in either the main Microsoft Dynamics GP window or
in a separate window. To open a list, use the List_Open procedure of the syListObj
form.

The List_Open procedure must always be called with the background keyword to prevent
conflicts with other list code that may be running.

Before you open a list using sanScript code, you must verify that a list of that type is
not already open. If a list of the specified type is already open, your code should
display a message indicating this to the user.

Opening a card list The following example shows how to verify whether a card list is already open. If
one is not, a specific card list can be opened.
local boolean list_is_open;
local string list_name;

{Assume that a list of the specified type is not open.}


list_is_open = false;

if isopen(form syCardList) then


if (ListObjState:IsCreated of window CardList of form syCardList) then

{A list is already open. Tell the user which list to close.}


call GetListPropertiesForListID of form syListObj,
GetListDictID(ListObjState of window CardList of form syCardList)
➥ of form syListObj,
GetListID(ListObjState of window CardList of form syCardList) of
➥ form syListObj, none, list_name;

206 IN T E G R AT I O N G U ID E
C H A P T E R 2 6 L I S T O V E R V I E W

{Set the flag indicating the list is open.}


list_is_open = true;

{Display a message indicating the situation for the user.}


warning "You need to close the list: " + list_name;
end if;
end if;

if list_is_open = false then


{Call to open list using the List_Open procedure}
end if;

Opening a transaction The following example shows how to verify whether a transaction list is already
list open. If one is not, a specific transaction list can be opened.

local boolean list_is_open;


local string list_name;

{Assume that a list of the specified type is not open.}


list_is_open = false;

if isopen(form syTrxList) then


if (ListObjState:IsCreated of window TrxList of form syTrxList) then

{A list is already open. Tell the user which list to close.}


call GetListPropertiesForListID of form syListObj,
GetListDictID(ListObjState of window TrxList of form syTrxList) of
➥ form syListObj,
GetListID(ListObjState of window TrxList of form syTrxList) of
➥ form syListObj, none, list_name;

{Set the flag indicating the list is open.}


list_is_open = true;

{Display a message indicating the situation for the user.}


warning "You need to close the list: " + list_name;
end if;
end if;

if list_is_open = false then


{Call to open list using the List_Open procedure}
end if;

Opening a report list The following example shows how to verify whether a report list is already open. If
one is not, a specific report list can be opened.

local boolean list_is_open;


local string list_name;

{Assume that a list of the specified type is not open.}


list_is_open = false;

if isopen(form syReportList) then


if (ListObjState:IsCreated of window ReportList of form syReportList)
➥ then

INTEGRATION GUIDE 207


PA RT 6 LI ST S

{A list is already open. Tell the user which list to close.}


call GetListPropertiesForListID of form syListObj,
GetListDictID(ListObjState of window ReportList of form
➥ syReportList) of form syListObj,
GetListID(ListObjState of window ReportList of form syReportList)
➥ of form syListObj, none, list_name;

{Set the flag indicating the list is open.}


list_is_open = true;

{Display a message indicating the situation for the user.}


warning "You need to close the list: " + list_name;
end if;
end if;

if list_is_open = false then


{Call to open list using the List_Open procedure}
end if;

Retrieving restriction parameters


If you use the optional restriction parameters for the List_Open procedure, you will
need to retrieve them to use when processing the content for the list being opened.
Typically, they are retrieved and used in the Refresh procedure for the list.

The restriction parameters for the List_Open procedure are optional. They can be used in
addition to the standard restrictions defined for lists.

If you supply the restriction parameters for the List_Open procedure, their values
will be temporarily stored as properties for the command that is used to add the list
to the Microsoft Dynamics GP navigation. For instance, the command named
ListObj_Leads is defined to open the Leads sample card list. If the List_Open
procedure is used to open the Leads card list, and the optional restriction
parameters are supplied, they will be temporarily stored with the List_Obj_Leads
command.

You can retrieve the property values from the list command by using the
Command_GetNamedProperty() function. The following table lists the constants
defined in the syListObj form that correspond to the named properties that will be
set for the command used to open the list.

Constant Description
NAMEDPROP_RESTRICTIONTYPE The optional integer restriction parameter.
NAMEDPROP_RESTRICTIONSTRING1 The first string restriction parameter.
NAMEDPROP_RESTRICTIONSTRING2 The second string restriction parameter.

208 IN T E G R AT I O N G U ID E
C H A P T E R 2 6 L I S T O V E R V I E W

The following example shows how these named properties are retrieved for the
Leads card list in the sample integrating application.

local string restriction_integer;


local string restriction_string1;
local string restriction_string2;

restriction_integer = Command_GetNamedProperty(tag, NAMEDPROP_RESTRICTIONTYPE


➥ of form syListObj);
restriction_string1 = Command_GetNamedProperty(tag,
➥ NAMEDPROP_RESTRICTIONSTRING1 of form syListObj);
restriction_string2 = Command_GetNamedProperty(tag,
➥ NAMEDPROP_RESTRICTIONSTRING2 of form syListObj);

List Debugging Tools


When adding a list to Microsoft Dynamics GP, you may want to use the List
Debugging Tools that are included in the Dynamics.dic dictionary. to help resolve
problems. The List Debugging Tools consist of several windows that provide
detailed information about the internal structure of the list that is being displayed.
To use the List Debugging Tools, complete the following procedure.

1. Enable script debugging for the Microsoft Dynamics GP runtime.


In the Dex.ini file for the Microsoft Dynamics GP installation, add the following
entry to enable script debugging for the Microsoft Dynamics GP runtime:

ScriptDebugger=TRUE

2. Start Microsoft Dynamics GP and log in to the system.

3. Display the list that you want to debug.

4. Open the List Debugging Tools.


In the menu for the list, choose Debug to open the List Debugging Tools
window.

INTEGRATION GUIDE 209


PA RT 6 LI ST S

5. View details about the list.


The List Debugging Tools window shows basic information about the list
currently active in Microsoft Dynamics GP. Use the buttons at the bottom of the
window to see additional information about the list. The composite information
and list cache information will be especially helpful when troubleshooting lists.

210 IN T E G R AT I O N G U ID E
Chapter 27: Action Pane
The Action Pane for a list provides access to the various tasks that can be performed
for items in the list. Your Microsoft Dynamics GP integration can contain actions
that are added to the Action Pane for existing card lists, transaction lists, or report
lists. You will also define the actions for any new lists you create. Information about
actions is divided into the following sections:

• Action ID
• Commands for the Action Pane
• Command scripts
• Adding to the Action Pane
• Registering actions and groups
• Checking action access
• Verifying an action
• Executing an action
• Performing actions for marked rows
• Logging action status
• Acting on action errors

Action ID
Each action you create has an action ID, which is a long integer value that uniquely
identifies the action. For each action you are defining, assign a unique integer value
that identifies the action. Create constants for each action to make them easier to
manage in your code.

Refer to Part 11, Script Since multiple third-party products can add actions to Microsoft Dynamics GP lists,
Reference, for the ID of the product that defines the action must be encoded into the action ID. The
detailed descriptions of BuildDictSpecificID() function is used to encode an action value and product ID
the functions and into a single long integer action ID. You can use this function to determine the value
procedures used for you should assign to the constant you are creating for each action. This function
list actions. takes a dictionary ID and the numeric value of the action, and returns an encoded
value based on them.

For example, the following constant for the sample integrating application defines
the action that opens the Contact History window.

ACTION_CONTACT_HISTORY: 1

The Expressions window available within Dexterity can be used to determine the
encoded value for this action. Simply type the name and parameters for the
BuildDictSpecificID() function and click Evaluate to see the encoded value. For
example, the following illustration shows the encoded ID for the Contact History
action.

INTEGRATION GUIDE 211


PA RT 6 LI ST S

Notice how the product ID (in this case 3333) is used for the function. An additional
constant for the action is defined for the encoded value:

ACTION_CONTACT_HISTORY_ENCODED: 218431489

When a user chooses the action for a list, your code that processes the request will
use the DisassembleDictSpecificID procedure to extract the product ID and the
integer value assigned to the action. If it’s an action for your product, you will
perform the appropriate actions. If it’s not an action for your product, your code
should simply ignore it.

If you are defining actions for your own list windows, it is not necessary to encode the
product ID into your action IDs. The product is already known.

Commands for the Action Pane


The groups and actions displayed in the Action Pane correspond to command
resources defined in the application. Command lists are used for groups, while
commands are used for the individual actions. You will define a command for each
new group or action you create. For actions and groups you add to Microsoft
Dynamics GP lists, you will typically define the commands on the command form
for your integration. If you’re creating your own list, you will define the commands
on the form used for the list.

The form that contains the commands you are adding must be open before the Action Pane is
displayed. If it isn’t, the commands won’t appear on the action pane.

When defining the commands used for the Action Pane, be sure to specify the
additional “ribbon” properties that indicate how the command or command list
should appear when displayed. The following Ribbon Item Properties are available
in the Command Definition window:

Button Size Specifies the initial size of the button displayed in the Action Pane
for the command. The following table lists the available sizes:

Button size Example


Small

Large

Button Type Specifies the type of action the button will perform. Set the type to
Action Button if the button will simply perform an action on the marked list items.
Set the type to Drop Dialog if the button will first display a drop dialog that allows
the user to confirm the action to be performed.

212 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

Layout Priority Specifies the preferred initial location of the button for the
command or command list. The following table lists the available locations and uses
the thick dashed outline to show where each appears within a group in the Action
Pane:

Layout priority Example


Primary

Secondary

Force Overflow

You must also specify the image to use for the action or group. The actions always
display an image. Groups display an image when they are in the collapsed state.
Typically, icon resources are used for the image display by an action or group. The
following table lists the icon resources that are used for the standard actions and
groups in Microsoft Dynamics GP. These icon resources have already been defined
in the Dynamics.dic dictionary. You should use these images when appropriate for
any groups or actions you define.

Type Item Icon name


Actions Delete Delete
Edit Edit
Post Post
Print Print
New New
New - document NewDocument
New - record NewRecord
New - report NewReport
View View
View - record ViewRecord
Groups Actions ActionMenu
Go To ExternalShortcut
Modify Edited
New Starburst
Reports HomePageMyReports
Restrictions Restrictions

INTEGRATION GUIDE 213


PA RT 6 LI ST S

Command scripts
When an action is chosen in the Action Pane, the script for the action’s command
will be run. Typically, the command script will call the ExecuteListAction
procedure of the appropriate form listed in the following table:

List type Form


Card list syCardList
Transaction list syTrxList
Report list syReportList

The call will pass the encoded action ID indicating the action to run.

For example, the following is the script for the Contact History command for the
sample integrating application. This command was added as an action for the
Customers card list. Notice how the encoded action ID is passed, and that the
ExecuteListAction procedure for the syCardList is being called.

{Need to use the command ID with the product ID and command number encoded}
call ExecuteListAction of form syCardList, ACTION_CONTACT_HISTORY_ENCODED;

In some cases, you may want to have the user verify the action before it is
performed. You will learn more about this in Verifying an action on page 219.

The code needed to process an action can be extensive. The command script simply
starts the process. You will learn more about the details of processing an action in
Executing an action on page 220.

Adding to the Action Pane


The Action Pane for a list is initially built the first time the list is opened. This is the
default layout for the Action Pane. Users can customize the Action Pane for the
additional list views they create. How you add actions to the Action Pane depends
on whether you are adding actions to your own list or to an existing Microsoft
Dynamics GP list.

The data for each action is stored in the sy07240 table in the DYNAMICS database.
As you add actions, you may need to reset the actions that appear for a list. To do
this, you will need to delete the appropriate rows from the sy07240 table.

Adding actions and groups to your list


If you are creating your own list, you will add items to the Action Pane using one of
the procedures provided for the list. For card lists, this is described in Action Pane on
page 259. For transaction lists, this is described in Action Pane on page 296.

Adding actions and groups to a Dynamics GP list


If you are adding your actions to a Microsoft Dynamics GP list, you will register a
trigger for the TRIGGER_LoadRibbonData procedure of form syListObj. The trigger
processing procedure will add your actions to the Action Pane for a specific list.

214 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

The following example is a portion of the Startup script for the sample integrating
application. It registers the trigger for the TRIGGER_LoadRibbonData procedure of
the syListObj form.

l_result = Trigger_RegisterProcedure(script TRIGGER_LoadRibbonData of form


➥ syListObj, TRIGGER_AFTER_ORIGINAL, script IG_AddCustomerActions);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The trigger processing procedure that adds items to the Action Pane has a list object
variable passed into it. You will use this object to determine which list is being
displayed, and whether you need to add your actions to the list’s Action Pane. To
determine which list is being displayed, examine the list object’s ListID component.
It will correspond to one of the following constants:

Constant List Form


LISTID_ACCOUNTS Accounts card list ListObj_Accounts
LISTID_ACCOUNTTRX Accounts transaction list ListObj_AccountTrx
LISTID_ALLPURCHASINGTRX Purchasing transaction list ListObj_PurchasingTrx
(including all POP and PM
transactions)
LISTID_ALLSALESTRX Sales transaction list (including ListObj_SalesTrx
all SOP, RM, and IVC
transactions)
LISTID_CHECKBOOKS Checkbooks card list ListObj_Checkbooks
LISTID_CUSTOMERS Customers card list ListObj_Customers
LISTID_EMPLOYEES Employees card list ListObj_Employees
LISTID_GLBATCHES General Ledger batches card list ListObj_Batches
LISTID_ITEMS Items card list ListObj_Items
LISTID_ITEMTRX Items transaction list ListObj_ItemsTrx
LISTID_IVCTRX Invoicing transaction list ListObj_SalesTrx
LISTID_PMBATCHES Payables batches card list ListObj_Batches
LISTID_PMTRX Payables transaction list ListObj_PurchasingTrx
LISTID_POPTRX Purchase order transaction list ListObj_PurchasingTrx
LISTID_PROSPECTS Prospects card list ListObj_Prospects
LISTID_REPORTS_ALL All Reports report list syReportList
LISTID_REPORTS_COMPANY Company Report report list syReportList
LISTID_REPORTS_CUSTOM Custom Report report list syReportList
LISTID_REPORTS_FINANCIAL Financial report list syReportList
LISTID_REPORTS_INVENTORY Inventory report list syReportList
LISTID_REPORTS_PAYROLL Payroll report list syReportList
LISTID_REPORTS_PURCHASING Purchasing report list syReportList
LISTID_REPORTS_SALES Sales report list syReportList
LISTID_REPORTS_SMARTLIST SmartList Favorites report list syReportList
LISTID_REPORTS_SYSTEM System report list syReportList
LISTID_RMBATCHES Receivables batches card list ListObj_Batches
LISTID_RMTRX Receivables transaction list ListObj_SalesTrx
LISTID_SALESPEOPLE Salespeople card list ListObj_Salesperson
LISTID_SOPTRX Sales order transaction list ListObj_SalesTrx
LISTID_VENDORS Vendors card list ListObj_Vendors

INTEGRATION GUIDE 215


PA RT 6 LI ST S

The following example is the trigger processing procedure for the sample
integrating application that adds the Contact History action to the Customer card
list. Notice how it verifies that the Customer list is being displayed, and locates the
position of the item to be added.

inout ListObjState list_object;

local integer seq;


local integer nStatus;
local boolean exists;

{Is this the Customers list?}


if list_object:ListID = LISTID_CUSTOMERS then

{Does the Contact History command exist for the list? If not, add it.}
exists = ExistsAsAction(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History of form Command_IG_Sample),
DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID) of form syListViewCmdBarObj;

if exists = false then

{Find the Remove Hold command}


seq = FindCommandInCmdList(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ModifyGroup of form ListObj_Customers),
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command Remove_Hold of form ListObj_Customers)) of form
➥ syListViewCmdBarObj;

{If the command was found, add the Contact History command}
if seq <> 0 then
seq = seq + 1;
nStatus = AddCommand(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ModifyGroup of form ListObj_Customers),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History of form
➥ Command_IG_Sample),
LISTACTIONPRIORITY_SECONDARY,
LISTACTIONBTNSIZE_SMALL,
"" {caption},
true {visible},
true {clone for all list view}) of form syListViewCmdBarObj;
end if;
end if;

216 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

{Register the Contact History action}


List_RegisterAction(list_object, command IG_Contact_History of form
➥ Command_IG_Sample, LISTCMDTYPE_SINGLESELECT,
➥ ACTION_CONTACT_HISTORY_ENCODED) of form syListObj;
end if;

Registering actions and groups


For Microsoft Dynamics GP to properly process actions and groups added to the
Action Pane, they must be registered. You do this using the List_RegisterAction()
and List_RegisterGroup() functions.

Each action has a corresponding command this is run when the action is performed.
Each group has a command list that defines the characteristics of the group. When
you register the command, you specify the encoded version of the Action ID that
corresponds to the command. You also specify under what conditions the action
should be available. The following table lists the available conditions:

Constant Description
LISTCMDTYPE_ALWAYSAVAILABLE The action is always available, regardless of the
number of items the user has marked in the list.
LISTCMDTYPE_SINGLESELECT The action is available when the user has marked
one item in the list.
LISTCMDTYPE_MULTISELECT The action is available when the user has marked
one or more items in the list.
LISTCMDTYPE_GROUP The item is a group.

How you register actions and groups for the Action Pane depends on whether you
are adding them to your own list or to an existing Microsoft Dynamics GP list.

Registering actions and groups for your list


If you are creating your own list, you will register the items added to the Action
Pane using one of the procedures provided for the list. For card lists, this is
described in Action Pane on page 259. For transaction lists, this is described in Action
Pane on page 296.

Registering actions and groups for a Dynamics


GP list
If you are adding your actions to a Microsoft Dynamics GP list, you will register
register them at the end of the same trigger processing procedure that adds them to
the Action Pane. Refer to the example in Adding to the Action Pane on page 214.

Checking action access


The actions in the Action Pane are enabled or disabled automatically, based on the
number and specific type of lines the user has marked in the list. Microsoft
Dynamics GP tracks two counts for every action in the Action Pane. The “count for”
counter tracks the number of items marked to determine whether the single-select
or multi-select actions should be enabled. The “count against” counter tracks the
number items marked that would prevent an action from being enabled. If there are
any “count against” lines marked, the action will be disabled.

INTEGRATION GUIDE 217


PA RT 6 LI ST S

For example, assume that the Qualify action can be performed for the items selected
in the list. This action would be active as long as the user has marked one or more
items to qualify. However, if the user marked an item that had already been
qualified, the “counts against” counter would be incremented, causing the Qualify
action to be disabled.

The Qualify action is


disabled because a lead is
marked that has already
been qualified.

How you specify actions access for the Action Pane items depends on whether you
are adding actions to your own list or to an existing Microsoft Dynamics GP list.

Checking action access for your list


If you are creating your own list, you will check the acction access for the items
added to the Action Pane using one of the procedures provided for the list. For card
lists, this is described in Action Pane on page 259. For transaction lists, this is
described in Action Pane on page 296.

Checking action access for a Dynamics GP list


If you are adding your actions to a Microsoft Dynamics GP list, you will register a
trigger for the CheckActionAccessForRecord procedure of form that is used for the
list. The trigger processing procedure will define the access behavior for the actions
being added.

You can refer to the script parameter documentation in the Microsoft Dynamics GP SDK to
see the set of parameters used with each CheckActionAccessForRecord procedure.

The following example is a portion of the Startup script for the sample integrating
application. It registers the trigger for the CheckActionAccessForRecord procedure
of the ListObj_Customers form used for the Customer list.
l_result = Trigger_RegisterProcedure(script CheckActionAccessForRecord of
➥ form ListObj_Customers, TRIGGER_AFTER_ORIGINAL, script
➥ IG_CheckAccessCustomerActions);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The trigger processing procedure is called once each time a user marks or unmarks
a line in the list. The procedure specifies how the item marked or unarked in the list
should be considered when determining whether the action should be accessible.
You will use the 'Table Reference' component of the list object composite passed into
the procedure to determine which row is being marked or unmarked in the list.

218 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

The parameter value returned through the “out” parameter this trigger processing
procedure specifies how the marked row should be considered. The value
corresponds to one of the following constants:

Constant Description
LISTACTIONACCESS_COUNT_NEUTRAL The marked row won’t affect the count for the
action.
LISTACTIONACCESS_COUNT_FOR The marked row will increase or decrease the
“count for” counter by one.
LISTACTIONACCESS_COUNT_AGAINST The marked row will increase or decrease the
“count against” counter by one.

For example, the following trigger processing procedure updates the action access
for two actions added to the Customer card list. Notice how the Inactive field from
the row being marked or unmarked is examined to determine which access counter
should be incremented or decremented.
in ListObjState list_object;
in integer nActionCmdTag;
out integer nAccessStatus;

if nActionCmdTag = Command_GetTag(command IG_Contact_History of form


Command_IG_Sample) then
nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
end if;

if nActionCmdTag = Command_GetTag(command IG_Update_Contact_Date of form


➥ Command_IG_Sample) then
{Is the customer active?}
if 'Inactive' of table (list_object:'Table Reference') = true then
{Customer is inactive, so disable the action}
nAccessStatus = LISTACTIONACCESS_COUNT_AGAINST;
else
{Customer is active, so count for enabling action}
nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
end if;
end if;

Verifying an action
Actions for lists can impact a large amount of data in Microsoft Dynamics GP. For
actions that can’t easily be reversed, such as deleting marked items, you will want
the user to confirm the action before it is peformed. This is typically done with drop
dialogs that appear for buttons in the Action Pane. A typical drop dialog is shown
in the following illustration:

If a button on the Action Pane is going to display a drop dialog, the underlying command for
the action must have its Button Type property set to Drop Dialog in the Command
Definition window.

INTEGRATION GUIDE 219


PA RT 6 LI ST S

You can use the ConfirmAction() function to display a predefined drop dialog. You
can also create your own drop dialog to use for an action. To create your own drop
dialog, simply create a small window that will contain the content for the drop
dialog. In the script for the action’s command, use the as dropdialog clause with the
open window command. For example, the following sanScript code opens a drop
dialog for the Qualify action:

open window Qualify as dropdialog;

The Button Type for the command that will display the drop dialog must be set to Drop
Dialog in the command’s definition.

Code for the items in the drop dialog window will perform the specific action.
Using a drop dialog window for an action allows to user to perform the action
without having to open a separate window in Microsoft Dynamics GP. For
example, the following drop dialog is used for the Leads list in the sample
integrating application to qualify leads:

If you create your own drop dialog for an action, be sure to close the drop dialog
before any script code performs the action. If don’t close the drop dialog, it will
remain open and active while the action is processed. This would be confusing for
the user, since the drop dialog would remain open as a long-running action is
processed.

The following is the code for the OK button in the Qualify drop dialog. Notice how
it closes the drop dialog before the action is performed.

{Save the source value the user entered}


'Lead Source' of window State = 'Lead Source' of window Qualify;

{Close the drop dialog -- so it's not visible while processing is occurring}
close window Qualify;

{Call the action}


call ExecuteListAction of form syCardList, ACTION_QUALIFYLEAD, true,
➥ "Qualify Leads";

Executing an action
An action is executed when the user clicks an item in the Action Pane. How you
process an action depends on whether you are adding actions to your own list or to
an existing Microsoft Dynamics GP list.

Executing actions for your list


If you are creating your own list window, you will use the procedure provided for
the list to execute actions for it. For card lists, this is described in Action Pane on
page 259. For transaction lists, this is described in Action Pane on page 296.

220 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

Executing actions for a Microsoft Dynamics GP


list
To execute your actions for a Microsoft Dynamics GP list window, you will register
a trigger for the ExecuteAction procedure for the form that defines that list. The
trigger processing procedure will be called when a user initiates an action. This
procedure will determine if the action chosen was one you defined, and then run
the appropriate code for the action.

The following example is a portion of the Startup script for the sample integrating
application. It registers the trigger for the ExecuteAction procedure of the
ListObj_Customers form used to implement the Customers list.

l_result = Trigger_RegisterProcedure(script ExecuteAction of form


➥ ListObj_Customers, TRIGGER_AFTER_ORIGINAL, script
➥ IG_ExecuteCustomerActions);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The trigger processing procedure that runs when the user chooses an action has a
list object variable and an action ID passed into it. You will use the action ID to find
out whether this is an action you need to process. If it is, you will use the object
variable to access the main table used for the list so you can determine what list
item the user has selected.

The following is the trigger processing procedure for the sample integrating
application that is activated whenever the user clicks an action in the Action Pane
for the Customers list. Notice that the DisassembleDictSpecificID procedure is
used to extract the product ID and action. If the action is defined by sample
integrating application, it is processed.
inout ListObjState list_object;
in long action_id;

local integer dict_id;


local integer action;

{Is this the default action? If it is, do not process it.}


if action_id <> DEFAULT_ACTION then

{Disassemble the action that was passed into the script}


call DisassembleDictSpecificID, action_id, dict_id, action;

{Process the action}


if dict_id = IG_PROD_ID then

{It is our action to process}


case action
in[ACTION_CONTACT_HISTORY]
{Execute the action to open the selected customer}
call ExecuteAction of form ListObj_Customers, list_object,
➥ DEFAULT_ACTION;

{Open the Contact History window}


call IG_Trigger_Open_Contact_History;

INTEGRATION GUIDE 221


PA RT 6 LI ST S

in[ACTION_UPDATE_CONTACT_DATE]
{Update the contact date for all of the marked customers}
call IG_Update_Contact_Date, list_object;
end case;
end if;
end if;

Performing actions for marked rows


The action chosen needs to be performed for every row that is marked in the list.
How the marked rows are accessed depends on the type of action being performed.

Multi-select actions
When a multi-select action is being performed, you must retrieve a reference to the
temporary table that contains the marked rows. The GetMarkedRecordsTableRef()
function of the syListObj form retrieves the reference to this table. The
GetMarkedRecordsTableIndex() function of the syListObj form retrieves the index
number to use when accessing the records. You will use this table reference to
retrieve specific information about the current marked rows that are being
processed. The following example shows the basic looping code used to process the
marked rows.
local reference ListTableReference;
local integer ListTableIndex;

ListTableReference = GetMarkedRecordsTableRef(list_object) of form syListObj;


ListTableIndex = GetMarkedRecordsTableIndex(list_object) of form syListObj;

{Get the first row that is marked}


get first table(ListTableReference) by number ListTableIndex;

while err() = OKAY do

{Perform the action on the current row}

{Get the next row that is marked}


get next table(ListTableReference) by number ListNumberIndex;
end while;

For a multiselect action, you must call the List_MultiSelectActionCompleteEvent


procedure to indicate that the action has been completed for all of the marked items.
A complete example of performing an action for the marked rows is show in
Logging action status on page 223.

Single-select actions
When a single-select action is being performed, you must use the 'Table Reference'
component of the list object composite to find out the row that is marked. The action
will be performed for this row. The following example shows a portion of the
ExecuteAction procedure for the Leads list. This code runs in response to the Edit
Lead action. This action is a single-select action that opens the maintenance window
for the row that is marked in the list.
open form IG_Lead_Maintenance;
'Lead ID' of window 'Lead Maintenance' of form IG_Lead_Maintenance =
➥ 'Lead ID' of table (list_object:'Table Reference');
run script 'Lead ID' of window 'Lead Maintenance' of form
➥ IG_Lead_Maintenance;

222 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

Always-available actions
When an always-available action is being performed, the marked row information
available will depend on the number of rows marked in the list. If no rows are
marked, no record information is available. If one row is marked, the 'Table
Reference' component of the list object composite will contain the marked row. If
more than one row is marked, the 'Table Reference' component of the list object
composite will contain the first row that is marked, based on the current sort order
for the list. You can use the GetMarkedRecordCount() of the syListObj form to find
out the number of rows that are marked.

Refresh event
If your list processing code is keeping track of which rows in the list are marked, it
may be helpful to know when all of the rows in the list have been unmarked due to
a “refresh” event. To be notified of this situation for your list, add the
ClearMarkedRecordsEvent procedure to the list. This procedure must have the
following parameter:

inout ListObjState list_object;

Logging action status


Since actions can be performed on multiple items marked in the list, it’s important
to keep track of the status of each individual action and display the results for the
user. Each list in Microsoft Dynamics GP has a Message Bar that is used to display
the results of the actions performed on the list items.

Within the script that processes an action for a list, you must do the following:

• For each failed action, log the details of the action

• Keep track of the total number of successful and failed operations performed

Use the ActionStatus_LogError() function of the syListObj form to log the details of
each error that occurred when performing actions on list items. This function takes
several parameters that you supply to provide details about what failed for the
specific item. These details are displayed in the Status Message Detail window in
Microsoft Dynamics GP.

Errors encountered
during action processing
are displayed here.

INTEGRATION GUIDE 223


PA RT 6 LI ST S

After all of the marked items in the list have been processed, call the
ActionStatus_LogActionComplete() function of the form syListObj to indicate that
the logging action is complete. The total number of successful and failed operations
are passed as parameters to this function.

If the action being processed is a multi-select action, you must call the
List_MultiSelectActionCompleteEvent procedure to indicate that all of the items
have been processed. If you don’t use this function, the list will remain in the
“processing” state.

The data for each action status item is stored in the sy07250 table in the current
company’s database. As you log action status, you may want to see what has
actually been logged in this table.

The following example is a procedure that performs the Update Contact Date action
for the Customer card list. It processes each customer marked in the list, keeping
track of the number of customers successfully processed. Any processing errors are
logged using the ActionStatus_LogError() function.

inout ListObjState list_object;

local ListStatusLineUserDefData UserDefData;


local long ErrorStatus;
local integer SuccessCount;
local integer FailureCount;
local reference ListTableReference;
local integer ListTableIndex;

{Clear the status counts}


SuccessCount = 0;
FailureCount = 0;

{Use the table reference from the list object to find which Customers
are selected in the list.}
ListTableReference = GetMarkedRecordsTableRef(list_object) of form syListObj;
ListTableIndex = GetMarkedRecordsTableIndex(list_object) of form syListObj;
get first table(ListTableReference) by number ListTableIndex;

while err() = OKAY do


{Attempt to update the contact date for the selected Customer}
'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number' of
➥ table(ListTableReference);
change table IG_Contact_History_MSTR;

if err() = OKAY then


{Item could be locked, so update it}
'Last Contact Date' of table IG_Contact_History_MSTR = sysdate();
save table IG_Contact_History_MSTR;
if err() = OKAY then
increment SuccessCount;
else
increment FailureCount;

{Log the details of the error}


UserDefData:'User Defined Text01' = 'Customer Number' of
➥ table(ListTableReference);
UserDefData:'User Defined LongInt01' = IG_PROD_ID;
ErrorStatus = ActionStatus_LogError(list_object:ActionStatusID,

224 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

list_object:'Error Sequence Number',


"Customer contact date could not be updated.",
err(),
'Customer Number' of table(ListTableReference),
UserDefData) of form syListObj;

increment list_object:'Error Sequence Number';


end if;
else
{Item could not be found}
increment FailureCount;

{Log the details of the error}


UserDefData:'User Defined Text01' = 'Customer Number' of
➥ table(ListTableReference);
UserDefData:'User Defined LongInt01' = IG_PROD_ID;
ErrorStatus = ActionStatus_LogError(list_object:ActionStatusID,
list_object:'Error Sequence Number',
"Customer could not be found or has not had initial contact
➥ information defined.",
err(),
'Customer Number' of table(ListTableReference),
UserDefData) of form syListObj;

increment list_object:'Error Sequence Number';


end if;

{Get the next Cusotmer to update}


get next table(ListTableReference) by number ListTableIndex;
end while;

{Log the success and failure results}


ErrorStatus = ActionStatus_LogActionComplete(list_object:ActionStatusID,
➥ SuccessCount, FailureCount) of form syListObj;

{Indicate that the mutli-select list action is complete}


call List_MultiSelectActionCompleteEvent of form syListObj, list_object;

If you want to display a different message in the message bar for the list, you can
add the GetSummaryStatusMsgText procedure. This procedure is also defined for
several core lists in Microsoft Dynamics GP. To display a different message for the
message bar for core lists, you would create a procedure trigger that runs after the
GetSummaryStatusMsgText procedure. The GetSummaryStatusMsgText procedure
has the following parameters:

in syListActionStatusHdrState HdrState;
out string sMsgText;

Use the GetActionID() function of the syListActionStatusObj form, passing in the


action status header composite, to retrieve the ID of the action that was performed.
If it’s your action being processed, set the “out” parameter to the text you want to
display in the message bar. The amount of text is limited to 255 characters.

INTEGRATION GUIDE 225


PA RT 6 LI ST S

Acting on action errors


The last parameter for the ActionStatus_LogError() function is the
ListStatusLineUserDefData composite field, which allows you to store additional
data regarding the item that failed. The composite has the following components:

• User Defined Text01


• User Defined Text02
• User Defined Text03
• User Defined Text04
• User Defined Text05
• User Defined LongInt01
• User Defined LongInt02
• User Defined Date01
• User Defined Date02

This composite field is one of the parameters passed to the ActOnActionError


procedure. This procedure runs when the user double-clicks a specific error in the
Status Detail Message window. It is typically used to navigate to a location where
the user can correct the error that occurred while the action was processing. The
ActOnActionError procedure has the following parameters:
in integer ListDictID;
in integer ListID;
in long ActionID;
in long ErrorID;
in string RecordID;
in ListStatusLineUserDefData UserDefData;

You can create a procedure trigger for the ActOnActionError procedure defined for
the list you are creating an action for. The trigger processing procedure should run
after the procedure defined for the list. The following example registers a procedure
trigger for the ActOnActionError procedure defined for the Customer list.
l_result = Trigger_RegisterProcedure(script ActOnActionError of form
➥ ListObj_Customers, TRIGGER_AFTER_ORIGINAL, script
➥ IG_ActOnCustomerActionError);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for ActOnActionError of form
➥ ListObj_Customers failed.";
end if;

In the trigger processing procedure you can perform any needed action to correct
the error, such as opening the appropriate maintenance window where the problem
can be resolved.

For example, the following is the IG_ActOnCustomerActionError procedure for the


sample integrating application. This procedure runs in response to the user clicking
on a list action error logged by the sample integration. If the action was the Update
Contact Date action, the Contact History window will be opened, allowing the user
to supply the initial contact information. Notice how the first long integer value in
the user-defined data is verified to be sure the error was generated by the sample
integrating application.

226 IN T E G R AT I O N G U ID E
C H A P T E R 2 7 A C T I O N P A N E

in ListDictID nListDictID;
in ListID nListID;
in ActionID nActionID;
in ErrorValue nErrorID;
in Reference sRecordID;
in ListStatusLineUserDefData UserDefData;

{Is this our action to process?}


if nListID = LISTID_CUSTOMERS then
{Look at the user-defined data to verify that the product ID is included}
if UserDefData:'User Defined LongInt01' = IG_PROD_ID then
if nActionID = ACTION_UPDATE_CONTACT_DATE then
{Open the Contact History window}
call IG_Trigger_Open_Contact_History;
end if;
end if;
end if;

INTEGRATION GUIDE 227


228 IN T E G R AT I O N G U ID E
Chapter 28: Information Pane
The Information Pane for a list displays additional information about the item
currently selected in the list. If you are integrating with an existing list in Microsoft
Dynamics GP, you may want to add additional data to the Information Pane. If you
are creating your own list, you will define the layout of the Information Pane to
display data for the selected item in your list. Information about the Information
Pane is divided into the following sections:

• Information Pane layout


• Adding content to the Information Pane
• Adding to the Information Pane header
• Adding to the Information Pane line items
• Information Pane procedure reference

Information Pane layout


The layout of the Information Pane depends on the type of list being displayed. For
card lists, the Information Pane contains three columns. Within each column are a
series of label-value pairs that display information about the selected item. When
integrating with Microsoft Dynamics GP lists, you can add additional items to the
end of each column.

Additional items can be


added to the end of
each column.

For transaction lists, the Information Pane contains three columns that display
header information, followed by the detailed line items for the selected transaction.
When integrating with Microsoft Dynamics GP lists, you can add additional items
to the end of each column in the header section. You can also add additional
information to the end of each line item.

Additional items can be


added to the end of
each line item.

Adding content to the Information Pane


The data displayed in the Information Pane is based on an XML file that is
constructed each time a row is selected in the card or transaction list. Several
functions are provided that you will use to build this XML file.

Adding to your list


If you are adding content to the Information Pane for your own list, you will use
one of the procedures provided for the list. For card lists, this is described in
Information Pane on page 267. For transaction lists, this is describe in Information
Pane on page 302.

INTEGRATION GUIDE 229


PA RT 6 LI ST S

Adding to a Microsoft Dynamics GP list


If you are adding content to the Information Pane for an existing Microsoft
Dynamics GP list, you will register triggers for the form procedures that define the
various portions of the Information Pane content. The trigger processing procedures
will add the content for the specific item selected in the list. The following table lists
the form-level procedures that are defined for each type of list to create the
Information Pane content.

Procedure Description Card Trx


List List
XML_CreateHeaderSection Adds items to the three-column X X
Information Pane header.
XML_CreateLineColumnHeaders Adds columns to the end of the line X
items list in the Information Pane.
XML_AddLineItem Adds data values to the end of the X
current line item in the Information
Pane.

Adding to the Information Pane header


The following example is a portion of the Startup script for the sample integrating
application. It registers the trigger for the XML_CreateHeaderSection procedure of
the ListObj_Customers form.

l_result = Trigger_RegisterProcedure(script XML_CreateHeaderSection of form


➥ ListObj_Customers, TRIGGER_AFTER_ORIGINAL, script
➥ IG_AddCustomerInfoPaneItems);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for XML_CreateHeaderSection of
➥ form ListObj_Customers failed.";
end if;

The trigger processing procedure adds the items to the Information Pane section
indicated by the form-level procedure. In this example, the trigger processing
procedure uses the XMLDoc_AddHeaderField procedure to add items to the end of
the columns in the header section of the Information Pane.

The parameters for the trigger processing procedure must match those of the form-level
procedure defined on the list form. The parameter list will vary, depending on the list
implementation. Refer to Information Pane procedure reference on page 232 for the paramter
list needed for each list defined in Microsoft Dynamics GP.

The following is the IG_AddCustomerInfoPaneItems trigger processing procedure


from the sample integrating application. It adds additional data showing the last
contact date for the customer selected in the list. The additional information is
added to the end of column 3 in the Information Pane header.

in table RM_Customer_MSTR;
inout ListPrevPaneXMLState XMLState;

{Retrieve the last contact information for the selected customer}


'Customer Number' of table IG_Contact_History_MSTR = 'Customer Number' of
➥ table RM_Customer_MSTR;
get table IG_Contact_History_MSTR;

230 IN T E G R AT I O N G U ID E
C H A P T E R 2 8 I N F O R M A T I O N P A N E

{If information was found, display it}


if err() = OKAY then
{Add the information to the end of column 3}
call XMLDoc_AddHeaderField of form syListObj, XMLState, "Last Contact",
➥ str('Last Contact Date' of table IG_Contact_History_MSTR), 3;
end if;

Adding to the Information Pane line items


Adding to the end of the line items for the Information Pane is a two-step process.
First, the column header must be added to the line item header. Then the values for
each line item must be added.

Add the column The following example is a portion of the Startup script for the sample integrating
header. application. It registers a trigger for the XML_CreateLineColumnHeaders
procedure of the ListObj_AccountTrx form.

l_result = Trigger_RegisterProcedure(script XML_CreateLineColumnHeaders of


➥ form ListObj_AccountTrx, TRIGGER_AFTER_ORIGINAL, script
➥ IG_AddCompanyToAccountTrxHeader);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The parameters for the trigger processing procedure must match those of the form-level
procedure defined on the list form. The parameter list will vary, depending on the list
implementation. Refer to Information Pane procedure reference on page 232 for the paramter
list needed for each list defined in Microsoft Dynamics GP.

The following is the IG_AddCompanyToAccountTrxHeader trigger processing


procedure that runs in response to this trigger. This procedure uses the
XMLDoc_AddColumn procedure to add a new column to the line item header.

in integer nTrxType;
inout ListPrevPaneXMLState XMLState;

{Add the Company header item, with the item right-justified}


call XMLDoc_AddColumn of form syListObj, XMLState, "Company", true;

Add the line item The following example is a portion of the Startup script for the sample integrating
values. application. It registers a trigger for the XML_AddLineItem procedure of the
ListObj_AccountTrx form.

l_result = Trigger_RegisterProcedure(script XML_AddLineItem of form


➥ ListObj_AccountTrx, TRIGGER_AFTER_ORIGINAL, script
➥ IG_AddCompanyToAccountTrx);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The following is the IG_AddCompanyToAccountTrx trigger processing procedure


that runs in response to the trigger. This procedure uses the
XMLDoc_AddLineItemValue procedure to add the company value to the end of
the current line item.

INTEGRATION GUIDE 231


PA RT 6 LI ST S

in anonymous table TrxHdr;


in anonymous table TrxLine;
in integer nTrxStatus;
in integer nTrxType;
inout ListPrevPaneXMLState XMLState;
inout reference RowValuesElement;

if technicalname(table TrxLine) = "GL_YTD_TRX_OPEN" then


call XMLDoc_AddLineItemValue of form syListObj, XMLState,
➥ RowValuesElement, 'Originating Company ID' of table TrxLine, true;
end if;

if technicalname(table TrxLine) = "GL_TRX_LINE_WORK" then


call XMLDoc_AddLineItemValue of form syListObj, XMLState,
➥ RowValuesElement, 'Intercompany ID' of table TrxLine, true;
end if;

Information Pane procedure reference


The following is a list of the form-level procedures and their corresponding
parameters for each core list defined in Microsoft Dynamics GP. Use this
information when creating the trigger processing procedures needed to add
additional data to the Information Pane.

Accounts card list


The XML_CreateHeaderSection procedure has the following parameters:

in table AccountListTemp;
inout ListPrevPaneXMLState XMLState;

Accounts transaction list


The XML_CreateHeaderSection procedure has the following parameters:

in anonymous table TrxHdr;


in integer nTrxStatus;
in integer nTrxType;
inout ListPrevPaneXMLState XMLState;

TrxHdr table can be:

• GL_TRX_HDR_WORK
• GL_Business_Form_HDR_WORK
• GL_YTD_TRX_OPEN
• GL_Account_TRX_HIST

TrxStatus can be:

• Work: indicated by the constant WORK


• Open: indicated by the constant OPEN
• History: indicated by the constant HIST

TrxType can be:

• Normal: indicated by the value 1


• Quick Journal: indicated by the value 2
• Clearing: indicated by the value 3

232 IN T E G R AT I O N G U ID E
C H A P T E R 2 8 I N F O R M A T I O N P A N E

The XML_CreateLineColumnHeaders procedure has the following parameters:


in integer nTrxType;
inout ListPrevPaneXMLState XMLState;

The XML_AddLineItem procedure has the following parameters:

in anonymous table TrxHdr;


in anonymous table TrxLine;
in integer nTrxStatus;
in integer nTrxType;
inout ListPrevPaneXMLState XMLState;

TrxHdr table can be:

• GL_TRX_HDR_WORK
• GL_Business_Form_HDR_WORK
• GL_YTD_TRX_OPEN
• GL_Account_TRX_HIST

TrxLine can be:

• GL_TRX_LINE_WORK
• GL_Business_Form_LINE_WORK
• GL_YTD_TRX_OPEN
• GL_Account_TRX_HIST

TrxStatus can be:

• Work: indicated by the constant WORK


• Open: indicated by the constant OPEN
• History: indicated by the constant HIST

TrxType can be:

• Normal: indicated by the value 1


• Quick Journal: indicated by the value 2
• Clearing: indicated by the value 3

All Purchasing transactions list


See Payables transactions list on page 236.

All Sales transactions list


See Receivables transactions list on page 239

Checkbooks card list


The XML_CreateHeaderSection procedure has the following parameters:
in table CM_Checkbook_MSTR;
inout ListObjState Me;
inout ListPrevPaneXMLState XMLState;

Customers card list


The XML_CreateHeaderSection procedure has the following parameters:
in table RM_Customer_MSTR;
inout ListPrevPaneXMLState XMLState;

INTEGRATION GUIDE 233


PA RT 6 LI ST S

Employees card list


The XML_CreateHeaderSection procedure has the following parameters:
in table EmployeeListTemp;
inout ListPrevPaneXMLState XMLState;

General Ledger batches card lists


The XML_CreateHeaderSection procedure has the following parameters:

in table Batch_Headers;
in long nSubList;
inout ListPrevPaneXMLState XMLState;

SubList can be:

• GL batches: indicated by the constant GL


• PM batches: indicated by the constant constant PM
• RM batches: indicated by the constant constant RM

Invoice transactions list


See Receivables transactions list on page 239.

Items card list


The XML_CreateHeaderSection procedure has the following parameters:

in table IV_ItemList_View;
inout ListPrevPaneXMLState XMLState;

Items transactions list


The XML_CreateHeaderSection procedure has the following parameters:

in anonymous table TrxHdr;


in integer nTrxStatus;
in integer nTrxType;
in 'History Module' sHistModule
inout ListPrevPaneXMLState XMLState;

TrxHdr can be:

• IV_TRX_WORK_HDR
• IV_TRX_HIST_HDR
• POP_ReceiptHist
• SOP_HDR_HIST
• IVC_HDR_HIST
• bmTrxHist

TrxStatus can be:

• Work: indicated by the constant WORK


• History: indicated by the constant HIST

234 IN T E G R AT I O N G U ID E
C H A P T E R 2 8 I N F O R M A T I O N P A N E

TrxType can be:

• Adjustment: indicated by the constant IV_ADJUSTMENT


• Variance: indicated by the constant IV_VARIANCE
• Transfer: indicated by the constant IV_TRANSFER
• Receipt: indicated by the constant IV_RECEIPT
• Return: indicated by the constant IV_RETURN
• Sale: indicated by the constant IV_SALE
• Assembly: indicated by the constant IV_ASSEMBLY

History Module can be:

• SOP: indicated by the constant HISTORY_MODULE_SOP


• Invoicing: indicated by the constant HISTORY_MODULE_IVC

The XML_CreateLineColumnHeaders procedure has the following parameters:

in anonymous table TrxHdr;


in integer nTrxType;
in 'History Module' sHistModule;
inout ListPrevPaneXMLState XMLState;

TrxHdr can be:

• IV_TRX_WORK_HDR
• IV_TRX_HIST_HDR
• POP_ReceiptHist
• SOP_HDR_HIST
• IVC_HDR_HIST
• bmTrxHist

TrxType can be:

• Adjustment: indicated by the constant IV_ADJUSTMENT


• Variance: indicated by the constant IV_VARIANCE
• Transfer: indicated by the constant IV_TRANSFER
• Receipt: indicated by the constant IV_RECEIPT
• Return: indicated by the constant IV_RETURN
• Sale: indicated by the constant IV_SALE
• Assembly: indicated by the constant IV_ASSEMBLY

History Module can be:

• SOP: indicated by the constant HISTORY_MODULE_SOP


• Invoicing: indicated by the constant HISTORY_MODULE_IVC

The XML_AddLineItem procedure has the following parameters:


in anonymous table TrxLine;
in integer nTrxStatus;
in integer nTrxType;
inout ListPrevPaneXMLState XMLState;

INTEGRATION GUIDE 235


PA RT 6 LI ST S

TrxLine can be:

• IV_TRX_WORK_LINE
• IV_TRX_HIST_LINE
• POP_ReceiptLineHist
• SOP_LINE_HIST
• IVC_LINE_HIST
• bmTrxCompHist

TrxStatus can be:

• Work: indicate by the constant WORK


• History: indicated by the constant HIST

TrxType can be:

• Adjustment: indicated by the constant IV_ADJUSTMENT


• Variance: indicated by the constant IV_VARIANCE
• Transfer: indicated by the constant IV_TRANSFER
• Receipt: indicated by the constant IV_RECEIPT
• Return: indicated by the constant IV_RETURN
• Sale: indicated by the constant IV_SALE
• Assembly: indicated by the constant IV_ASSEMBLY

Payables batches card list.


See General Ledger batches card lists on page 234.

Payables transactions list


The XML_CreateHeaderSection procedure has the following parameters:

inout ListPrevPaneXMLState XMLState;


in anonymous table TrxHdr;
in integer nTrxStatus;
in integer nSource;
in integer nTrxType;

TrxHdr can be:

• POP_PO
• POP_POHist
• POP_Receipt
• POPReceiptHist
• PM_Manual_Payment_WORK
• PM_Payment_WORK
• PM_Transaction_WORK
• PM_Transaction_OPEN
• PM_Paid_Transaction_HIST

TrxStatus can be:

• Work: indicated by the constant WORK


• Open: indicated by the constant OPEN
• History: indicated by the constant HIST

236 IN T E G R AT I O N G U ID E
C H A P T E R 2 8 I N F O R M A T I O N P A N E

Source can be:

• PM
• PM_CCHECKS
• POP_POTRX
• POP_RECEIPT
• POP_RETURN

TrxType can be:

• PM_DOC_INVOICE
• PM_DOC_FIN_CHG
• PM_DOC_MISC_CHG
• PM_DOC_RETURN
• PM_DOC_CR_MEMO
• PM_DOC_PAYMENT
• POP_DOCTYPE_INVOICE
• POP_DOCTYPE_SHIPMENT
• POP_DOCTYPE_SHIPMENT_INVOICE
• POP_DOCTYPE_IN_TRANSIT
• POP_DOCTYPE_RETURN
• POP_DOCTYPE_RETURNCREDIT
• POP_DOCTYPE_INVENTORYRETURN
• POP_DOCTYPE_INVENTORYRETURNCREDIT

The XML_CreateLineColumnHeaders procedure has the following parameters:


inout ListPrevPaneXMLState XMLState;
inout anonymous table TrxHdr;
in integer nTrxStatus;
in integer nSource;

TrxHdr can be:

• POP_PO
• POP_POHist
• POP_Receipt
• POPReceiptHist
• PM_Manual_Payment_WORK
• PM_Payment_WORK
• PM_Transaction_WORK
• PM_Transaction_OPEN
• PM_Paid_Transaction_HIST

TrxStatus can be:

• Work: indicated by the constant WORK


• Open: indicated by the constant OPEN
• History: indicated by the constant HIST

Source can be:

• PM
• PM_CCHECKS
• POP_POTRX
• POP_RECEIPT
• POP_RETURN

INTEGRATION GUIDE 237


PA RT 6 LI ST S

TrxType can be:

• PM_DOC_INVOICE
• PM_DOC_FIN_CHG
• PM_DOC_MISC_CHG
• PM_DOC_RETURN
• PM_DOC_CR_MEMO
• PM_DOC_PAYMENT
• POP_DOCTYPE_INVOICE
• POP_DOCTYPE_SHIPMENT
• POP_DOCTYPE_SHIPMENT_INVOICE
• POP_DOCTYPE_IN_TRANSIT
• POP_DOCTYPE_RETURN
• POP_DOCTYPE_RETURNCREDIT
• POP_DOCTYPE_INVENTORYRETURN
• POP_DOCTYPE_INVENTORYRETURNCREDIT

The XML_AddLineItem procedure has the following parameters:

inout ListPrevPaneXMLState XMLState;


inout anonymous table TrxLine;
in integer nTrxStatus;
in integer nSource;
in integer nRcptType;

TrxLine can be:

• POP_POLine
• POP_POLineHist
• POP_ReceiptLine
• POP_ReceiptLineHist

TrxStatus can be:

• Work: indicated by the constant WORK


• Open: indicated by the constant OPEN
• History: indicated by the constant HIST

Source can be:

• POP_POTRX
• POP_RECEIPT
• POP_RETURN

RcptType can be one of the following:

For POP Purchase Order Documents:

• POP_DOCTYPE_PO
• POP_DOCTYPE_DROPSHIP
• POP_DOCTYPE_BLANKET
• POP_DOCTYPE_BLANKET_DROPSHIP

238 IN T E G R AT I O N G U ID E
C H A P T E R 2 8 I N F O R M A T I O N P A N E

For POP Receipt Documents:

• POP_DOCTYPE_SHIPMENT
• POP_DOCTYPE_INVOICE
• POP_DOCTYPE_SHIPMENT_INVOICE
• POP_DOCTYPE_RETURN
• POP_DOCTYPE_RETURNCREDIT
• POP_DOCTYPE_INVENTORYRETURN
• POP_DOCTYPE_INVENTORYRETURNCREDIT
• POP_DOCTYPE_IN_TRANSIT

For PM Documents:

• PM_DOC_INVOICE
• PM_DOC_FIN_CHG
• PM_DOC_MISC_CHG
• PM_DOC_RETURN
• PM_DOC_CR_MEMO
• PM_DOC_PAYMENT
• PM_DOC_SCHEDULE

Propects card list


The XML_CreateHeaderSection procedure has the following parameters:

in table SOP_Prospect_MSTR;
inout ListPrevPaneXMLState XMLState;

Purchase Order Processing transactions list


See Payables transactions list on page 236.

Receivables batches card list


See General Ledger batches card lists on page 234.

Receivables transactions list


The XML_CreateHeaderSection procedure has the following parameters:

in anonymous table TrxHdr;


in integer nSource;
in integer nDocStatus;
in 'Document Type' nDocType;
in 'SOP Number' sSOPNum;
in 'Invoice Number' sIVCNum;
inout ListPrevPaneXMLState XMLState;

TrxHdr can be:

• IVC_HDR_HIST
• IVC_HDR_WORK
• RM_Cash_WORK
• RM_Sales_WORK
• RM_OPEN
• RM_HISTORY
• SOP_HDR_HIST
• SOP_HDR_WORK

INTEGRATION GUIDE 239


PA RT 6 LI ST S

Source can be:

• RM: indicated by the constant RM


• SOP: indicated by the constant SOP
• IVC: indicated by the constant IVC

DocStatus can be:

• Work: indicated by the constant WORK


• Open: indicated by the constant OPEN
• History: indicated by the constant HIST

Document Type can be:

• SOP_QUOTE
• SOP_ORDER
• SOP_INVOICE
• SOP_RETURN
• SOP_BACK_ORDER
• SOP_FULFILLMENT_ORDER
• IVC_INVOICE
• IVC_RETURN
• RM_DOC_CASH
• RM_DOC_CRMEMO
• RM_DOC_DBMEMO
• RM_DOC_FINCHG
• RM_DOC_RETURNS
• RM_DOC_SALES
• RM_DOC_SCH_PP
• RM_DOC_SCH_PYMNT
• RM_DOC_SERVICE
• RM_DOC_WARR

The XML_CreateLineColumnHeaders procedure has the following parameter:

inout ListPrevPaneXMLState XMLState;

The XML_AddLineItem procedure has the following parameters:

in anonymous table TrxHdr;


in anonymous table TrxLine;
inout ListPrevPaneXMLState XMLState;

TrxHdr can be:

• RM_Cash_WORK
• RM_Sales_WORK
• RM_OPEN
• SOP_HDR_HIST
• IVC_HDR_HIST
• RM_HISTORY
• SOP_HDR_WORK
• IVC_HDR_WORK

240 IN T E G R AT I O N G U ID E
C H A P T E R 2 8 I N F O R M A T I O N P A N E

TrxLine can be:

• SOP_LINE_WORK
• SOP_LINE_HIST
• IVC_LINE_WORK
• IVC_LINE_HIST

Sales Order Processing transactions list


See Receivables transactions list on page 239.

Salespeople card list


The XML_CreateHeaderSection procedure has the following parameters:

in table RM_Salesperson_MSTR;
inout ListPrevPaneXMLState XMLState;

Vendor card list


The XML_CreateHeaderSection procedure has the following parameters:

in table PM_Vendor_MSTR;
inout ListPrevPaneXMLState XMLState;

INTEGRATION GUIDE 241


242 IN T E G R AT I O N G U ID E
Chapter 29: Card Lists
A card list displays a list of items in the accounting system, such as customers,
vendors, or accounts. If you define a set of items in your integration, you may want
to implement a card list for that item. The sample integrating application
implements the Leads list, as shown in the following illustration.

Information about implementing a card list is divided into the following sections:

• Card list form


• Checking access
• Creating a temporary table
• Attaching tables
• Table access
• List columns
• List options
• Selecting the data to display
• Filling the list
• Formatting list data
• Filter tokens
• Action Pane
• Information Pane
• Business Analyzer
• Row selection actions
• Open and closing
• List navigation
• Custom list views

Card list form


Create the card list Each card list is a separate form in the dictionary. This form serves as a base for the
form. card list table references, scripts, and state information. To make creating a card list
easier, a basic template for a card list form is provided with Dexterity.

Importing the card list template


To import the card list template and begin creating a card list, complete the
following procedure:

1. Open your development dictionary.


With Dexterity, open your development dictionary.

INTEGRATION GUIDE 243


PA RT 6 LI ST S

2. Import an item from a text file.


In the Explorer menu, choose Import From Text File.

3. Select the card list form template.


Click the lookup button in the Import From Text File window. Using the dialog
displayed, select the ListObjCardGeneric.form located in the Develop folder
inside the Samples folder for Dexterity.

4. Import the form.


Click Import to import the template into your dictionary.

5. Rename the form.


Rename the form to a name more appropriate for your integration. Using the
standard convention for naming card list forms, the name would begin with
ListObj_ and end with the name of the item that will be displayed in the list. For
example, the card list form included in the sample integrating application is
named ListObj_Leads.

Checking access
Add the The CheckListAccess procedure for the card list form is used to control access to the
CheckListAccess card list. In releases prior to Microsoft Dynamics GP 10, this procedure contained
procedure. code to verify that the user has access to the primary form used to manage the data
that is displayed in the list. If the user didn’t have access to the form, access to the
card list was denied. Beginning with Microsoft Dynamics GP 10, security tasks are
used to control access to card lists. Refer to Security task operations on page 395 for
information about creating security task operations that control access to specific list
features.

The CheckListAccess procedure can still be used to control access to a list. For
instance, you may not want to allow a list to be displayed if a specific module hasn’t
been registered. To grant access, the procedure should return true. Otherwise, the
procedure should return false.

For leads in the sample integration, the CheckListAccess procedure always allows
access. Security for this list is controlled through security tasks:

inout boolean bSuccess;

bSuccess = true;

Creating a temporary table


Create a temporary The content for the card list comes from a temporary table that you will create for
table for the card list. the list. Typically, this table contains the same fields as the master table that stores
the data you want to display in the list. You may want to create the definition for the
list’s temporary table simply be duplicating the table definition for the master table.
For example, the IG_Leads_List_TEMP table used for the Leads list in the sample
integrating application was created by duplicating the IG_Leads_MSTR table. Be
sure the temporary table has the following characteristics:

• The table physical name must be TEMP

• The database type must be SQL

Be sure to verify the key names for the duplicated table. You may want to change them to
names more suitable for the list’s temporary table.

244 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

Add additional fields to Some additional fields from the Dynamics.dic dictionary must be added to the
the temporary table. temporary table. These are:

InfoValue This field is used for the information icon that can be displayed for
each row in the list. This field is required only if the information icon will be
displayed. You may want to add this field now, in the event it is needed later for
your list.

Marked To Process The field is used for the check mark displayed for each row.
It is required for every list.

Attaching tables
Attach tables to the The content of a card list comes from the temporary table that is defined for the list.
card list. The master table and any other tables needed to populate the list’s temporary table
must also be attached to the list. Use the Form Definition window to attach these
tables to the card list form.

For the Leads list in the sample integration, the IG_Leads_List_TEMP table and the
IG_Leads_MSTR table were attached to the ListObj_Leads form. The
SY_Record_Notes_MSTR table is also attached, since it will be examined to verify
whether notes have been attached for each lead.

Table access
Assign a reference to The syCardList form in the Dynamics.dic dictionary must be able to access the main
the main table. table used for your card list. A reference to the main table for the card list provides
this access. You create this reference using a global procedure for your integration.
For example, the following is the procedure in the sample integrating application
that creates a reference to the IG_Leads_List_TEMP table for the Leads list.

Procedure name: AssignTableRef_LeadList

if isopen(form syCardList) then


assign 'Table Reference' of window CardList of form syCardList
➥ as reference to table IG_Leads_List_TEMP;
end if;

Add the The procedure that assigns the table reference must be called each time the card list
RegisterTableRef is displayed. This in done using a trigger that will call the AssignTableRef
Trigger procedure. procedure you just created. The procedure trigger is created in the
RegisterTableRefTrigger procedure that is part of your card list form. The following
is the RegisterTableRefTrigger procedure for the Leads list.
inout integer nTriggerTag;

local integer nStatus;

nStatus = Trigger_RegisterFocus(anonymous('Attach Button' of window


➥ CardList of form syCardList), TRIGGER_FOCUS_CHANGE,
➥ TRIGGER_AFTER_ORIGINAL, script AssignTableRef_LeadList, nTriggerTag);
if nStatus <> SY_NOERR then
error "Could not register the RegisterTableRefTrigger for the Leads list";
end if;

The tag for this trigger is automatically saved so that this trigger can be unregistered when
another list is displayed.

INTEGRATION GUIDE 245


PA RT 6 LI ST S

List columns
Add the The CreateListColumnsData procedure for the list form specifies which columns
CreateListColumns will be available for the list window. The CreateDefaultColumn() funtion is used to
Data procedure. add columns to a card list. When you add columns, you specify the following:

• Which columns will be available


• Which columns will be displayed
• The default position for the columns
• The initial width for the column
• The default sort order for the column
• Formatting information for each column

The following is a portion of the CreateListColumnsData procedure that defines the


columns for the Leads list. Note that the order the columns are defined in this script
specifies the default order they will have in the list, because the sequence number is
incremented for each additional column.

in ListDictID nListDictID;
in ListID nListID;

local integer nStatus;


local integer nSeq;
local integer nRet;
local integer PRODUCT_ID;

{Set the product ID}


PRODUCT_ID = IG_PROD_ID;

{Delete any existing column information for the list}


nRet = DeleteForListView(nListDictID, nListID, LIST_PRIMARYVIEWID) of form
➥ syListViewColObj;
nSeq = 0;

{--- Marked To Process checkbox ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Marked To Process'){field id},
COLSORTORDER_NONE {sort order},
true {visible},
25 {width},
0, {array index}
0, 0, {no format field }
0, {token ID}
0 {sort seq}) of form syListViewColObj;

{--- Information Icon ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,

246 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

resourceid(field InfoValue){field id},


COLSORTORDER_NONE{sort order},
true{visible},
25{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

{--- Lead Name ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Lead Name'){field id},
COLSORTORDER_ASCENDING{sort order},
true{visible},
180{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

{--- Lead ID ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Lead ID'),
COLSORTORDER_NONE{sort order},
true{visible},
80{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

The column data for your list is stored in the sy07226 table in the DYNAMICS
database. As you create your list, you may need to reset the default columns that
appear for the list. To do this, you will need to delete the appropriate rows for your
list from the sy07226 table.

Add the Notice that the column display names are not part of the column definitions created
GetColumnName in the CreateListColumnsData procedure. The column names are used in various
procedure. locations in the list implementation, so they are defined in a separate procedure
named GetColumnName.

This procedure typically contains a case statement that returns the appropriate
column name, based on the resource ID passed into the procedure. The following is
the GetColumnName procedure for the Leads list in the sample integrating
application.

INTEGRATION GUIDE 247


PA RT 6 LI ST S

in ColFieldID sFieldID;
in ColArrayIndex iColIndex;
out string sColName;

default window to State;

case sFieldID
in [resourceid('Lead ID' of table IG_Leads_MSTR)]
set sColName to "Lead ID";
in [resourceid('Lead Name' of table IG_Leads_MSTR)]
set sColName to "Lead Name";
in [resourceid('Address 1' of table IG_Leads_MSTR)]
set sColName to "Address 1";
in [resourceid('Address 2' of table IG_Leads_MSTR)]
set sColName to "Address 2";
in [resourceid('City' of table IG_Leads_MSTR)]
set sColName to "City";
in [resourceid('State' of table IG_Leads_MSTR)]
set sColName to "State";
in [resourceid('Zip' of table IG_Leads_MSTR)]
set sColName to "ZIP";
in [resourceid('Contact' of table IG_Leads_MSTR)]
set sColName to "Contact";
in [resourceid('Lead Business Category' of table IG_Leads_MSTR)]
set sColName to "Category";
in [resourceid('Potential Revenue' of table IG_Leads_MSTR)]
set sColName to "Potential Revenue";
in [resourceid('Phone 1' of table IG_Leads_MSTR)]
set sColName to "Phone 1";
in [resourceid('Phone 2' of table IG_Leads_MSTR)]
set sColName to "Phone 2";
in [resourceid('Fax' of table IG_Leads_MSTR)]
set sColName to "Fax";
in [resourceid('Qualified Lead' of table IG_Leads_MSTR)]
set sColName to "Qualified";
in [resourceid('Qualification Date' of table IG_Leads_MSTR)]
set sColName to "Qualification Date";
in [resourceid('Lead Source' of table IG_Leads_MSTR)]
set sColName to "Source";
else
set sColName to "<<No Name>>";
end case;

248 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

List options
Add the Each list has numerous options that can be specified by the user, such as which
CreateListOptionsData sections of the list are displayed, and their corresponding sizes. These options are
procedure. stored in a table. A default set of options must be created for the list. This is done by
the CreateListOptionsData procedure. The following is the CreateListOptionsData
procedure for the Lead list. The list has the ID value 1.

local integer nStatus;

{Remove all records for this list.}


nStatus = DeleteForListView(IG_PROD_ID, 1, LIST_PRIMARYVIEWID) of form
➥ syListViewOptionsObj;

{Add the default options record for the list.}


nStatus = CreateDefaultViewRecord(IG_PROD_ID, 1, LISTOPTION_ALLRECORDS,
➥ DATERESTRICT_NONE) of form syListViewOptionsObj;

Add the You can create predefined selections that control what items are displayed in the
FillListOptionsDDL list. These predefined selections appear in the “Restrictions” group displayed in the
procedure. Action Pane for the list. Each item has an integer value associated with it, which is
used to uniquely identify the options. Typically form-level constants are created for
each option. For example, the following constants are defined for the ListObj_Leads
form:

LISTOPTION_LEADSALL: 1
LISTOPTION_LEADSQUALIFIED: 2

The items are added by the FillListOptionsDDL procedure each time the list is
displayed. The list object state variable for the card list is passed into this procedure,
which allows access to the content of the drop-down list.

The following is the FillOptionsDDL procedure for the Leads list. It adds two
options to the list. Notice the constants are used to specify the data values for each
list item.

inout ListObjState list_object;

{Clear any existing items in the list}


clear field(list_object:ListOptionsDDLRef);

{Add items to the list options}


add item "All Leads", LISTOPTION_LEADSALL to
➥ field(list_object:ListOptionsDDLRef);
add item "Qualified Leads", LISTOPTION_LEADSQUALIFIED to
➥ field(list_object:ListOptionsDDLRef);

INTEGRATION GUIDE 249


PA RT 6 LI ST S

Selecting the data to display


Add the GetSortIndex Two procedures you supply for the list are used to control what data will be
procedure. displayed. The first of these is the GetSortIndex procedure. This procedure
examines the column the user has selected to sort the list contents, and then creates
a virtual key for the primary table used for the list. Data in the list will be sorted
using this key.

The following is the GetSortIndex procedure for the Leads list in the sample
integrating application. Notice that pass-through sanScript is used to create a
virtual key for the main table used for the Leads list.

in string sFieldName;
in ColSortOrder nSortOrder;
inout ListObjState list_object;

local text sCommand;


local string sCompileMSG;
local integer DictID = IG_PROD_ID;

pragma(disable warning LiteralStringUsed);

sCommand = "inout ListObjState Me; assign Me:SortIndex as key for " +


➥ "table(Me:'Table Reference') " +
➥ "with KEY_OPTION_ALLOW_DUPLICATES using '" + sFieldName + "'" +
➥ " of table(Me:'Table Reference')";

if nSortOrder = COLSORTORDER_DESCENDING then


sCommand = sCommand + " with KEY_SEGMENT_OPTION_DESCENDING";
end if;
if sFieldName <> technicalname('Lead ID' of
➥ table(list_object:'Table Reference')) then
sCommand = sCommand + CH_COMMA + "'Lead ID'" + " of
➥ table(Me:'Table Reference')";
end if;
sCommand = sCommand + ";";

if execute (DictID ,sCommand, sCompileMSG, list_object) <> 0 then


warning "Error: " + sCompileMSG;
end if;

pragma(enable warning LiteralStringUsed);

Add the SetRange The rows displayed in the list depend on several factors, such as the selection
procedure. option the user chose, or any search restrictions they have applied. The SetRange
procedure applies the appropriate range to the main table for the list, accounting for
any predefined selections or search criteria the user has specified.

The following is the SetRange procedure for the Leads list. It creates a set of range
selection criteria based on the user’s predefined selection and any filter options
specified through the Filter Pane at the top of the list. Every column that can be
displayed in the list must be included in the range restriction. The range where
statement is used to apply the range to the main table for the list.

250 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

inout ListObjState list_object;

local string sRestrict;


local string sFind_SQL;
local text sRestriction;

default window to State;

range clear table(list_object:'Table Reference');

{Qualified Leads only restriction }


if list_object:ListOptionValue = LISTOPTION_LEADSQUALIFIED then
sRestriction = physicalname('Qualified Lead' of table
➥ IG_Leads_MSTR) + CH_EQUAL + str(2);
end if;

{Apply any range restrictions based on the Find text the user entered}
if not empty(list_object:'Find Text') then
if not empty(sRestriction) then
sRestriction = sRestriction + CH_SPACE + SQL_AND + CH_SPACE;
end if;

sRestriction = sRestriction + CH_LEFTPAREN;


sFind_SQL = SQL_FormatStrings(CH_PERCENT + list_object:'Find Text'
➥ + CH_PERCENT);

sRestrict = physicalname('Lead ID' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + sRestrict;

sRestrict = physicalname('Lead Name' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Address 1' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Address 2' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('City' of table IG_Leads_MSTR) + CH_SPACE


➥ + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('State' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Zip' of table IG_Leads_MSTR) + CH_SPACE


➥ + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Contact' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

INTEGRATION GUIDE 251


PA RT 6 LI ST S

sRestrict = physicalname('Lead Business Category' of table


➥ IG_Leads_MSTR) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Potential Revenue' of table


➥ IG_Leads_MSTR) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Phone 1' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Phone 2' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Fax' of table IG_Leads_MSTR) + CH_SPACE


➥ + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Lead Source' of table IG_Leads_MSTR) +


➥ CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestriction = sRestriction + CH_RIGHTPAREN;


end if;

range table(list_object:'Table Reference') where sRestriction;

Filling the list


Add the Refresh The Refresh procedure controls the process of displaying or updating the data
procedure. displayed in the list. The type of action to be performed is passed into this
procedure. If indicated, the procedure must populate the temporary table used for
the list. The procedure must set the range options appropriately, and call the other
procedures that are used during the display process.

Loading the temporary table


For optimal performance, the process that loads the temporary table with data
should be performed by code that is run directly on the SQL Server. One approach
is to use the range copy statement, which will generate a SQL statement that will
copy data from one table to another directly on the server. This is technique used for
the Leads list. Pass-through SQL could also be used for this process.

Avoid using sanScript code, such as copy from table to table when loading the
temporary table with data. Each record copied from the source to the temporary
table will require two calls to the SQL Server, increasing network traffic and the SQL
Server load.

Setting the Information Icon


If the list is displaying the Information Icon for each row, the Refresh procedure
must set the initial value of this column by updating the InfoValue field for each
row in the temporary table used for the list. For optimal performance, this update
operation should be performed using pass-through SQL that will be executed by the
SQL Server.

252 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

The InfoValue field in the temporary table specifies what the Information Icon will
display for a specific row. The InfoValue field is a bitmask field. It has multiple
states that can be set independently. The InfoValue_SetState() function of the
syListObj form in the Dynamics.dic dictionary should be used to specify the values
for the InfoValue column. The icon of the highest-priorty state will be displayed for
the list. The tooltip for the icon will display all of the states that have been set.

As an example, the Leads list examines two conditions that are indicated by the
Information Icon column. The first is whether the lead has been qualified. If the lead
has not been qualified, the InfoValue column (which controls the Information Icon)
is set to the “inactive” state. The following is the basic SQL statement used to find
the qualified state and set the InfoValue field:

set InfoValue = (INFO_VALUE_INACTIVE * ((LISTTEMP.QualifiedLead) % 2))

The SQL statement examines the value of the QualifiedLead field, which has a
drop-down list datatype. This field can have the value 1 (not qualified) or 2
(qualified). The modulus operation (%) will return 1 if the lead is not qualified (1 %
2 = 1). It will return 0 is the lead is qualified (2 % 2 = 0).

The LISTTEMP identifier refers to the physical name of the temporary table used for
the list. The INFO_VALUE_INACTIVE identifier represents the value that the
InfoValue field should be set to when the lead has not been qualified.

The second condition examined will find whether the lead has a record-level note
attached. If a note is attached, the InfoValue column is set to the “note attached”
state. The following is the basic SQL statement used to find whether a note exists for
the current lead. If a record-level note exists, the InfoValue field will be set to
indicate that state:

set InfoValue = (INFO_VALUE_NOTE * (select count(*) from NOTETABLE where


NOTETABLE.NOTEINDX = LISTTEMP.NOTEINDX))

The select statement counts the number of rows in the note master table that have
the same note index as the current row in the list’s temporary table. If a note is
attached for the current row, the value 1 will be returned. Otherwise, the value 0
will be returned.

The LISTTEMP identifier refers to the physical name of the temporary table used for
the list. The NOTETABLE identifier refers to the physical name of the
SY_Record_Notes_MSTR table. The INFO_VALUE_NOTE identifier represents the
value that the InfoValue field should be set to when the lead has a note attached.

The following is the complete Refresh procedure for the Leads list. Notice how it
loads the temporary table for the Leads list, and then uses pass-through SQL to set
the InfoValue field for each row of the list. The InfoValue_SetState() function is
used to retrieve the values used for the InfoValue field.

inout ListObjState list_object;


in integer nRefreshType;
in string sSortColFieldName;
in integer nSortOrder;
optional in string sBackToID;

local boolean fReloadData, fResetRange, fGetNewIndex;


local text SQLCommand;

INTEGRATION GUIDE 253


PA RT 6 LI ST S

local long SQLConnection;


local long SQLStatus;
local string ListTempTable;
local string InfoValueField;
local string QualifiedField;
local string NotesTable;
local integer InfoValueInactive;
local integer InfoValueNote;

default window to State;

pragma(disable warning LiteralStringUsed);

case nRefreshType
in [REFRESHTYPE_CHANGESORT]
fReloadData = true;
fResetRange = true;
fGetNewIndex = true;
in [REFRESHTYPE_RELOAD]
fReloadData = true;
fResetRange = true;
fGetNewIndex = true;
in [REFRESHTYPE_FIND]
fReloadData = true;
fResetRange = true;
fGetNewIndex = false;
in [REFRESHTYPE_RESTRICT]
fReloadData = true;
fResetRange = true;
fGetNewIndex = false;
else {Refresh type is invalid, so do nothing}
fReloadData = false;
fResetRange = false;
fGetNewIndex = false;
end case;

{Change the key if necessary}


if fGetNewIndex then
call GetSortIndex of form ListObj_Leads, sSortColFieldName, nSortOrder,
➥ list_object;
'Field Name' = sSortColFieldName;
ColSortOrder = nSortOrder;
end if;

field(list_object:RecCountStringRef) = getmsg(5965); {Processing...}

if fReloadData then
{Load the temporary table with data}
Table_Truncate(table(list_object:'Table Reference'));

{Set the range on the source table}


range clear table IG_Leads_MSTR;
clear field 'Lead ID' of table IG_Leads_MSTR;
range start table IG_Leads_MSTR by number 1;
fill field 'Lead ID' of table IG_Leads_MSTR;
range end table IG_Leads_MSTR by number 1;

254 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

{Copy the records to the temporary table}


range copy table IG_Leads_MSTR to table(list_object:'Table Reference') by
➥ number 1;

{Be sure the buffer for the referenced table is cleared}


clear table(list_object:'Table Reference');

{Pass-through SQL used to set the InfoValue column}

{Define the values to which the InfoValue column must be set for rows that
meet the criteria}
InfoValue_SetState(InfoValueInactive, INFOVALUE_CUSTOM1) of form
➥ syListObj;
InfoValue_SetState(InfoValueNote, INFOVALUE_NOTEATTACHED) of form
➥ syListObj;

{Get the SQL connection to use}


SQLStatus = SQL_GetConnection(FOREGROUND, SQLConnection) of form
➥ XSQLExec;

{Get the names of the resources to use in the SQL statements}


ListTempTable = Table_GetOSName(table(list_object:'Table Reference'));
InfoValueField = physicalname(InfoValue of table IG_Leads_List_TEMP);
QualifiedField = physicalname('Qualified Lead' of table
➥ IG_Leads_List_TEMP);

NotesTable = Table_GetOSName(table SY_Record_Notes_MSTR);

{Build the SQL statement to execute}


SQLCommand = "update " + ListTempTable
+ " set " + InfoValueField
+ " = (" + str(InfoValueInactive) + " * ((" + ListTempTable + "."
+ QualifiedField + ") % 2)) "
+ " + (" + str(InfoValueNote) + " * (select count(*) from "
+ NotesTable + " where "
+ NotesTable + ".NOTEINDX = " + ListTempTable + ".NOTEINDX)" +
")";

{ Clear the Connection }


SQLStatus = SQL_Clear(SQLConnection);

{ Submit the command to SQL Server.}


SQLStatus = SQL_Execute(SQLConnection, SQLCommand);
if SQLStatus <> 0 then
warning "An unknown SQL error occurred updating data for the list";
SQLStatus = SQL_Clear(SQLConnection);
abort script;
end if;
end if;

if fResetRange then
{Reset the range for the table}
call SetRange of form ListObj_Leads, list_object;
end if;

INTEGRATION GUIDE 255


PA RT 6 LI ST S

if not empty(sBackToID) then


set 'Lead ID' of table(list_object:'Table Reference') to sBackToID;
get table(list_object:'Table Reference');
end if;

pragma(enable warning LiteralStringUsed);

Formatting list data


Add the FormatField The data displayed in the card list is used in other areas of the list, such as the
procedure. Information Pane. It is also used in the reports that can be generated from the list
contents or exported to Microsoft Excel. The formatting applied to this data will
vary, depending on where it is used. For example, when a currency value is
displayed in the Information Pane, you may want it to appear with a currency
symbol. When that same value is exported to Excel, you may want just the numeric
portion without a currency symbol.

To have the Print This List or Send To Excel actions appear in the Action Pane for a list,
you must have the FormatField procedure defined first.

The FormatField procedure for the list is used to specify the formatting for fields in
the list. This procedure is automatically called as each field is displayed in the
Information Pane, used in the reports generated from the list, or exported to Excel.
The procedure has the following parameters:
in reference TableRef;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in integer nFormatFor;
out string sValue;
out integer nAlignment;

The table reference parameter provides access the current record in the temporary
table used for the list. The field and array index paramters indicate which field is
being displayed and may need formatting. The “format for” parameter will be set to
one of the following constants, indicating where the field value is to be used:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

The formatted value is passed back out of the procedure as a string. Consider using
the following functions defined for the syListObj form to help with formatting the
list data:

• List_FormatBoolean()
• List_FormatCurrency()
• List_FormatDate()
• List_FormatInteger()
• List_FormatPhone()
• List_FormatQuantity()
• List_FormatString()
• List_FormatTime()

256 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

You will also specify the alignment of the formatted data value. The last parameter
of the procedure must be set to one of the following constants to specify the
alignment:

Constant Description
ALIGN_LEFT Left-aligned
ALIGN_CENTER Center-aligned
ALIGN_RIGHT Right-aligned

The following example is the FormatField procedure for the Leads card list defined
in the sample integrating application. It formats each of the values that can appear
in the list.

in reference TableRef;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in integer nFormatFor;
out string sValue;
out integer nAlignment;

local string s;

{Assume default left alignment}


nAlignment = ALIGN_LEFT;

case nFieldID
in[resourceid(field 'Lead ID')]
sValue = List_FormatString('Lead ID' of table(TableRef), nFormatFor)
➥ of form syListObj;
in[resourceid(field 'Lead Name')]
sValue = List_FormatString('Lead Name' of table(TableRef), nFormatFor)
➥ of form syListObj;
in[resourceid(field 'Address 1')]
sValue = List_FormatString('Address 1' of table(TableRef), nFormatFor)
➥ of form syListObj;
in[resourceid(field 'City')]
sValue = List_FormatString('City' of table(TableRef), nFormatFor) of
➥ form syListObj;
in[resourceid(field 'State')]
sValue = List_FormatString('State' of table(TableRef), nFormatFor) of
➥ form syListObj;
in[resourceid(field 'Zip')]
sValue = List_FormatString('Zip' of table(TableRef), nFormatFor) of
➥ form syListObj;
in[resourceid(field 'Contact')]
sValue = List_FormatString('Contact' of table(TableRef), nFormatFor)
➥ of form syListObj;
in[resourceid(field 'Lead Business Category')]
'Lead Business Category' of window State = 'Lead Business Category' of
➥ table(TableRef);
sValue = itemname('Lead Business Category' of window State,
➥ 'Lead Business Category' of window State);
in[resourceid(field 'Phone 1')]
sValue = List_FormatPhone('Phone 1' of table(TableRef), nFormatFor) of
➥ form syListObj;

INTEGRATION GUIDE 257


PA RT 6 LI ST S

in[resourceid(field 'Phone 2')]


sValue = List_FormatPhone('Phone 2' of table(TableRef), nFormatFor) of
➥ form syListObj;
in[resourceid(field 'Fax')]
sValue = List_FormatPhone('Fax' of table(TableRef), nFormatFor) of
➥ form syListObj;
in[resourceid(field 'Potential Revenue')]
sValue = List_FormatCurrency('Potential Revenue' of table(TableRef),
➥ 2, nFormatFor, true) of form syListObj;
in[resourceid(field 'Lead Source')]
sValue = List_FormatString('Lead Source' of table(TableRef),
➥ nFormatFor) of form syListObj;
in[resourceid(field 'Qualification Date')]
sValue = List_FormatDate('Qualification Date' of table(TableRef),
➥ nFormatFor) of form syListObj;
else
s = getmsg(6703);{Unknown [%1]}
substitute s, str(nFieldID);
sValue = s;
end case;

Filter tokens
Add the The filtering feature of the card list allows the user to create restrictions that display
GetColumnTokens specific rows in the list. Most fields in the list can be searched without any
procedure. additional coding required for the list. However, some fields (such as list boxes,
drop-down lists, visual switches, and radio groups) require additional coding to
define the tokens that can be used for filtering based on these fields.

The filter tokens provide a user-friendly representation of the data for that field,
making it easy to select the possible values for that field when defining a filter. For
example, the Leads card list has a column for the Lead Business Category. This
column is a drop-down list that stores integer values 1 through 8, representing the
category. Rather than requiring the user need to know which category corresponds
to which value, filter tokens are created for this field to display the category values.

The filter tokens display


meaningful values for the
Category field.

The core list code can automatically produce filter tokens for many list fields. For
the other fields that require filter tokens (typically list fields), you will add code to
the GetColumnTokens procedure you define for your list. This procedure has the
following parameters:

in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

258 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

The GetColumnTokens procedure is called automatically when each column is


added to the list. The parameters for the procedure indicate which column is being
added. You will use the Columns_AutoGenTokensForEnumField() function
function defined for the syListObj form to define the tokens for the field. In certain
special cases, you will need to use the Columns_AddToken() function to create the
filter tokens. Refer to the description of that function for details.

The following example is the GetColumnTokens procedure for the Leads card list. It
defines the filter tokens for the Lead Business Category column, which is based on a
drop-down list.

in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

local boolean status;

if nFieldID = resourceid(field 'Lead Business Category') then


{Can use the auto-generated tokens}
status = Columns_AutoGenTokensForEnumField(list_object,
➥ 'Lead Business Category' of window State, nColumnID) of form syListObj;
end if;

Action Pane
Define constants for The Action Pane allows the user to perform actions on the items selected in the list.
the actions. Adding groups and actions to the Action Pane is a multi-step process. You begin by
defining constants for the actions that you want to add to the Action Pane. For
instance, the following constants were defined for the Leads list:

ACTION_NEWLEAD: 1
ACTION_EDITLEAD: 2
ACTION_VIEWLEAD: 3
ACTION_DELETELEAD: 4
ACTION_QUALIFYLEAD: 5

Create commands and The next step involves creating commands for each action and command lists for
command lists for the each group that will appear in the Action Pane. The commands will contain the
the Action Pane. code that performs the actions. Refer to Commands for the Action Pane on page 212 for
details about creating these commands. Continuing the example, the following
commands and command lists are defined for the Leads list:

• DeleteLead
• EditLead
• NewLead
• QualifyLead
• ViewLead
• CL_ActionsGroup
• CL_GoToGroup
• CL_ModifyGroup
• CL_NewGroup
• CL_ReportsGroup

INTEGRATION GUIDE 259


PA RT 6 LI ST S

The script for each command contains code the will execute the action the user has
chosen. For example, the following is the script defined for the EditLead command.

call ExecuteListAction of form syCardList, ACTION_EDITLEAD;

In some cases, you may want to have the user verify the action before it is
performed. You can learn more about this in Verifying an action on page 219.

Add the Use the CreateListRibbonData procedure to add groups and actions to the Action
CreateListRibbonData Pane for the list you are creating. You will use the functions AddGroup() and
procedure. AddCommand() from the syListViewCmdBarObj form to add the groups and the
actions for each group.

The CreateListRibbonData procedure runs only when no Action Pane items exist for the list.
If you need to add additional items after the initial Action Pane items have been created, use
the technique described in Adding to the Action Pane on page 214.

The CreateListRibbonData procedure for the Leads list creates six groups and adds
the commands to those groups. It also adds the two user-defined groups, which by
default are not visible. The user can add additional commands to these groups
when they customize the Action Pane for the list.

These groups and


commands are added for
the Leads list.

The following is the complete CreateListRibbonData procedure.

in ListDictID nListDictID;
in ListID nListID;

local CmdDictID nCmdDictID, nParentDictID;


local CmdFormID nCmdFormID, nParentFormID;
local CmdID nCmdID, nParentCmdID;
local integer nStatus;
local CmdSequencenSeq, nGroupSeq;

nGroupSeq = 0;

{ Actions group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);
nCmdID = resourceid(command CL_ActionsGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Actions group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

260 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);

{ Qualify Lead }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command QualifyLead),
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Modify group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);
nCmdID = resourceid(command CL_ModifyGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Modify group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);

{ Edit Lead }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command EditLead),
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Delete Lead }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command DeleteLead),
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

INTEGRATION GUIDE 261


PA RT 6 LI ST S

{ New group }
increment nGroupSeq;
nCmdID = resourceid(command CL_NewGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the New group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);

{ New Lead }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command NewLead),
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Restrictions group }
increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTRIBBONGROUP_RESTRICT, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Restrictions group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

{ Include/Exclude Qualified Restriction }


increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTACTION_LISTRESTRICT, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,

262 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Reports group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);
nCmdID = resourceid(command CL_ReportsGroup);

nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,


nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Reports group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

{ Print This List }


increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTACTION_PRINTLIST, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Go To group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);
nCmdID = resourceid(command CL_GoToGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

{ View Lead }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command ViewLead),
LISTACTIONPRIORITY_PRIMARY,

INTEGRATION GUIDE 263


PA RT 6 LI ST S

LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Send To Excel }
increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTACTION_EXPORTTOEXCEL, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ User Defined Group 1 }


increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTRIBBONGROUP_USERDEF1, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
false{visible}) of form syListViewCmdBarObj;

{ User Defined Group 2 }


increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTRIBBONGROUP_USERDEF2, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
false{visible}) of form syListViewCmdBarObj;

Add the To control access for the commands added to the Action Pane, the actions must be
RegisterCommands registered. The RegisterCommands procedure for the list performs this action. In
procedure. this procedure, you will use the List_RegisterGroup() and List_RegisterAction()
functions of the syListObj form to register each item you added to the Action Pane.
The following is the RegisterCommands procedure for the Leads list.

inout ListObjState list_object;

{ Actions }
List_RegisterGroup(list_object, command CL_ActionsGroup) of form syListObj;
List_RegisterAction(list_object, command QualifyLead,
➥ LISTCMDTYPE_MULTISELECT, ACTION_QUALIFYLEAD) of form syListObj;

{ Modify }
List_RegisterGroup(list_object, command CL_ModifyGroup) of form syListObj;
List_RegisterAction(list_object, command EditLead, LISTCMDTYPE_SINGLESELECT,
➥ ACTION_EDITLEAD) of form syListObj;
List_RegisterAction(list_object, command DeleteLead, LISTCMDTYPE_MULTISELECT,
➥ ACTION_DELETELEAD) of form syListObj;

264 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

{ New }
List_RegisterGroup(list_object, command CL_NewGroup) of form syListObj;
List_RegisterAction(list_object, command NewLead,
➥ LISTCMDTYPE_ALWAYSAVAILABLE, ACTION_NEWLEAD) of form syListObj;

{ Reports }
List_RegisterGroup(list_object, command CL_ReportsGroup) of form syListObj;

{ Go To }
List_RegisterGroup(list_object, command CL_GoToGroup) of form syListObj;
List_RegisterAction(list_object, command ViewLead, LISTCMDTYPE_SINGLESELECT,
➥ ACTION_VIEWLEAD) of form syListObj;

Add the The actions in the Action Pane are enabled or disabled automatically, based on the
CheckActionAccessFor number and specific type of lines the user has marked in the list. Microsoft
Record procedure. Dynamics GP tracks two counts for every action in the Action Pane. The “count for”
counter tracks the number of items marked to determine whether the single-select
or multi-select actions should be enabled. The “count against” counter tracks the
number items marked that would prevent an action from being enabled. If there are
any “count against” lines marked, the action will be disabled.

For example, assume that the Qualify action can be performed for the items selected
in the list. This action would be active as long as the user has marked one or more
items to qualify. However, if the user marked an item that had already been
qualified, the “counts against” counter would be incremented, causing the Qualify
action to be disabled.

The Qualify action is


disabled because a lead is
marked that has already
been qualified.

The CheckActionAccessForRecord procedure is called multiple times when the user


marks or unmarks an item in the list. The procedure has the following parameters:

in ListObjState list_object;
in integer nActionCmdTag;
out integer nAccessStatus;

Each time the procedure is called, a command tag is passed in. The procedure
specifies how the item marked or unarked in the list should be considered when
determining whether the action corresponding to that tag should be accessible. You
will use the 'Table Reference' component of the list object composite passed into the
procedure to determine which row is being marked or unmarked in the list.

INTEGRATION GUIDE 265


PA RT 6 LI ST S

The parameter value returned through the “out” parameter this trigger processing
procedure specifies how the marked row should be considered. The value
corresponds to one of the following constants:

Constant Description
LISTACTIONACCESS_COUNT_NEUTRAL The marked row won’t affect the count for the
action.
LISTACTIONACCESS_COUNT_FOR The marked row will increase or decrease the
“count for” counter by one.
LISTACTIONACCESS_COUNT_AGAINST The marked row will increase or decrease the
“count against” counter by one.

The following is the CheckActionAccessForRecord procedure for the Leads list. By


default, the marking or unmarking actions are considered neutral. The Delete, Edit,
View, and Qualify actions have specific conditions for which they will be enabled or
disabled.

in ListObjState list_object;
in integer nActionCmdTag;
out integer nAccessStatus;

nAccessStatus = LISTACTIONACCESS_COUNT_NEUTRAL;

if nActionCmdTag = Command_GetTag(command DeleteLead) then


nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
elseif nActionCmdTag = Command_GetTag(command EditLead) then
nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
elseif nActionCmdTag = Command_GetTag(command ViewLead) then
nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
elseif nActionCmdTag = Command_GetTag(command QualifyLead) then
{Examine whether the lead is already qualified}
if 'Qualified Lead' of table (list_object:'Table Reference') = 1 then
{Lead has not been qualifed}
nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
else
{Lead has already been qualified, so disable that action}
nAccessStatus = LISTACTIONACCESS_COUNT_AGAINST;
end if;
end if;

Add the ExecuteAction To execute the actions you have defined for your list, you will add the
procedure. ExecuteAction procedure. This procedure is called every time a user chooses an
action for the list. The value corresponding to the action is also passed into the
procedure. The procedure must contain the code to perform the action the user
chose.

The ExecuteAction script must also handle the default action for the list window.
The default action occurs when the user presses the Enter key or double-clicks on a
line in the list. The value corresponding to the constant DEFAULT_ACTION
indicates the default action.

Executing an action for a list can be an involved process, since the action can be
performed for multiple items marked in the list. Refer to Performing actions for
marked rows on page 222 for details about processing actions for multiple items.

266 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

The ExecuteAction procedure must also be able to handle any errors that occur
during action processing. Refer to Logging action status on page 223 and Acting on
action errors on page 226 for detailed information about how to log and act on errors
encountered as actions are processed.

The following is the ExecuteAction script for the Leads list in the sample integrating
application. Notice that the list object is passed into the procedure. The reference to
the main table contained in this object is used to find what row the user had marked
in the list for the single-select actions.
inout ListObjState list_object;
in long iAction;

case iAction
in [ACTION_NEWLEAD]
open form IG_Lead_Maintenance;
in [ACTION_EDITLEAD]
open form IG_Lead_Maintenance;
'Lead ID' of window 'Lead Maintenance' of form IG_Lead_Maintenance =
➥ 'Lead ID' of table (list_object:'Table Reference');
run script 'Lead ID' of window 'Lead Maintenance' of form
➥ IG_Lead_Maintenance;
in [ACTION_DELETELEAD]
call DeleteLeads of form ListObj_Leads, list_object;
in [ACTION_VIEWLEAD]
open form IG_Lead_Inquiry;
'Lead ID' of window IG_Lead_Inquiry of form IG_Lead_Inquiry =
➥ 'Lead ID' of table (list_object:'Table Reference');
run script 'Lead ID' of window IG_Lead_Inquiry of form
➥ IG_Lead_Inquiry;
in [ACTION_QUALIFYLEAD]
call QualifyLeads of form ListObj_Leads, list_object;
in [DEFAULT_ACTION]
open form IG_Lead_Maintenance;
'Lead ID' of window 'Lead Maintenance' of form IG_Lead_Maintenance =
➥ 'Lead ID' of table (list_object:'Table Reference');
run script 'Lead ID' of window 'Lead Maintenance' of form
➥ IG_Lead_Maintenance;
end case;

Information Pane
Add the The Information Pane for the list provides additional details about the row that is
GeneratePreviewPane currently selected in the list. When the user selects a row, the
XML procedure. GeneratePreviewPaneXML procedure for the list is called. This procedure builds an
XML file that displays detailed information about the selected row.

The layout of the Information Pane depends on the type of list being displayed. For
card lists, the Information Pane contains three columns. Within each column are a
series of label-value pairs that display information about the selected item. The
following illustration shows the Information Pane for the Leads card list.

INTEGRATION GUIDE 267


PA RT 6 LI ST S

The GeneratePreviewPaneXML procedure for the list is run each time a user selects
a row in the list. This procedure has the following parameters:

inout ListObjState list_object;


inout string XMLFilePath;
inout string sTitle;

First, the title used for the Information Pane content is constructed. This value will
be passed out through the last parameter for the procedure. Then the
XMLDoc_Create procedure of the syListObj form starts the process of creating the
Information Pane content. To create the items in the header section, the
XMLDoc_AddHeaderField procedure of the syListObj form is used. This
procedure adds a data item to the end of the specified column. Finally, the
XMLDoc_Save procedure of the syListObje form completes the XML document
used for the Information Pane.

The following is the GeneratePreviewPaneXML procedure for the Leads list. It


displays additional information about the selected lead.

inout ListObjState list_object;


inout string XMLFilePath;
inout string sTitle;

local ListPrevPaneXMLState XMLState;


local string sName;
local string sValue;
local integer iAlignment;
local reference Leads_MSTR_Temp;

{Get the reference for the temporary table used by the list}
Leads_MSTR_Temp = list_object:'Table Reference';

sTitle = str('Lead ID' of table(Leads_MSTR_Temp)) + CH_SPACE + CH_COLON +


➥ CH_SPACE + 'Lead Name' of table(Leads_MSTR_Temp);

{ Build up basic XML file }


call XMLDoc_Create of form syListObj, XMLState, XMLFilePath, sTitle;

{Add the fields that will be displayed}

{--Column 1--}

{Address}
sValue = 'Address 1' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "Address", sValue, 1;
sValue = 'Address 2' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "", sValue, 1;

{City, State, Zip}


sValue = 'City' of table(Leads_MSTR_Temp) + ", " + 'State' of
➥ table(Leads_MSTR_Temp) + " " + 'Zip' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "", sValue, 1;

{Phone 1}
call GetColumnName of form ListObj_Leads, resourceid(field 'Phone 1'), 0,
➥ sName;

268 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field


➥ 'Phone 1'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 1;

{Phone 2}
call GetColumnName of form ListObj_Leads, resourceid(field 'Phone 2'), 0,
➥ sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Phone 2'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 1;

{Fax}
call GetColumnName of form ListObj_Leads, resourceid(field 'Fax'), 0, sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Fax'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 1;

{--Column 2--}

{Lead Category}
call GetColumnName of form ListObj_Leads, resourceid(field
➥ 'Lead Business Category'), 0, sName;
sValue = itemname('Lead Business Category' of window State,
➥ 'Lead Business Category' of table(Leads_MSTR_Temp));
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 2;

{Contact}
call GetColumnName of form ListObj_Leads, resourceid(field 'Contact'), 0,
➥ sName;
sValue = 'Contact' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 2;

{Potential Revenue}
call GetColumnName of form ListObj_Leads, resourceid(field
➥ 'Potential Revenue'), 0, sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp,
➥ resourceid(field 'Potential Revenue'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 2;

{--Column 3--}

{Qualified Lead}
call GetColumnName of form ListObj_Leads, resourceid(field 'Qualified Lead'),
➥ 0, sName;
sValue = itemname('Qualified Lead' of window State, 'Qualified Lead' of
➥ table(Leads_MSTR_Temp));
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 3;

{Qualification Date}
call GetColumnName of form ListObj_Leads, resourceid(field
➥ 'Qualification Date'), 0, sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp,
➥ resourceid(field 'Qualification Date'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 3;

INTEGRATION GUIDE 269


PA RT 6 LI ST S

{Source}
call GetColumnName of form ListObj_Leads, resourceid(field 'Lead Source'), 0,
➥ sName;
sValue = 'Lead Source' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 3;

{Save the XML document.}


call XMLDoc_Save of form syListObj, XMLState;

Business Analyzer
Beginning with Microsoft Dynamics GP 2010 R2, a list page can display the
Business Analyzer. The Business Analyzer displays SQL Server Reporting Services
(SSRS) reports that supplement the list data.

Add the The Business Analyzer is available only if it has been enabled for the list. The
CheckFactBoxEnabled CheckFactBoxEnabled procedure for the list is is used to do this. If the value true is
procedure. returned, the Business Analyzer will be available for the list. The following is the
CheckFactBoxEnabled procedure for the Leads list. It indicates that the Business
Analzyer is available for the list.
in ListDictID nListDictID;
in ListID nListID;
out boolean fEnabled;

fEnabled = true;

Add the To specify the initial set of SSRS reports that will be displayed for the Business
CreateListFactBoxData Analyzer, you must add the CreateListFactBoxData procedure to the list. This
procedure. procedure uses the CreateDefaultFactBox() function to add the default reports that
will be displayed in the Business Analyzer for the list. The following is the
CreateListFactBoxData procedure for the Leads list. It adds two reports that will be
available by default in the Business Analyzer for the Leads list.
in ListDictID nListDictID;
in ListID nListID;

local integer nStatus;


local 'Sequence Number' nSeq;
local integer nRet;

{ Remove all reports for the default list. }


nRet = DeleteForListView(nListDictID, nListID, LIST_PRIMARYVIEWID) of form
syListViewFactBoxReportsObj;

{ Add the default set of SSRS reports for the list. }


nSeq = 0;

increment nSeq;
nStatus = CreateDefaultFactBox(
nListDictID,
nListID,
nSeq,
"%Company%/Sales/Charts And KPIs/",
"Lead Potential Revenue",
LIST_PRIMARYVIEWID) of form syListViewFactBoxReportsObj;

270 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

increment nSeq;
nStatus = CreateDefaultFactBox(
nListDictID,
nListID,
nSeq,
"%Company%/Sales/Charts And KPIs/",
"Leads Per Salesperson",
LIST_PRIMARYVIEWID) of form syListViewFactBoxReportsObj;

Add the Load Some of the reports that are being displayed in the Business Analyer may have
FactBoxParameters parameters that control what data is displayed by the report. One of the parameter
procedure. values can come from the rows the user has marked or selected in the list. For
example, you might want to pass a parameter that contains the Lead IDs for the
leads that the user has marked in the Leads list. You can add the
LoadFactBoxParameters procedure to the list to set the values for this parameter.

The reports displayed in the Business Analyzer for the list don’t have to use the parameter. If
they don’t have a parameter with the specified name, the parameter is ignored.

There is a maximum total length for the parameters passed to the report for the
Business Analyzer. If you mark a very large number of items in the list, you might
exceed this limit. As the parameter list is built, the core list object will keep track of
the length. If it is exceeded, a message will be displayed in the status bar for the list
and no additional values will be added to the parameter.

The following example is the LoadFactBoxParameters procedure for the Leads list.
It adds an additional parameter that contains the Lead IDs for each lead that is
selected in the list.
inout ListObjState list_object;
inout reference tableRef;
in boolean fMultipleMarked;

local text LeadParam;


local integer nStatus;
local boolean fParamTooLong;

if fMultipleMarked then

{ Look through the list of marked leads, and add each one. }
get first table(tableRef);
nStatus = err();
while nStatus <> EOF do
call FactBoxParameter_Add of form syListObj, list_object, LeadParam,
➥ 'Lead ID' of table(tableRef), fMultipleMarked, fParamTooLong;
if fParamTooLong then
exit while;
end if;

get next table(tableRef);


nStatus = err();
end while;
else
{ Add only the selected lead. }
call FactBoxParameter_Add of form syListObj, list_object, LeadParam,
➥ 'Lead ID' of table(tableRef);
end if;

INTEGRATION GUIDE 271


PA RT 6 LI ST S

{ Set the parameter that will be available for each report. }


call List_SetFactBoxParameter of form syListObj, list_object,
physicalname('Lead ID' of table IG_Leads_List_TEMP), LeadParam;

Row selection actions


Add the LinePre Depending on the type of data displayed in your list, you may want to perform
procedure. additional processing when the user focuses on a row in the list. The LinePre
procedure is run every time the user focuses to a new line. The list object for the list
is passed into each of these scripts. This provides access to the main table and other
resources for the list.

Open and closing


Add the Initialize The Initialize procedure is used to prepare a list to display data. It performs the
procedure. following:

• Opens the list object form


• Sets the list type
• Sets the title for the list
• Fills the Options drop-down list
• Sets the initial sort column
• Registers the commands used in the Action Pane

The following is the Initialize procedure for the Leads list in the sample integrating
application.
inout ListObjState list_object;
inout string sWindowTitle;
inout integer nStatus;

default window to State;

{Open the Leads list object}


nStatus = OKAY;
open form ListObj_Leads;
if not isopen(form ListObj_Leads) then
nStatus = FAILED;
abort script;
end if;

{Set the list type}


list_object:ListType = LISTTYPE_CARD;

{Set the window title and header title}


sWindowTitle = "Leads";
field(list_object:HeaderTextRef) = "Leads";

{Fill the Restrictions drop-down list}


call FillListOptionsDDL of form ListObj_Leads, list_object;

{Set the initial sort}


ColSortOrder = 1;

{Register the commands used for the Action Pane}


call RegisterCommands of form ListObj_Leads, list_object;

272 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

Add the Close When the user displays another page or list, the Close procedure for the list is run.
procedure. This procedure must perform any clean-up actions for the list, such as closing the
list object form, or removing data from temporary tables used for the list. The
following is the Close procedure for the Leads list in the sample integrating
application.
inout ListObjState list_object;

list_object:IsCreated = false;
close form ListObj_Leads;

List navigation
Define the command A list window is actually opened using a command that you define. Commands to
to open the list open lists must have the type DataList, and specify the form that provides the base
window. functionality for the list.

The command that opens the Leads list in the sample integrating application has
the following characteristics:

Command Name: ListObj_Leads


Display Name: Leads
Type: Data List
Data List Form: syListObj
Image Type: Icon
Normal Image: ListPage

Add the command to A separate procedure in Microsoft Dynamics GP is used to create the items that
the Navigation Pane appear in each section of the Navigation Pane. The following table lists the
menu structure. procedures used for each:

Navigation Pane section Procedure


Administration CreateMenu_Administration_NavButton
Field Service CreateMenu_FieldService_NavButton
Financial CreateMenu_Financial_NavButton
HR & Payroll CreateMenu_Payroll_NavButton
Inventory CreateMenu_Inventory_NavButton
Manufacturing CreateMenu_Manufacturing_NavButton
Project CreateMenu_ProjectAccounting_NavButton
Purchasing CreateMenu_Purchasing_NavButton
Sales CreateMenu_Sales_NavButton

A procedure trigger registered for one of these procedures is used to add the list
command to the appropriate location in the Navigation Pane menu structure. For
example, the following is the procedure trigger registration that adds the
Navigation Pane items for the sample integrating application.

INTEGRATION GUIDE 273


PA RT 6 LI ST S

l_result = Trigger_RegisterProcedure(script CreateMenu_Sales_NavButton,


TRIGGER_AFTER_ORIGINAL, script IG_CreateNavBarItems);
if l_result <> SY_NOERR then
warning "Procedure trigger for CreateMenu_Sales_NavButton failed.";
end if;

The trigger processing procedure has the following parameters, which indicate the
command list to which commands should be added:

in CmdParentDictID ParentDictID;
in CmdParentFormID ParentFormID;
in CmdParentCmdID ParentCmdID;
in integer LoadMode;

The following is the trigger processing procedure that adds the ListObj_Leads
command to the Sales section of the Navigation Pane:

in CmdParentDictID ParentDictID;
in CmdParentFormID ParentFormID;
in CmdParentCmdID ParentCmdID;
in integer LoadMode;

local integer Seq;


local integer Status;

{Add the Leads command to access the Leads list}


{Find the appropriate location to add the item, after Salespeople}
Seq = FindCommandInMenu(ParentDictID,
ParentFormID,
ParentCmdID,
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command ListObj_Salespeople of form Command_Sales),
LoadMode,
"");

{If the item was found, add the new item after it.}
if Seq <> 0 then
Seq = Seq + 1;
end if;

Status = AddCommandToMenu(ParentDictID,
ParentFormID,
ParentCmdID,
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command ListObj_Leads of form Command_IG_Sample),
true,
LoadMode);

274 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

Register the list The final step to making the list accessible is registering it. This is typically
command. performed in the form pre script for the command form that defines the list
navigation command. The registration process does the following:

• Identifies the list


• Indicates the form that defines the list content
• Specifies the list type
• Indicates the Navigation Pane section the command appears in

The RegisterListNavigationCommand() function registers the command that will


open the list. The following example is the form pre script for the
Command_IG_Sample form defined in the sample integrating application. It
registers the navigation command that opens the Leads list. The Leads list is
assigned the ID value “1”.

Consider creating a constant for the list ID value. For instance, the constant
LISTID_LEADS is used for the Leads list in the sample integrating application.

local boolean result;

result = RegisterListNavigationCommand(command ListObj_Leads,


IG_PROD_ID,
1,
IG_PROD_ID,
resourceid(form ListObj_Leads),
0,
LISTTYPE_CARD,
command SalesButton of form Command_NavBar) of form syListObj;

Custom list views


Each list has a primary view that is read-only. Users can save a copy of the primary
view, and then make changes to the columns, Action Pane buttons, and filter criteria
for the new view. When you install your integration, you may want to include some
custom views for your lists. For instance, the sample integrating application
includes a “High Revenue” view for the Leads list.

This custom view was


added by the sample
integrating application.

INTEGRATION GUIDE 275


PA RT 6 LI ST S

Custom list views are added when the integration is installed, before the list has
even been accessed the first time. To add custom list views, you will register a
procedure trigger for the CreateDefaultListViews procedure of the syListObj form.
The following example shows this trigger registration for the sample integrating
application.

l_result = Trigger_RegisterProcedure(script CreateDefaultListViews of form


➥ syListObj, TRIGGER_AFTER_ORIGINAL, script
➥ IG_CreateDefaultCustomListViews);
if l_result <> SY_NOERR then
warning "Trigger registration for CreateDefaultListViews failed.";
end if;

The trigger processing procedure that runs in response this trigger must determine
whether the primary and custom views have already been added. If they have, no
action should be taken. If no views have been added, the script must add the
primary view for the list. After the primary view is added, it must add each custom
view, specifying the unique characteristics of each view. The custom view can
specify a different set of columns to display, different items in the Action Pane, and
special filtering criteria for the data. If the custom view doesn’t specify its own set of
columns, Action Pane items, or filtering criteria, the settings from the primary list
view will be used.

Filtering criteria is the most common change made for custom list views. Microsoft
Dynamics GP uses a special syntax for defining the filtering criteria applied to a list.
The syntax can be complex. Don’t attempt to write the filtering expression
manually. Instead, in Microsoft Dynamics GP use the filter pane for the list to define
the filter criteria. When you save the list view, the filter criteria will be saved in the
SY07230 table in the DYNAMICS database. Copy the filter criteria from the
FilterCritera column of this table for use in the script that will add the custom list
view. For example, the following expression is the filtering criteria for the Leads list
that restricts the data displayed to show leads with a potential revenue of $50,000 or
greater. It was created using the filter pane for the Leads list, and then copied from
the SY07230 table.

<criteria><or><and><eval property="PotentialRevenue" operator="is greater


than and includes" value1="50000" value2="" /></and></or></criteria>

The following example is the trigger processing procedure that adds the custom list
view for the Leads list in the sample integrating application. It uses the Exists()
function of the syListViewObj form to find out whether views for the Leads list
have been added. If they haven’t, it uses the CreateDefaultViewRecord() -- View
function to add the primary view, and the CreateDefaultCustomViewRecord()
function to add the custom view (named”High Revenue”). Finally, the procedure
specifies the characteristics of the custom view. The columns and Action Pane items
are unchanged from the primary view, so no script code is needed. New filter
criteria are applied for the custom view. Notice how the filter criteria shown
previously is converted into a string in the sanScript code. All quotes in this criteria
string are replaced with the QUOTE constant. Functions from the
syListViewFiltersObj form write the updated criteria for the custom list view.

local integer nStatus;


local long viewID;
local syListViewFiltersState syListViewFilters;
local FilterCriteria sFilterCriteria;

276 IN T E G R AT I O N G U ID E
C H A PT E R 2 9 C A R D L IS T S

{Does the primary view exist for the list?}


if Exists(IG_PROD_ID, LISTID_LEADS, LIST_PRIMARYVIEWID) of form
➥ syListViewObj = false then

{Create the primary view record}


nStatus = CreateDefaultViewRecord(IG_PROD_ID, LISTID_LEADS) of form
➥ syListViewObj;

{Create the custom view record for the 'High Revenue' view}
nStatus = CreateDefaultCustomViewRecord(IG_PROD_ID, LISTID_LEADS,
➥ "High Revenue", 1, viewID) of form syListViewObj;

if nStatus = OKAY then

{Add the information about the custom view.}

{Add the columns for the custom view.}


{If the custom view will have a different set of columns than the
primary view does, call a routine that defines the columns. The
routine will be similar to the routine that creates columns for
the primary view, but will use the viewID that was returned
when the custom view was created, rather than the constant
LIST_PRIMARYVIEWID. If the columns will be the same as the
primary view, no additional code is required.}

{Add the Action Pane items for the custom view.}


{If the custom view will have a different set of actions than the
primary view does, call a routine that defines the actions. The
routine will be similar to the routine that creates actions for
the primary view, but will use the viewID that was returned
when the custom view was created, rather than the constant
LIST_PRIMARYVIEWID. If the actions will be the same as the
primary view, no additional code is required.}

{Define the filter criteria for the custom view}


sFilterCriteria = "<criteria><or><and><eval property="+
➥ QUOTE + "PotentialRevenue" + QUOTE + " operator=" + QUOTE +
➥ "is greater than and includes" + QUOTE + " value1=" + QUOTE +
➥ "50000" + QUOTE + " value2=" + QUOTE + QUOTE +
➥ " /></and></or></criteria>";

nStatus = Create(syListViewFilters, table syListViewFilters,


➥ IG_PROD_ID, LISTID_LEADS, viewID, MODE_CHG) of form
➥ syListViewFiltersObj;
if nStatus = OKAY then
call SetFilterCriteria of form syListViewFiltersObj,
syListViewFilters,
sFilterCriteria;

nStatus = Commit(syListViewFilters) of form syListViewFiltersObj;


call Destroy of form syListViewFiltersObj, syListViewFilters;
end if;
end if;
end if;

INTEGRATION GUIDE 277


278 IN T E G R AT I O N G U ID E
Chapter 30: Transaction Lists
A transaction list displays a list of date-specific information in the accounting
system, such as receivables transactions or inventory transactions. A transaction list
is very similar to a card list, but has additional capabilities that allow date
restrictions to be applied to filter the content of the list.

If you maintain date-specific information within your integration, you may want to
implement a transaction list to display that information. The sample integrating
application implements a Contact History list, which displays date-specific
information about customer contacts.

Information about implementing a transaction list is divided into the following


sections:

• Transaction list form


• Checking access
• Creating a temporary table
• Attaching tables
• Table access
• List columns
• List options
• Loading the temporary table
• Selecting the data to display
• Filling the list
• Formatting list data
• Filter tokens
• Action Pane
• Information Pane
• Business Analyzer
• Row selection actions
• Open and closing
• List navigation
• Custom list views

INTEGRATION GUIDE 279


PA RT 6 LI ST S

Transaction list form


Create the transaction Each transaction list is a separate form in the dictionary. This form serves as a base
list form. for the transaction list table references, scripts, and state information. To make
creating a transaction list easier, a basic template for a transaction list form is
provided with Dexterity.

Importing the transaction list template


To import the card list template and begin creating a card list, complete the
following procedure:

1. Open your development dictionary.


With Dexterity, open your development dictionary.

2. Import an item from a text file.


In the Explorer menu, choose Import From Text File.

3. Select the card list form template.


Click the lookup button in the Import From Text File window. Using the dialog
displayed, select the ListObjTrxGeneric.form located in the Develop folder
inside the Samples folder for Dexterity.

4. Import the form.


Click Import to import the template into your dictionary.

5. Rename the form.


Rename the form to a name more appropriate for your integration. Using the
standard convention for naming transaction list forms, the name would begin
with ListObj_ and end with the name of the item that will be displayed in the
list. For example, the transaction list form included in the sample integrating
application is named ListObj_ContactHistoryTrx.

Checking access
Add the The CheckListAccess procedure for the transaction list form is used to control
CheckListAccess access to the transaction list. In releases prior to Microsoft Dynamics GP 10, this
procedure. procedure contained code to verify that the user has access to the primary form
used to manage the data that is displayed in the list. If the user didn’t have access to
the form, access to the card list was denied. Beginning with Microsoft Dynamics GP
10, security tasks are used to control access to card lists. Refer to Security task
operations on page 395 for information about creating security task operations that
control access to specific list features.

The CheckListAccess procedure can still be used to control access to a list. For
instance, you may not want to allow a list to be displayed if a specific module hasn’t
been registered. To grant access, the procedure should return true. Otherwise, the
procedure should return false.

For contact history in the sample integration, the CheckListAccess procedure


always allows access. Security for this list is controlled through security tasks:

in long nSubList;
inout boolean bSuccess;

bSuccess = true;

280 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

Creating a temporary table


The content for the transaction list comes from a temporary table that you will
create for the list. Typically, this table contains the same fields as the various
transaction tables that stores the data you want to display in the list. Be sure the
temporary table has the following characteristics:

• The table physical name must be TEMP

• The database type must be SQL

Add additional fields to Some additional fields from the Dynamics.dic dictionary must be added to the
the temporary table. temporary table. These are:

InfoValue This field is used for the information icon that can be displayed for
each row in the list. This field is required only if the information icon will be
displayed. You may want to add this field now, in the event it is needed later for
your list.

Marked To Process The field is used for the check mark displayed for each row.
It is required for every list.

Attaching tables
Attach tables to the The content of a transaction list comes from the temporary table that is defined for
transaction list. the list. Any of the other tables used to populate the temporary table must be
attached to the list form. Use the Form Definition window to attach these tables to
the transaction list form.

For the Contact History list in the sample integration, the ContactHistoryTrxTemp
table was created and attached to the ListObj_ContactHistoryTrx form. This is the
main table that will be used to display data in the list. The
IG_ContactHistory_MSTR table and the RM_Customer_MSTR table are also
attached, since they contain the data that will be added to the temporary table for
the list.

Table access
Assign a reference to The syTrxList form in the Dynamics.dic dictionary must be able to access the main
the main table. table used for your transaction list. A reference to the main table for the transaction
list provides this access. You create this reference using a global procedure for your
integration. For example, the following is the procedure in the sample integrating
application that creates a reference to the ContactHistoryTrxTemp table for the
Contact History list.

Procedure name: AssignTableRef_ContactHistoryList

if isopen(form syTrxList) then


assign ListObjState:'Table Reference' of window TrxList of form
➥ syTrxList as reference to table ContactHistoryTrxTemp;
end if;

Add the The procedure that assigns the table reference must be called each time the
RegisterTableRef transaction list is opened. This in done using a trigger that will call the
Trigger procedure. AssignTableRef procedure you just created. The procedure trigger is created in the
RegisterTableRefTrigger procedure that is part of your transaction list form. The
following is the RegisterTableRefTrigger procedure for the Contact History list.

INTEGRATION GUIDE 281


PA RT 6 LI ST S

out integer nTriggerTag;

local integer nStatus;

nStatus = Trigger_RegisterFocus(anonymous('Attach Button' of window TrxList


➥ of form syTrxList), TRIGGER_FOCUS_CHANGE, TRIGGER_AFTER_ORIGINAL, script
➥ AssignTableRef_ContactHistoryList, nTriggerTag);
if nStatus <> SY_NOERR then
error "Could not register the RegisterTableRefTrigger for the
➥ Contact History list";
end if;

The tag for this trigger is automatically saved so that this trigger can be unregistered when
the list is closed or another list is displayed.

List columns
Add the The CreateListColumnsData procedure for the list form specifies which columns
CreateListColumns will be available for the list window. The CreateDefaultColumn() funtion is used to
Data procedure. add columns to a card list. When you add columns, you specify the following:

• Which columns will be available


• Which columns will be displayed
• The default position for the columns
• The initial width for the column
• The default sort order for the column
• Formatting information for each column

The following is a portion of the CreateListColumnsData procedure that defines the


columns for the Contact History list. Note that the order the columns are defined in
this script specifies the default order they will have in the list, because the sequence
number is incremented for each additional column.
in ListDictID nListDictID;
in ListID nListID;

local integer nStatus;


local integer nSeq;
local integer nRet;
local integer PRODUCT_ID;

{Set the product ID}


PRODUCT_ID = IG_PROD_ID;

nRet = DeleteForListView(nListDictID, nListID, LIST_PRIMARYVIEWID, "") of


➥ form syListViewColObj;
nSeq = 0;

{--- checkbox ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Marked To Process'){field id},
COLSORTORDER_NONE{sort order},
true{visible},

282 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

25{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

{--- information icon ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field InfoValue){field id},
COLSORTORDER_NONE{sort order},
true{visible},
25{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

{--- Customer Number ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Customer Number'){field id},
COLSORTORDER_ASCENDING{sort order},
true{visible},
100{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

{--- Customer Name ---}


increment nSeq;
nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Customer Name'){field id},
COLSORTORDER_NONE{sort order},
true{visible},
150{width},
0,
0, 0, { no format field }
0, {token ID}
0{sort seq}) of form syListViewColObj;

INTEGRATION GUIDE 283


PA RT 6 LI ST S

The column data for your list is stored in the sy07226 table in the DYNAMICS
database. As you create your list, you may need to reset the default columns that
appear for the list. To do this, you will need to delete the appropriate rows for your
list from the sy07226 table.

Add the Notice that the column display names are not part of the column definitions created
GetColumnName in the CreateListColumnsData procedure. The column names are used in various
procedure. locations in the list implementation, so they are defined in a separate procedure
named GetColumnName.

This procedure typically contains a case statement that returns the appropriate
column name, based on the resource ID passed into the procedure. The following is
the GetColumnName procedure for the Contact History list in the sample
integrating application.

in ColFieldID sFieldID;
in ColArrayIndex iColIndex;
out string sColName;

default window to State;

case sFieldID
in [resourceid('Customer Number' of table ContactHistoryTrxTemp)]
set sColName to "Customer ID";
in [resourceid('Customer Name' of table ContactHistoryTrxTemp)]
set sColName to "Customer Name";
in [resourceid('First Contact Date' of table ContactHistoryTrxTemp)]
set sColName to "First Contact";
in [resourceid('Last Contact Date' of table ContactHistoryTrxTemp)]
set sColName to "Last Contact";
in [resourceid('Contact Salesperson ID' of table ContactHistoryTrxTemp)]
set sColName to "First Contact Salesperson";
in [resourceid('Contact Salesperson ID 2' of table
➥ ContactHistoryTrxTemp)]
set sColName to "Last Contact Salesperson";
in [resourceid('Active' of table ContactHistoryTrxTemp)]
set sColName to "Active";
else
set sColName to "<<No Name>>";
end case;

List options
Add the Each list has numerous options that can be specified by the user, such as which
CreateListOptionsData sections of the list are displayed, and their corresponding sizes. These options are
procedure. stored in a table. A default set of options must be created for the list. This is done by
the CreateListOptionsData procedure. The following is the CreateListOptionsData
procedure for the Contact History list. The list has the ID value 2.

local integer nStatus;

{Remove all records for this list.}


nStatus = DeleteForListView(IG_PROD_ID, 2, LIST_PRIMARYVIEWID) of form
➥ syListViewOptionsObj;

284 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

{Add the default options record for the list.}


nStatus = CreateDefaultViewRecord(IG_PROD_ID, 2, LISTOPTION_ALLRECORDS,
➥ DATERESTRICT_LAST90DAYS) of form syListViewOptionsObj;

Add the You can create predefined selections that control what items are displayed in the
FillListOptionsDDL list. These predefined selections appear in the “Restrictions” group displayed in the
procedure. Action Pane for the list. Each item has an integer value associated with it, which is
used to uniquely identify the options. Typically form-level constants are created for
each option. For example, the following constants are defined for the
ListObj_ContactHistoryTrx form:

LISTOPTION_CONTACTSSALL: 1
LISTOPTION_CONTACTSACTIVE: 2

The items are added by the FillListOptionsDDL procedure each time the list is
displayed. The list object state variable for the transaction list is passed into this
procedure, which allows access to the content of the drop-down list.

The following is the FillOptionsDDL procedure for the Contact History list. It adds
two options to the list. Notice the constants are used to specify the data values for
each list item.

inout ListObjState list_object;

{Clear any existing items in the list}


clear field(list_object:ListOptionsDDLRef);

{Add items to the list options}


add item "All Customers", LISTOPTION_CONTACTSALL to
➥ field(list_object:ListOptionsDDLRef);
add item "Active Customers", LISTOPTION_CONTACTSACTIVE to
➥ field(list_object:ListOptionsDDLRef);

Loading the temporary table


To load data into temporary table used for transaction list, you must write several
procedures that work together to add the records to the temporary table. For
transaction lists, the data loading process runs in the background, and can be
stopped by the user, so these procedures must have special code to handle this
situation.

If you don’t want the user to be able to stop the data loading process for your transaction list,
you won’t need to have these procedures. Instead, you can load data into the transaction list
using the same technique used for the card list.

Add the LoadData The LoadData procedure actually loads the data into the temporary table. The name
procedure. given to this procedure typically indicates which table the data is being loaded into.
For example, the LoadData_ContactHistoryTrxTemp procedure is used to load data
in to the temporary table for the Contact History list.

The LoadData procedure uses the OkCallBackScript callback procedure defined in


the transaction list object form. This callback is used to find out whether the user
has stopped the data loading process for the list. After every group of 10 records is
loaded, the callback should be checked to find whether the user has clicked Stop.

INTEGRATION GUIDE 285


PA RT 6 LI ST S

If the transaction list will be displaying the Information Icon, this procedure should
also set the initial value of the InfoValue field that is part of the temporary table
definition. The InfoValue_SetState() function of the syListObj form in the
Dynamics.dic dictionary should be used to specify the values for the InfoValue
column. The icon of the highest-priorty state will be displayed for the list. The
tooltip for the icon will display all of the states that have been set.

The following is the LoadData_ContactHistoryTrxTemp procedure that loads the


temporary table for the Contact History list. Notice that it retrieves data from the
following tables:

• RM_Customer_MSTR
• IG_Contact_History_MSTR

Notice that it uses the OKCallBackScript callback from the list object, and that it also
keeps track of the total number of records added to the temporary table. The
procedure also sets the initial value of the Information Icon that is displayed for the
list.
inout ListObjState list_object;
inout long nRecCount;

local integer nStatus;


local text sCriteria;
local string sStartDateRestrict, sEndDateRestrict;
local boolean fOk;
local integer iCount;

default window to State;

range clear table RM_Customer_MSTR;

get first table RM_Customer_MSTR;


nStatus = err();

while nStatus <> EOF do


increment nRecCount;

clear table(list_object:'Table Reference');

{Get data from the RM_Customer_MSTR table}


'Customer Number' of table(list_object:'Table Reference') =
➥ 'Customer Number' of table RM_Customer_MSTR;
'Customer Name' of table(list_object:'Table Reference') =
➥ 'Customer Name' of table RM_Customer_MSTR;
'Active' of table(list_object:'Table Reference') = not 'Inactive' of
➥ table RM_Customer_MSTR;

{Set the value to use for the Information Icon column}


if Hold of table RM_Customer_MSTR = true then
InfoValue_SetState(InfoValue of table(list_object:'Table Reference'),
➥ INFOVALUE_ONHOLD) of form syListObj;
else
InfoValue_ClearState(InfoValue of table(list_object:
➥ 'Table Reference'), INFOVALUE_ONHOLD) of form syListObj;
end if;

286 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

{Get data from the IG_Contact_History_MSTR table}


'Customer Number' of table IG_Contact_History_MSTR =
➥ 'Customer Number' of table(list_object:'Table Reference');
get table IG_Contact_History_MSTR by number 1;

if err() = OKAY then


'First Contact Date' of table(list_object:'Table Reference') =
➥ 'First Contact Date' of table IG_Contact_History_MSTR;
'Contact Salesperson ID' of table(list_object:'Table Reference') =
➥ 'Contact Salesperson ID' of table IG_Contact_History_MSTR;

'Last Contact Date' of table(list_object:'Table Reference') =


➥ 'Last Contact Date' of table IG_Contact_History_MSTR;
'Contact Salesperson ID 2' of table(list_object:'Table Reference') =
➥ 'Contact Salesperson ID 2' of table IG_Contact_History_MSTR;
end if;

{Save the record in the temporary table}


save table(list_object:'Table Reference');

field(list_object:RecCountStringRef) = str(nRecCount) + CH_SPACE +


➥ '(L) TrxString';
field(list_object:LoadingRecCountStringRef) = '(L) LoadingString'
➥ + CH_SPACE + str(nRecCount) + CH_SPACE + '(L) TrxString';

increment iCount;
if iCount = 10 then {Check if we should continue}
call foreground with name list_object:OkCallBackScript in
➥ dictionary DYNAMICS, 'Window Title', fOk;
if not fOk then
abort script;
end if;
iCount = 0;
end if;

if nRecCount = 50 then
call foreground with name list_object:OkCallBackScript in
➥ dictionary DYNAMICS, 'Window Title', fOk;
if fOk then
call foreground with name list_object:FillListCallBackScript in
➥ dictionary DYNAMICS;
else
abort script;
end if;
end if;

get next table RM_Customer_MSTR;


nStatus = err();
end while;

INTEGRATION GUIDE 287


PA RT 6 LI ST S

Add the The LoadBackground procedure is called by the Refresh procedure (which will be
LoadBackground added later) to actually fill the temporary table in the background. This procedure
procedure. calls the LoadData procedure, filling the temporary table. The following is the
LoadBackground procedure for the Contact History list.

inout ListObjState list_object;


inout long nRecCount;

local boolean fOk;

default window to State;

call foreground with name list_object:OkCallBackScript in dictionary


➥ DYNAMICS, 'Window Title', fOk;
if fOk then
call LoadData_ContactHistoryTrxTemp of form
➥ ListObj_ContactHistoryTrx, list_object, nRecCount;
else
abort script;
end if;

Selecting the data to display


Add the GetSortIndex Two procedures you supply for the list are used to control what data will be
procedure. displayed. The first of these is the GetSortIndex procedure. This procedure
examines the column the user has selected to sort the list contents, and then creates
a virtual key for the primary table used for the list. Data in the list will be sorted
using this key.

The following is the GetSortIndex procedure for the Contact History list in the
sample integrating application. Notice that pass-through sanScript is used to create
a virtual key for the main table used for the Contact History list.
in string sFieldName;
in ColSortOrder nSortOrder;
inout ListObjState list_object;

local text sCommand;


local string sCompileMSG;
local integer DictID = IG_PROD_ID;

pragma(disable warning LiteralStringUsed);

sCommand = "inout ListObjState Me; assign Me:SortIndex as key for " +


➥ "table(Me:'Table Reference') " +
➥ "with KEY_OPTION_ALLOW_DUPLICATES using '" + sFieldName + "'" +
➥ " of table(Me:'Table Reference')";

if nSortOrder = COLSORTORDER_DESCENDING then


sCommand = sCommand + " with KEY_SEGMENT_OPTION_DESCENDING";
end if;
if sFieldName <> technicalname('Customer Number' of
➥ table(list_object:'Table Reference')) then
sCommand = sCommand + CH_COMMA + "'Customer Number'" + " of
➥ table(Me:'Table Reference')";
end if;

288 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

sCommand = sCommand + ";";

if execute (DictID ,sCommand, sCompileMSG, list_object) <> 0 then


warning "Error: " + sCompileMSG;
end if;

pragma(enable warning LiteralStringUsed);

Add the SetRange The rows displayed in the list depend on several factors, such as the selection
procedure. option the user chose, the specified date range, or any search restrictions the user
has applied. The SetRange procedure applies the appropriate range to the main
table for the list, accounting for any predefined selections or search criteria the user
has specified.

The following is the SetRange procedure for the Contact History list. It creates a set
of range selection criteria based on the user’s predefined selection, the specified
date range, and any filter options specified through the Filter Pane at the top of the
list. Every column that can be displayed in the list must be included in the range
restriction. The range where statement is used to apply the range to the main table
for the list.

inout ListObjState list_object;

local string sRestrict;


local string sFind_SQL;
local text sRestriction;

default window to State;

range clear table(list_object:'Table Reference');

{Active Only restriction }


if list_object:ListOptionValue = LISTOPTION_CONTACTSACTIVE then
sRestriction = physicalname('Inactive' of table
➥ ContactHistoryTrxTemp) + CH_EQUAL + str(0);
end if;

{Apply any range restrictions based on the date range specified}


if not (empty(list_object:'Start Date') and empty(list_object:'End Date'))
then
if not empty(sRestriction) then
sRestriction = sRestriction + CH_SPACE + SQL_AND + CH_SPACE;
end if;
sRestriction = sRestriction + CH_LEFTPAREN;

if empty(list_object:'Start Date') then


sRestrict = physicalname('Last Contact Date' of
➥ table(list_object:'Table Reference')) +
➥ CH_LESSTHAN + CH_EQUAL + CH_SPACE +
➥ CH_SINGLEQUOTE + sqlDate(list_object:'End Date') + CH_SINGLEQUOTE;
elseif empty(list_object:'End Date') then
sRestrict = physicalname('Last Contact Date' of
➥ table(list_object:'Table Reference')) + CH_GREATERTHAN + CH_EQUAL +
➥ CH_SPACE + CH_SINGLEQUOTE + sqlDate(list_object:'Start Date') +
➥ CH_SINGLEQUOTE;
else

INTEGRATION GUIDE 289


PA RT 6 LI ST S

sRestrict = physicalname('Last Contact Date' of


➥ table(list_object:'Table Reference')) +
➥ CH_LESSTHAN + CH_EQUAL + CH_SPACE +
➥ CH_SINGLEQUOTE + sqlDate(list_object:'End Date') +
➥ CH_SINGLEQUOTE + CH_SPACE + SQL_AND + CH_SPACE +
➥ physicalname('Last Contact Date' of
➥ table(list_object:'Table Reference')) + CH_GREATERTHAN +
➥ CH_EQUAL + CH_SPACE + CH_SINGLEQUOTE +
➥ sqlDate(list_object:'Start Date') + CH_SINGLEQUOTE;
end if;
sRestriction = sRestriction + sRestrict;

sRestriction = sRestriction + CH_RIGHTPAREN;


end if;

{Apply any range restrictions based on the Find text the user entered}
if not empty(list_object:'Find Text') then
if not empty(sRestriction) then
sRestriction = sRestriction + CH_SPACE + SQL_AND + CH_SPACE;
end if;

sRestriction = sRestriction + CH_LEFTPAREN;


sFind_SQL = SQL_FormatStrings(CH_PERCENT + list_object:'Find Text' +
➥ CH_PERCENT);

sRestrict = physicalname('Customer Number' of table


➥ ContactHistoryTrxTemp) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + sRestrict;

sRestrict = physicalname('Customer Name' of table


➥ ContactHistoryTrxTemp) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('First Contact Date' of table


➥ ContactHistoryTrxTemp) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Contact Salesperson ID' of table


➥ ContactHistoryTrxTemp) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Last Contact Date' of table


➥ ContactHistoryTrxTemp) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestrict = physicalname('Contact Salesperson ID 2' of table


➥ ContactHistoryTrxTemp) + CH_SPACE + SQL_LIKE + CH_SPACE + sFind_SQL;
sRestriction = sRestriction + CH_SPACE + SQL_OR + CH_SPACE + sRestrict;

sRestriction = sRestriction + CH_RIGHTPAREN;


end if;

range table(list_object:'Table Reference') where sRestriction;

290 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

Filling the list


Add the FinishRefresh The FinishRefreshProcedureBackground completes the process of filling the
Background procedure. transaction list when the list is filled in the background. This procedure will be
called by the Refresh procedure, which will be added next. The following script is
the FinishRefreshProcedureBackground for the Contant History list.

inout ListObjState list_object;


inout long nRecCount;
in boolean fResetRange;

if fResetRange then
clear table(list_object:'Table Reference');
{ need to reset the range on the temp table }
call SetRange of form ListObj_ContactHistoryTrx, list_object;
end if;
{Display number of records in the list.}
nRecCount = countrecords(table(list_object:'Table Reference'));
field(list_object:RecCountStringRef) = str(nRecCount) + CH_SPACE +
➥ "Customers";

Add the Refresh The Refresh procedure controls the process of displaying or updating the data
procedure. displayed in the list. The type of action to be performed is passed into this
procedure. The procedure must set the range options appropriately, and call the
other procedures that are used during the display process.

The following is the Refresh procedure for the Contact History list.

inout ListObjState list_object;


in integer nRefreshType;
in string sSortColFieldName; {technical name of the field to sort by}
in integer nSortOrder; {sort order - ascending or descending}

local integer nStatus;


local long nRecCount;
local boolean fReloadData, fResetRange, fGetNewIndex;
local boolean fDatesOutOfTempTableRange;

default window to State;

fDatesOutOfTempTableRange = (list_object:'Start Date' <


➥ '(L) TempTableStartDate') or
➥ ((list_object:'Start Date' > '(L) TempTableEndDate') and
➥ (not empty('(L) TempTableEndDate'))) or
➥ ((list_object:'End Date' > '(L) TempTableEndDate') and
➥ (not empty('(L) TempTableEndDate'))) or
➥ ((list_object:'End Date' < '(L) TempTableStartDate') and
➥ (not empty(list_object:'End Date')));
case nRefreshType
in [REFRESHTYPE_CHANGESORT]
fReloadData = false;
fResetRange = false;
fGetNewIndex = true;
in [REFRESHTYPE_RELOAD]
fReloadData = true;
fResetRange = true;

INTEGRATION GUIDE 291


PA RT 6 LI ST S

fGetNewIndex = true;
in [REFRESHTYPE_FIND]
fReloadData = false;
fResetRange = true;
fGetNewIndex = false;
in [REFRESHTYPE_RESTRICT]
fReloadData = false;
fResetRange = true;
fGetNewIndex = false;
else { refresh type is invalid, so do nothing }
fReloadData = false;
fResetRange = false;
fGetNewIndex = false;
end case;

{Change index/key if necessary}


if fGetNewIndex then
call GetSortIndex of form ListObj_ContactHistoryTrx, list_object,
➥ sSortColFieldName, nSortOrder;
end if;

field(list_object:RecCountStringRef) = getmsg(5965); {Processing...}

if fReloadData then
{Clear/truncate the temp table}
range clear table(list_object:'Table Reference');
nStatus = Table_Truncate(table(list_object:'Table Reference'));
assert nStatus = OKAY;

'(L) TempTableStartDate' = list_object:'Start Date';


'(L) TempTableEndDate' = list_object:'End Date';

nRecCount = 0;

call with name list_object:OpenWindowCallBackScript in dictionary


➥ DYNAMICS;
call background LoadDataBackground of form
➥ ListObj_ContactHistoryTrx, list_object, nRecCount;
end if;

if RunRefreshInBackground(list_object) of form syListObj then


call background FinishRefreshBackground of form
➥ ListObj_ContactHistoryTrx, list_object, nRecCount, fResetRange;
else
call FinishRefreshBackground of form ListObj_ContactHistoryTrx,
➥ list_object, nRecCount, fResetRange;
end if;

Formatting list data


Add the FormatField The data displayed in the transaction list is used in other areas of the list, such as the
procedure. Information Pane. It is also used in the reports that can be generated from the list
contents or exported to Microsoft Excel. The formatting applied to this data will
vary, depending on where it is used. For example, when a currency value is
displayed in the Information Pane, you may want it to appear with a currency
symbol. When that same value is exported to Excel, you may want just the numeric
portion without a currency symbol.

292 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

To have the Print This List or Send To Excel actions appear in the Action Pane for a list,
you must have the FormatField procedure defined first.

The FormatField procedure for the list is used to specify the formatting for fields in
the list. This procedure is automatically called as each field is displayed in the
Information Pane, used in the reports generated from the list, or exported to Excel.
The procedure has the following parameters:
in reference TableRef;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in integer nFormatFor;
out string sValue;
out integer nAlignment;

The table reference parameter provides access the current record in the temporary
table used for the list. The field and array index paramters indicate which field is
being displayed and may need formatting. The “format for” parameter will be set to
one of the following constants, indicating where the field value is to be used:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

The formatted value is passed back out of the procedure as a string. Consider using
the following functions defined for the syListObj form to help with formatting the
list data:

• List_FormatBoolean()
• List_FormatCurrency()
• List_FormatDate()
• List_FormatInteger()
• List_FormatPhone()
• List_FormatQuantity()
• List_FormatString()
• List_FormatTime()

You will also specify the alignment of the formatted data value. The last parameter
of the procedure must be set to one of the following constants to specify the
alignment:

Constant Description
ALIGN_LEFT Left-aligned
ALIGN_CENTER Center-aligned
ALIGN_RIGHT Right-aligned

INTEGRATION GUIDE 293


PA RT 6 LI ST S

The following example is the FormatField procedure for the Contact History
transaction list defined in the sample integrating application. It formats each of the
values that can appear in the list.
in reference TableRef;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in integer nFormatFor;
out string sValue;
out integer nAlignment;

local string s;

{Assume default left alignment}


nAlignment = ALIGN_LEFT;

case nFieldID
in[resourceid(field 'Customer Number')]
sValue = List_FormatString('Customer Number' of table(TableRef),
➥ nFormatFor) of form syListObj;
in[resourceid(field 'Customer Name')]
sValue = List_FormatString('Customer Name' of table(TableRef),
➥ nFormatFor) of form syListObj;
in[resourceid(field 'First Contact Date')]
sValue = List_FormatDate('First Contact Date' of table(TableRef),
➥ nFormatFor) of form syListObj;
in[resourceid(field 'Last Contact Date')]
sValue = List_FormatDate('Last Contact Date' of table(TableRef),
➥ nFormatFor) of form syListObj;
in[resourceid(field 'Contact Salesperson ID')]
sValue = List_FormatString('Contact Salesperson ID' of
➥ table(TableRef), nFormatFor) of form syListObj;
in[resourceid(field 'Contact Salesperson ID 2')]
sValue = List_FormatString('Contact Salesperson ID 2' of
➥ table(TableRef), nFormatFor) of form syListObj;
in[resourceid(field 'Active')]
sValue = List_FormatBoolean('Active' of table(TableRef), nFormatFor)
➥ of form syListObj;
else
s = getmsg(6703);{Unknown [%1]}
substitute s, str(nFieldID);
sValue = s;
end case;

Filter tokens
Add the The filtering feature of the transaction list allows the user to create restrictions that
GetColumnTokens display specific rows in the list. Most fields in the list can be searched without any
procedure. additional coding required for the list. However, some fields (such as list boxes,
drop-down lists, visual switches, and radio groups) require additional coding to
define the tokens that can be used for filtering based on these fields.

294 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

The filter tokens provide a user-friendly representation of the data for that field,
making it easy to select the possible values for that field when defining a filter. For
example, the Contact History transaction list has a column for the Last Contact date.
This column is a date value and has several filter tokens that are automatically
created for it.

The filter tokens display


meaningful values for the
Last Contact date field.

The core list code can automatically produce filter tokens for many list fields. For
the other fields that require filter tokens (typically list fields), you will add code to
the GetColumnTokens procedure you define for your list. This procedure has the
following parameters:
in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

The GetColumnTokens procedure is called automatically when each column is


added to the list. The parameters for the procedure indicate which column is being
added. You will use the Columns_AutoGenTokensForEnumField() function
function defined for the syListObj form to define the tokens for the field. In certain
special cases, you will need to use the Columns_AddToken() function to create the
filter tokens. Refer to the description of that function for details.

The following example is the GetColumnTokens procedure for the Contract History
transaction list. It defines the filter tokens for the Active column, which is based on
a check box.
in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

local long internal_ID;

if nFieldID = resourceid(field 'Inactive') then


{Need to add tokens for this check box field}
{Active}
internal_ID = Columns_AddToken(list_object,
nColumnID,
"Yes", {Token name}
1, {Unique ID for this token}
"(ACTIVE = '1')") of form syListObj;

INTEGRATION GUIDE 295


PA RT 6 LI ST S

{Inactive}
internal_ID = Columns_AddToken(list_object,
nColumnID,
"No", {Token name}
2, {Unique ID for this token}
"(ACTIVE = '0')") of form syListObj;
end if;

Action Pane
Define constants for The Action Pane allows the user to perform actions on the items selected in the list.
the actions. Adding groups and actions to the Action Pane is a multi-step process. You begin by
defining constants for the actions that you want to add to the Action Pane. For
instance, the following constants were defined for the Contact History list:

ACTION_UPDATECONTACT: 1
ACTION_EDITCUSTOMER: 2

Create commands and The next step involves creating commands for each action and command lists for
command lists for the each group that will appear in the Action Pane. The commands will contain the
the Action Pane. code that performs the actions. Refer to Commands for the Action Pane on page 212 for
details about creating these commands. Continuing the example, the following
commands and command lists are defined for the Contact History list:

• EditCustomer
• UpdateContact
• CL_ActionsGroup
• CL_GoToGroup
• CL_ReportsGroup

The script for each command contains code the will execute the action the user has
chosen. For example, the following is the script defined for the EditCustomer
command.
call ExecuteListAction of form syTrxList, ACTION_EDITCUSTOMER;

In some cases, you may want to have the user verify the action before it is
performed. You can learn more about this in Verifying an action on page 219.

Add the Use the CreateListRibbonData procedure to add groups and actions to the Action
CreateListRibbonData Pane for the list you are creating. You will use the functions AddGroup() and
procedure. AddCommand() from the syListViewCmdBarObj form to add the groups and the
actions for each group.

The CreateListRibbonData procedure runs only when no Action Pane items exist for the list.
If you need to add additional items after the initial Action Pane items have been created, use
the technique described in Adding to the Action Pane on page 214.

The CreateListRibbonData procedure for the Contact History list creates four
groups and adds the commands to those groups. It also adds the two user-defined
groups, which by default are not visible. The user can add additional commands to
these groups when they customize the Action Pane for the list.

These groups and


commands are added for
the Leads list.

296 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

The following is the complete CreateListRibbonData procedure.

in ListDictID nListDictID;
in ListID nListID;

local CmdDictID nCmdDictID, nParentDictID;


local CmdFormID nCmdFormID, nParentFormID;
local CmdID nCmdID, nParentCmdID;
local integer nStatus;
local CmdSequence nSeq, nGroupSeq;

nGroupSeq = 0;

{ Actions group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_ContactHistoryTrx);
nCmdID = resourceid(command CL_ActionsGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Actions group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_ContactHistoryTrx);

{ Update Contact }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command UpdateContact),
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Edit Customer }
increment nSeq;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, resourceid(command EditCustomer),
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

INTEGRATION GUIDE 297


PA RT 6 LI ST S

{ Restrictions group }
increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTRIBBONGROUP_RESTRICT, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Restrictions group ---}


nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

{ Date Restriction }
increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTACTION_DATERESTRICT, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Include/Exclude Active Customers Restriction }


increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTACTION_LISTRESTRICT, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Reports group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_ContactHistoryTrx);
nCmdID = resourceid(command CL_ReportsGroup);

nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,


nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{--- add default commands to the Reports group ---}


nSeq = 0;

298 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

{ Print This List }


increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTACTION_PRINTLIST, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ Go To group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_ContactHistoryTrx);
nCmdID = resourceid(command CL_GoToGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

nSeq = 0;

nParentDictID = nCmdDictID;
nParentFormID = nCmdFormID;
nParentCmdID = nCmdID;

{ Send To Excel }
increment nSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTACTION_EXPORTTOEXCEL, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddCommand(nListDictID, nListID, LIST_PRIMARYVIEWID,
nParentDictID, nParentFormID, nParentCmdID,
nSeq,
nCmdDictID, nCmdFormID, nCmdID,
LISTACTIONPRIORITY_PRIMARY,
LISTACTIONBTNSIZE_LARGE,
""{caption},
true{visible}) of form syListViewCmdBarObj;

{ User Defined Group 1 }


increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTRIBBONGROUP_USERDEF1, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
false{visible}) of form syListViewCmdBarObj;

INTEGRATION GUIDE 299


PA RT 6 LI ST S

{ User Defined Group 2 }


increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_TRX,
➥ LISTRIBBONGROUP_USERDEF2, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
false{visible}) of form syListViewCmdBarObj;

Add the To control access for the commands added to the Action Pane, the actions must be
RegisterCommands registered. The RegisterCommands procedure for the list performs this action. In
procedure. this procedure, you will use the List_RegisterGroup() and List_RegisterAction()
functions of the syListObj form to register each item you added to the Action Pane.
The following is the RegisterCommands procedure for the Contact History list.

inout ListObjState list_object;

{ Actions }
List_RegisterGroup(list_object, command CL_ActionsGroup) of form syListObj;
List_RegisterAction(list_object, command UpdateContact,
➥ LISTCMDTYPE_SINGLESELECT, ACTION_UPDATECONTACT) of form syListObj;
List_RegisterAction(list_object, command EditCustomer,
➥ LISTCMDTYPE_SINGLESELECT, ACTION_EDITCUSTOMER) of form syListObj;

{ Reports }
List_RegisterGroup(list_object, command CL_ReportsGroup) of form syListObj;

{ Go To }
List_RegisterGroup(list_object, command CL_GoToGroup) of form syListObj;

Add the The actions in the Action Pane are enabled or disabled automatically, based on the
CheckActionAccessFor number and specific type of lines the user has marked in the list. Microsoft
Record procedure. Dynamics GP tracks two counts for every action in the Action Pane. The “count for”
counter tracks the number of items marked to determine whether the single-select
or multi-select actions should be enabled. The “count against” counter tracks the
number items marked that would prevent an action from being enabled. If there are
any “count against” lines marked, the action will be disabled.

For example, assume that the Update Contact action can be performed when a
single item is marked in the list. This action would be active as long as the user has
marked exactly one item.

The CheckActionAccessForRecord procedure is called multiple times when the user


marks or unmarks an item in the list. The procedure has the following parameters:

in ListObjState list_object;
in integer nActionCmdTag;
out integer nAccessStatus;

Each time the procedure is called, a command tag is passed in. The procedure
specifies how the item marked or unarked in the list should be considered when
determining whether the action corresponding to that tag should be accessible. You
will use the 'Table Reference' component of the list object composite passed into the
procedure to determine which row is being marked or unmarked in the list.

300 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

The parameter value returned through the “out” parameter this trigger processing
procedure specifies how the marked row should be considered. The value
corresponds to one of the following constants:

Constant Description
LISTACTIONACCESS_COUNT_NEUTRAL The marked row won’t affect the count for the
action.
LISTACTIONACCESS_COUNT_FOR The marked row will increase or decrease the
“count for” counter by one.
LISTACTIONACCESS_COUNT_AGAINST The marked row will increase or decrease the
“count against” counter by one.

The following is the CheckActionAccessForRecord procedure for the Contact


History list. By default, the marking or unmarking actions are considered neutral.
The Update Contact and Edit Customer actions have specific conditions for which
they will be enabled or disabled.

in ListObjState list_object;
in integer nActionCmdTag;
out integer nAccessStatus;

nAccessStatus = LISTACTIONACCESS_COUNT_NEUTRAL;

if nActionCmdTag = Command_GetTag(command EditCustomer) then


nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
elseif nActionCmdTag = Command_GetTag(command UpdateContact) then
nAccessStatus = LISTACTIONACCESS_COUNT_FOR;
end if;

Add the ExecuteAction To execute the actions you have defined for your list, you will add the
procedure. ExecuteAction procedure. This procedure is called every time a user chooses an
action for the list. The value corresponding to the action is also passed into the
procedure. The procedure must contain the code to perform the action the user
chose.

The ExecuteAction script must also handle the default action for the list window.
The default action occurs when the user presses the Enter key or double-clicks on a
line in the list. The value corresponding to the constant DEFAULT_ACTION
indicates the default action.

The default action for transaction lists is specified in the Initialize procedure for the list. This
procedure is described in Open and closing on page 304.

Executing an action for a list can be an involved process, since the action can be
performed for multiple items marked in the list. Refer to Performing actions for
marked rows on page 222 for details about processing actions for multiple items.

The ExecuteAction procedure must also be able to handle any errors that occur
during action processing. Refer to Logging action status on page 223 and Acting on
action errors on page 226 for detailed information about how to log and act on errors
encountered as actions are processed.

The following is the ExecuteAction script for the Contact History list in the sample
integrating application. Notice that the list object is passed into the procedure. The
reference to the main table contained in this object is used to find what row the user
had marked in the list for the single-select actions.

INTEGRATION GUIDE 301


PA RT 6 LI ST S

inout ListObjState list_object;


in long iAction;

case iAction
in [ACTION_EDITCUSTOMER, DEFAULT_ACTION]
open form RM_Customer_Maintenance;
'Customer Number' of window RM_Customer_Maintenance of form
RM_Customer_Maintenance = 'Customer Number' of table
➥ (list_object:'Table Reference');
run script 'Customer Number' of window RM_Customer_Maintenance
➥ of form RM_Customer_Maintenance;
in [ACTION_UPDATECONTACT]
open form RM_Customer_Maintenance;
'Customer Number' of window RM_Customer_Maintenance of form
➥ RM_Customer_Maintenance = 'Customer Number' of table
➥ (list_object:'Table Reference');
run script 'Customer Number' of window RM_Customer_Maintenance
➥ of form RM_Customer_Maintenance;

open form IG_Contact_History;


'Customer Number' of window 'Contact History' of form
➥ IG_Contact_History = 'Customer Number' of table
➥ (list_object:'Table Reference');
run script 'Customer Number' of window 'Contact History' of
➥ form IG_Contact_History;
end case;

Information Pane
Add the The Information Pane for the list provides additional details about the row that is
GeneratePreviewPane currently selected in the list. When the user selects a row, the
XML procedure. GeneratePreviewPaneXML procedure for the list is called. This procedure builds an
XML file that displays detailed information about the selected row.

The layout of the Information Pane depends on the type of list being displayed. For
transaction lists, the Information Pane contains up to three columns in the header
section. Within each column are a series of label-value pairs that display
information about the selected item. The layout also typically contains a set of line
items that describe details of the selected list item, such as the line items for a
transaction.

The following illustration shows the Information Pane for the Contact History
transaction list.

The GeneratePreviewPaneXML procedure for the list is run each time a user selects
a row in the list. This procedure has the following parameters:
inout ListObjState list_object;
inout string XMLFilePath;
inout string sTitle;

302 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

First, the title used for the Information Pane content is constructed. This value will
be passed out through the last parameter for the procedure. Then the
XMLDoc_Create procedure of the syListObj form starts the process of creating the
Information Pane content. To create the items in the header section, the
XMLDoc_AddHeaderField procedure of the syListObj form is used. This
procedure adds a data item to the end of the specified column.

To create line items, the XMLDoc_AddColumn procedure is used to add the


columns that will be displayed. Next, the XMLDoc_AddLineItem procedure is
called to add a new line item. The XMLDoc_AddLineItemValue procedure is used
to add the individual items to the line item.

Finally, the XMLDoc_Save procedure of the syListObje form completes the XML
document used for the Information Pane.

The following is the GeneratePreviewPaneXML procedure for the Contact History


list. It displays complete contact information about the selected customer.

inout ListObjState list_object;


inout string XMLFilePath;
inout string sTitle;

local ListPrevPaneXMLState XMLState;


local string sName;
local string sValue;
local reference RowValuesElement;
local reference Contact_History_MSTR_Temp;

{Get the reference for the temporary table used by the list}
Contact_History_MSTR_Temp = list_object:'Table Reference';

sTitle = str('Customer Number' of table(Contact_History_MSTR_Temp)) +


➥ CH_SPACE + CH_COLON + CH_SPACE +
➥ 'Customer Name' of table(Contact_History_MSTR_Temp);

{ Build up basic XML file }


call XMLDoc_Create of form syListObj, XMLState, XMLFilePath, sTitle;

{Add the fields that will be displayed}

{--Column 1--}

{Customer ID}
sValue = 'Customer Number' of table(Contact_History_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "Customer ID",
➥ sValue, 1;

{Columns for line items}


call XMLDoc_AddColumn of form syListObj, XMLState, "Contact", false;
call XMLDoc_AddColumn of form syListObj, XMLState, "Date", false;
call XMLDoc_AddColumn of form syListObj, XMLState, "Salesperson", false;

{Add the line items}


{First Contact}
call XMLDoc_AddLineItem of form syListObj, XMLState, RowValuesElement;
sValue = "First Contact";

INTEGRATION GUIDE 303


PA RT 6 LI ST S

call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,


➥ sValue, false;

sValue = List_FormatDate('First Contact Date' of


table(Contact_History_MSTR_Temp), LIST_FORMATFOR_PREVPANE) of form syListObj;
call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

sValue = 'Contact Salesperson ID' of table(Contact_History_MSTR_Temp);


call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

{Last Contact}
call XMLDoc_AddLineItem of form syListObj, XMLState, RowValuesElement;

sValue = "Last Contact";


call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

sValue = List_FormatDate('Last Contact Date' of


table(Contact_History_MSTR_Temp), LIST_FORMATFOR_PREVPANE) of form syListObj;
call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

sValue = 'Contact Salesperson ID 2' of table(Contact_History_MSTR_Temp);


call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

{Save the XML document.}


call XMLDoc_Save of form syListObj, XMLState;

Business Analyzer
Beginning with Microsoft Dynamics GP 2010 R2, a list page can display the
Business Analyzer. Refer to Business Analyzer on page 270 for more information.

Row selection actions


Add the LinePre Depending on the type of data displayed in your list, you may want to perform
procedure. additional processing when the user focuses on a row in the list. The LinePre
procedure is run every time the user focuses to a new line. The list object for the list
is passed into each of these scripts. This provides access to the main table and other
resources for the list.

Open and closing


Add the Initialize The Initialize procedure is used to prepare a list to display data. It performs the
procedure. following:

• Opens the list object form


• Sets the list type
• Sets the title for the list
• Fills the Options drop-down list
• Clears the date and find fields
• Registers the commands used in the Action Pane
• Sets the default action for the list

304 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

The following is the Initialize procedure for the Contact History list in the sample
integrating application.
inout ListObjState list_object;
out 'Window Title' sWdwTitle;
out integer nStatus;

default window to State;

{Open the Contact History list object}


open form ListObj_ContactHistoryTrx;

clear table(list_object:'Table Reference');

{Set the list type}


list_object:ListType = LISTTYPE_TRX;

{Set the window title and header title}


sWdwTitle = "Contact History";
field(list_object:HeaderTextRef) = "Contact History";
'Window Title' = "Contact History";

'(L) TrxString' = "Customers";


'(L) LoadingString' = getmsg(7086);{"Loading"}

{Fill the Options drop-down list}


call FillListOptionsDDL of form ListObj_ContactHistoryTrx, list_object;

{Clear date and find fields}


clear '(L) TempTableStartDate', '(L) TempTableEndDate',
➥ '(L) TempTableHasHistory', list_object:'Find Text';

nStatus = OKAY;

{Register the commands used for the Action Pane}


call RegisterCommands of form ListObj_ContactHistoryTrx, list_object;

{For transaction lists, set the default action}


list_object:DefaultAction = DEFAULT_ACTION;

Add the Close When the user closes the list or displays another list, the Close procedure for the list
procedure. is run. This procedure must perform any clean-up actions for the list, such as closing
the list object form, or removing data from temporary tables used for the list. The
following is the Close procedure for the Contact History list in the sample
integrating application.
inout ListObjState list_object;

list_object:IsCreated = false;
close form ListObj_ContactHistoryTrx;

INTEGRATION GUIDE 305


PA RT 6 LI ST S

List navigation
Define the command A list window is actually opened using a command that you define. Commands to
to open the list open lists must have the type DataList, and specify the form that provides the base
window. functionality for the list.

The command that opens the Contact History list in the sample integrating
application has the following characteristics:

Command Name: ListObj_ContactHistory


Display Name: Contact History
Type: Data List
Data List Form: syListObj
Image Type: Icon
Normal Image: ListPage

Add the command to A separate procedure in Microsoft Dynamics GP is used to create the items that
the Navigation Pane appear in each section of the Navigation Pane. The following table lists the
menu structure. procedures used for each:

Navigation Pane section Procedure


Administration CreateMenu_Administration_NavButton
Field Service CreateMenu_FieldService_NavButton
Financial CreateMenu_Financial_NavButton
HR & Payroll CreateMenu_Payroll_NavButton
Inventory CreateMenu_Inventory_NavButton
Manufacturing CreateMenu_Manufacturing_NavButton
Project CreateMenu_ProjectAccounting_NavButton
Purchasing CreateMenu_Purchasing_NavButton
Sales CreateMenu_Sales_NavButton

A procedure trigger registered for one of these procedures is used to add the list
command to the appropriate location in the Navigation Pane menu structure. For
example, the following is the procedure trigger registration that adds the
Navigation Pane items for the sample integrating application.

l_result = Trigger_RegisterProcedure(script CreateMenu_Sales_NavButton,


TRIGGER_AFTER_ORIGINAL, script IG_CreateNavBarItems);
if l_result <> SY_NOERR then
warning "Procedure trigger for CreateMenu_Sales_NavButton failed.";
end if;

The trigger processing procedure has the following parameters, which indicate the
command list to which commands should be added:

in CmdParentDictID ParentDictID;
in CmdParentFormID ParentFormID;
in CmdParentCmdID ParentCmdID;
in integer LoadMode;

306 IN T E G R AT I O N G U ID E
C H A PT E R 3 0 T R A N S A C TI O N L IS T S

The following is the trigger processing procedure that adds the


ListObj_ContactHistory command to the Sales section of the Navigation Pane:
in CmdParentDictID ParentDictID;
in CmdParentFormID ParentFormID;
in CmdParentCmdID ParentCmdID;
in integer LoadMode;

local integer Seq;


local integer Status;

{Add the Contact History command to access the Contact History list}
{Find the appropriate location to add the item, after Salespeople}
Seq = FindCommandInMenu(ParentDictID,
ParentFormID,
ParentCmdID,
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command ListObj_Salespeople of form Command_Sales),
LoadMode,
"");

{If the item was found, add the new item after it.}
if Seq <> 0 then
Seq = Seq + 1;
end if;

{Add the Contact History command to access the Contact History list}
Seq = Seq + 1;
Status = AddCommandToMenu(ParentDictID,
ParentFormID,
ParentCmdID,
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command ListObj_ContactHistory of form Command_IG_Sample),
true,
LoadMode);

Register the list The final step to making the list accessible is registering it. This is typically
command. performed in the form pre script for the command form that defines the list
navigation command. The registration process does the following:

• Identifies the list


• Indicates the form that defines the list content
• Specifies the list type
• Indicates the Navigation Pane section the command appears in

The RegisterListNavigationCommand() function registers the command that will


open the list. The following example is the form pre script for the
Command_IG_Sample form defined in the sample integrating application. It
registers the navigation command that opens the Contact History list. The Contact
History list is assigned the ID value “2”.

Consider creating a constant for the list ID value. For instance, the constant
LISTID_CONTACTHISTORY is used for the Contact History list in the sample
integrating application.

INTEGRATION GUIDE 307


PA RT 6 LI ST S

local boolean result;

result = RegisterListNavigationCommand(command ListObj_ContactHistory,


IG_PROD_ID,
2,
IG_PROD_ID,
resourceid(form ListObj_ContactHistoryTrx),
0,
LISTTYPE_TRX,
command SalesButton of form Command_NavBar) of form syListObj;

Custom list views


Each list has a primary view that is read-only. Users can save a copy of the primary
view, and then make changes to the columns, Action Pane buttons, and filter criteria
for the new view. When you install your integration, you may want to include some
custom views for your lists. Adding a custom list view for a transaction list is done
the same way it is for a card list. The process is described in detail in Custom list
views on page 275.

308 IN T E G R AT I O N G U ID E
Chapter 31: Report Lists
Microsoft Dynamics GP has several Report Lists that provide access to the reports
that are part of a specific series or type. For example, the Sales Report List provides
access to reports associated with the Sales series, the System Report List provides
access to all system reports, and so on. If you have created reports for your
integration, you will want to add them to the appropriate Report List to make them
easily accessible.

The sample integrating application adds reports to the “sales” series so they appear
in the Sales Report List, as shown in the following illustration.

Information about integrating with the Report List is divided into the following
sections:

• Report types
• Report series
• Integrating with Report List
• Adding Report List items
• Retrieving Report List item information
• Printing and viewing reports
• Custom actions
• Composite definitions

INTEGRATION GUIDE 309


PA RT 6 LI ST S

Report types
Several types of reports can be added to the Report List. The actions enabled in the
Action Pane are based on the report type. The following table lists the types of
reports and the corresponding constants:

Report type Constant Description


Simple report REPORTTYPE_SIMPLE A report that is started with a basic run report
statement.
Report with options REPORTTYPE_RPTWITHOPTIONS A report that is printed based on settings from a report
options window.
Report from window REPORTTYPE_RPTFROMWINDOW A report that is printed by choosing the Print menu
item when the specific window is open.
SmartList favorite REPORTTYPE_SMARTLISTFAVORITE A favorite defined in SmartList.
Custom report REPORTTYPE_CUSTOM A report created with the runtime Report Writer.
SQL Reporting Services REPORTTYPE_SQLREPORTING A report created using SQL Reporting Services.
External report REPORTTYPE_EXTERNALFILE A report that can be run externally from Microsoft
Dynamics GP, such as Crystal Reports or FRx.
Other REPORTTYPE_OTHER Any other type of report.

Report series
Each Report List displays the reports that are part of a specific Microsoft Dynamics
GP report series or of a specific type. The following table lists the report series and
corresponding constants for the report series that are predefined by the core
Dynamics.dic dictionary:

Series Constant
Financial REPORTSERIES_FINANCIAL
Sales REPORTSERIES_SALES
Purchasing REPORTSERIES_PURCHASING
Inventory REPORTSERIES_INVENTORY
Payroll REPORTSERIES_PAYROLL
Project REPORTSERIES_PROJECT
System REPORTSERIES_SYSTEM
Company REPORTSERIES_COMPANY

When you add reports for your integration, you will add them to the appropriate
existing report series.

Integrating with Report List


To integrate with a Report List, you will register several triggers that respond to
Report List events. Unlike card lists or transaction lists, you don’t need to create any
additional forms. All processing is handled through the trigger processing scripts
you create for your integration. The procedures and functions you need to create
triggers for are found on the syReportList form.

When a specific Report List is displayed, the reports that are part of the series for
that list are listed. Triggers are activated as the LoadData procedure builds the
temporary table for the report list. If your integration has reports that should be
displayed for the selected report series, you will use AddReport() function to add
your reports to the list.

310 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

As each item is added to the Report List, other triggers are activated that will
retrieve additional details about the report being added. For example, one trigger
retrieves the display name for the report. Refer to Retrieving Report List item
information on page 316 for more information.

Other triggers are activated when the user selects a report in the list and performs
an action such as viewing or printing. Your integration will have to handle these
requests for the reports you add to each Report List. Refer to Printing and viewing
reports on page 321 for details.

Adding Report List items


When a Report List is displayed, a temporary table is built that contains the reports
to display for that list. To have your reports added to the temporary table, create a
procedure trigger for the LoadData procedure of the syReportList form.

The following example is a portion of the Startup script for the sample integrating
application. It registers a procedure trigger that will add items to the Sales Report
List for the sample.

l_result = Trigger_RegisterProcedure(script LoadData of form syReportList,


➥ TRIGGER_AFTER_ORIGINAL, script IG_ReportList_AddReports);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

Determining whether to add reports


The processing procedure that runs in response to this trigger must use the
parameters passed into the procedure to determine whether the reports should be
added for the Report List the user is displaying. You should add your reports in the
following cases:

• The Report Series ID parameter is equal to the constant REPORTS_ALL defined


on the syReportList form. This indicates the user is viewing the “All Reports”
Reports List, which displays all reports available.

• You are adding SmartList favorites, and the Report Series ID parameter is equal
to the constant REPORTS_SMARTLISTONLY defined on the syReportList form.
This indicates the user is viewing the “SmartList Favorites” Report List.

• The Report Series DictID parameter matches the Microsoft Dynamics GP


product ID, and the Report Series ID matches one of the predefined report
series IDs, and you want to add reports to that existing series.

Specifying information about each report


The syReportData composite contains all of the information about each report that
will be added to the Report List. You will set the values in this composite, based on
the type of report you’re adding to the list. Refer to Composite definitions on page 324
for a description of this composite.

The following table lists the types of reports that can be added, and indicates which
components of the syReportData composite must be set. The Xs indicate required
values, and the Os indicate optional values for each type. Some components of the
composite are used internally by the Report List implementation, and should not be
set.

INTEGRATION GUIDE 311


PA RT 6 LI ST S

Report from Window


Report with Options

SmartList Favorite

SQL Reporting

External
Simple

Other
Report Type X X X X X X X
Product ID X X X X X X X
Report Series DictID X X X X X X
Report Series ID X X X X X X
Report Category ID O O O O O O
Report ID X X X X X X X
Report Option ID X
Report Option Name X O
My Report Name O
VisibleTo O
User ID O
User Class O
Company ID O
String A 255 O O O O O O
Report Options Table Ref O
Report Names Table Ref O
DictID X X X
Resid X X X

Adding each report


When the syReportData composite has been supplied with the appropriate data, the
AddReport() function of the syReportList form is used to add the report to the list.

When adding a report that uses a report options window, you will be using the
AddReport() function several times. The first time adds the template report entry,
with the report option name “<<New>>”. This entry in the Report List opens the
report options window for the report so the user can create a new report option.
Next, your code should loop through every report option that has been defined for
the report, and add an entry to the Report List.

When adding an item for SmartList favorites, you must supply the
ASI_Favorite_Type for the Report ID component of the syReportData composite.
The Report List will automatically add all of the SmartList favorites of that type for
the current user logged into Microsoft Dynamics GP. If you specify the name of a
specific favorite in the Report Option Name component, only that item will be
added to the Report List.

Example
The following example shows the trigger processing procedure for the sample
integrating application that adds the various report types to the Sales Report List.
Notice how the reports are added to the predefined Sales report series. Also note
how only the SmartList favorites are added when the SmartList Favorites Report
List is being displayed.

312 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

in ListObjState list_object;
in 'Report Series DictID' nSeriesDictID;
in 'Report Series ID' nSeriesID;

local integer status;


local syReportData RptData;

{Add items to the Sales series or if all reports are being requested}
if (nSeriesID = REPORTS_ALL of form syReportList) or
➥ ((nSeriesDictID = DYNAMICS) and (nSeriesID = REPORTSERIES_SALES)) then

{Simple Report}
clear field RptData;
RptData:'Report Type' = REPORTTYPE_SIMPLE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_LeadsSimple;
RptData:'Report Option Name' = "Leads";
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);

status = AddReport(RptData) of form syReportList;

{Reports with Options}


{First, add the <<New>> entry for the report.}
clear field RptData;
RptData:'Report Type' = REPORTTYPE_RPTWITHOPTIONS;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_LeadsWithOptions;
RptData:'Report Option ID' = 0;
RptData:'Report Option Name' = getmsg(7487); {<<New>>}
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);

status = AddReport(RptData) of form syReportList;

{Then add an entry for each option that has been defined.}
range clear table IG_Leads_ROPT;
'Report ID' of table IG_Leads_ROPT = ReptID_LeadsWithOptions;
clear 'Report Option Name' of table IG_Leads_ROPT;
range start table IG_Leads_ROPT by number 1;
fill 'Report Option Name' of table IG_Leads_ROPT;
range end table IG_Leads_ROPT by number 1;

get first table IG_Leads_ROPT;


while err() = OKAY do
clear field RptData;
RptData:'Report Type' = REPORTTYPE_RPTWITHOPTIONS;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_LeadsWithOptions;
RptData:'Report Option ID' = 'Report ID' of table IG_Leads_ROPT;

INTEGRATION GUIDE 313


PA RT 6 LI ST S

RptData:'Report Option Name' = 'Report Option Name' of table


➥ IG_Leads_ROPT;
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);

status = AddReport(RptData) of form syReportList;

get next table IG_Leads_ROPT;


end while;
range clear table IG_Leads_ROPT;

{First, add the <<New>> entry for the report.}


clear field RptData;
RptData:'Report Type' = REPORTTYPE_RPTWITHOPTIONS;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_LeadsList;
RptData:'Report Option ID' = 0;
RptData:'Report Option Name' = getmsg(7487); {<<New>>}
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);

status = AddReport(RptData) of form syReportList;

{Then add an entry for each option that has been defined.}
range clear table IG_Leads_ROPT;
'Report ID' of table IG_Leads_ROPT = ReptID_LeadsList;
clear 'Report Option Name' of table IG_Leads_ROPT;
range start table IG_Leads_ROPT by number 1;
fill 'Report Option Name' of table IG_Leads_ROPT;
range end table IG_Leads_ROPT by number 1;

get first table IG_Leads_ROPT;


while err() = OKAY do
clear field RptData;
RptData:'Report Type' = REPORTTYPE_RPTWITHOPTIONS;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_LeadsList;
RptData:'Report Option ID' = 'Report ID' of table IG_Leads_ROPT;
RptData:'Report Option Name' = 'Report Option Name' of table
➥ IG_Leads_ROPT;
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);

status = AddReport(RptData) of form syReportList;

get next table IG_Leads_ROPT;


end while;
range clear table IG_Leads_ROPT;

{Other Report Type}


clear field RptData;
RptData:'Report Type' = REPORTTYPE_OTHER;

314 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

RptData:'Product ID' = IG_PROD_ID;


RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_LeadsQuick;

status = AddReport(RptData) of form syReportList;

{SmartList Favorite}
clear field RptData;
RptData:'Report Type' = REPORTTYPE_SMARTLISTFAVORITE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = SMARTLIST_OBJECTTYPE_LEADS;
RptData:'Report Option Name' = "";
RptData:'VisibleTo' = SMARTLIST_VISIBLETO_SYSTEM; {All users}

status = AddReport(RptData) of form syReportList;

{Report from Window}


clear field RptData;
RptData:'Report Type' = REPORTTYPE_RPTFROMWINDOW;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = ReptID_ContactHistory;
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(form IG_Contact_History);

status = AddReport(RptData) of form syReportList;

end if;

{Only SmartList favorites are being displayed}


if (nSeriesID = REPORTS_SMARTLISTONLY of form syReportList) then

{SmartList Favorite}
clear field RptData;
RptData:'Report Type' = REPORTTYPE_SMARTLISTFAVORITE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = DYNAMICS;
RptData:'Report Series ID' = REPORTSERIES_SALES;
RptData:'Report ID' = SMARTLIST_OBJECTTYPE_LEADS;
RptData:'Report Option Name' = "";
RptData:'VisibleTo' = SMARTLIST_VISIBLETO_SYSTEM; {All users}

status = AddReport(RptData) of form syReportList;

end if;

INTEGRATION GUIDE 315


PA RT 6 LI ST S

Retrieving Report List item information


Several procedure trigger and function triggers are used to retrieve information
about each report that you have added to a Report List. Some of these triggers are
activated as the Report List displays reports. Others are activated as actions are
performed on the selected or marked report. Some of these triggers are optional,
and are used only in certain cases.

The following is a list of the procedure and function triggers that you can
implement. All of them are located on the syReportList form.

TRIGGER_GetReportResid
This procedure trigger is used to retrieve the dictionary ID and resource ID of a
report that has been added to a Report List. It is used when security access is
checked for the report. If access is denied for the current user, the report will not
appear in the Report List.

The following example shows the registration for this trigger from the sample
integrating application.

l_result = Trigger_RegisterProcedure(script TRIGGER_GetReportResid of form


➥ syReportList, TRIGGER_AFTER_ORIGINAL,script IG_ReportList_GetReportResid);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The following example shows the trigger processing procedure that looks up and
returns the dictionary ID and resource ID for a report. Note how the Product ID and
Report ID components of the syReportData composite are examined to determine
which report is being queried.

inout syReportData RptData;

if RptData:'Product ID' = IG_PROD_ID then

{Leads report}
if (RptData:'Report ID' = ReptID_LeadsSimple) or (RptData:'Report ID' =
➥ ReptID_LeadsWithOptions) then
RptData:'Resid' = resourceid(report IG_Leads);
RptData:'DictID' = IG_PROD_ID;
end if;

{Leads List report}


if (RptData:'Report ID' = ReptID_LeadsList) then
RptData:'Resid' = resourceid(report IG_Leads_List);
RptData:'DictID' = IG_PROD_ID;
end if;

end if;

316 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

TRIGGER_GetReportCategoryName
This function trigger is used to retrieve the report category name to display for each
report added to a Report List. The following example shows the registration for this
trigger from the sample integrating application.

l_result = Trigger_RegisterFunction(function TRIGGER_GetReportCategoryName of


➥ form syReportList, TRIGGER_AFTER_ORIGINAL, function
➥ IG_ReportList_GetReportCategoryName);
if l_result <> SY_NOERR then
warning "Function trigger registration failed.";
end if;

The following example shows the trigger processing function that returns the report
category name for the reports included with the sample integrating application.
Note how the Product ID of the syReportData composite is examined to find which
product contains the report.

function returns 'Report Category Name' sCategoryName;

in syReportData RptData;

if RptData:'Product ID' = IG_PROD_ID then


{It's one of our reports}
sCategoryName = "Sample";
end if;

TRIGGER_GetReportDisplayName
This function trigger is used to retrieve the name to display for each report added to
a Report List. The following example shows the registration for this trigger from the
sample integrating application.

l_result = Trigger_RegisterFunction(function TRIGGER_GetReportDisplayName of


➥ form syReportList, TRIGGER_AFTER_ORIGINAL, function
➥ IG_ReportList_GetReportDisplayName);
if l_result <> SY_NOERR then
warning "Function trigger registration failed.";
end if;

The following example shows the trigger processing function that returns the report
display name for the reports included with the sample integrating application. Note
how the Product ID and Report ID of the syReportData composite are examined to
find which report is being queried.

function returns 'Report Display Name' sReportName;

in syReportData RptData;

if RptData:'Product ID' = IG_PROD_ID then


{It's one of our reports to print}
if RptData:'Report ID' = ReptID_LeadsSimple then
sReportName = "Leads (Simple)";
end if;

if RptData:'Report ID' = ReptID_LeadsWithOptions then


sReportName = "Leads";
end if;

INTEGRATION GUIDE 317


PA RT 6 LI ST S

if RptData:'Report ID' = ReptID_ContactHistory then


sReportName = "Contact History";
end if;

if RptData:'Report ID' = ReptID_LeadsQuick then


sReportName = "Leads (Other)";
end if;

if RptData:'Report ID' = ReptID_LeadsList then


sReportName = "Leads List";
end if;
end if;

TRIGGER_GetReportDestination
This procedure trigger is used to retrieve report destination information for reports
that use a report options window. The following example shows the registration for
this trigger from the sample integrating application.

l_result = Trigger_RegisterProcedure(script TRIGGER_GetReportDestination of


➥ form syReportList, TRIGGER_AFTER_ORIGINAL, script
➥ IG_ReportList_GetReportDestination);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

You will use the Product ID and Report ID components of the syReportData
composite to determine whether your report is being queried. If it is, you will look
up the report option information, and then set the components of the
ReportDestOptions composite with the option settings retrieved. Refer to the
description of this composite for the list of values that can be set. The information in
the ReportDestOptions composite is passed to the procedure that actually runs the
report.

If the “Ask Each Time” component is set to true in the composite, the Report
Destination window will be displayed automatically when the report is printed
from the Report List. The other settings in the composite, such as the output
destinations, will be reflected in the Report Destination window. After the user
makes selections in the destination window, the settings made are reflected in the
ReportDestOptions composite.

If the “Ask Each Time” component isn’t set to true in the composite, the other
options in the composite are passed directly to the procedure that runs the report.

The following example is the trigger processing procedure that retrieves the report
options for the Leads or Leads List reports.
inout syReportData RptData;
inout ReportDestOptions RptDest;

{The user asked for a report that uses a report option. Read the option
information and fill in the ReportDestOptions composite.}

{Is it one of our reports to print?}


if RptData:'Product ID' = IG_PROD_ID then
if (RptData:'Report ID' = ReptID_LeadsWithOptions) or
➥ (RptData:'Report ID' = ReptID_LeadsList) then

318 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

{It's the Leads or Leads List report which uses a areport option.
Look up the option.}
{Don't look up <<New>> report option}
if (RptData:'Report Option Name' <> "") and (RptData:'Report Option
➥ Name' <> getmsg(7487)) then

'Report ID' of table IG_Leads_ROPT = integer(RptData:'Report


➥ Option ID');
'Report Option Name' of table IG_Leads_ROPT = RptData:'Report
➥ Option Name';

get table IG_Leads_ROPT;


if err() = OKAY then
{Specify the settings for the destination options composite.}
RptDest:'Ask Each Time' = 'Ask Each Time' of table
➥ IG_Leads_ROPT;
RptDest:'Print to Screen' = 'Print to Screen' of table
➥ IG_Leads_ROPT;
RptDest:'Print to Printer' = 'Print to Printer' of table
➥ IG_Leads_ROPT;
RptDest:'Print to File' = 'Print to File' of table
➥ IG_Leads_ROPT;
RptDest:'File Export Name' = 'File Export Name' of table
➥ IG_Leads_ROPT;
RptDest:'Export Type' = 'Export Type' of table IG_Leads_ROPT;
RptDest:'If File Existing' = 'If File Existing' of table
➥ IG_Leads_ROPT;
else
error "Could not retrieve report option " +
➥ RptData:'Report Option Name' + ".";
end if;
end if;
end if;
end if;

TRIGGER_GetOptionsWindowIDs
This procedure trigger indicates which report options window to open for reports
that use report options. The following example shows the registration for this
trigger from the sample integrating application.
l_result = Trigger_RegisterProcedure(script TRIGGER_GetOptionsWindowIDs of
➥ form syReportList, TRIGGER_AFTER_ORIGINAL, script
➥ IG_ReportList_GetOptionsWindowIDs);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

You will use the Product ID and Report ID components of the syReportData
composite to determine which report is being queried. If it is your report and uses
an options window, return your product ID and the resource ID of the form that
defines the report options window.

INTEGRATION GUIDE 319


PA RT 6 LI ST S

The following example is the trigger processing procedure that retrieves the ID of
the report options window used for the Leads and Leads List reports.

inout syReportData RptData;


inout DictID nDictID;
inout FormID nFormID;

if RptData:'Product ID' = IG_PROD_ID then


{It's one of our reports with options to print}
if (RptData:'Report ID' = ReptID_LeadsWithOptions) or
➥ (RptData:'Report ID' = ReptID_LeadsList) then
{It's a report that uses an options window}
nDictID = IG_PROD_ID;
nFormID = resourceid(form IG_Leads_Reports);
end if;
end if;

The Report List starts the process of opening the report options window for your
report. You must provide a form-level procedure on your report option form that
will be called by the Report List. This procedure must be named
“OpenOptionFromList” and take one “in” parameter of type syReportData. The
procedure will open the report options window. It will also use the information
passed into the procedure through the syReportData composite to determine which
report option should be displayed.

The following is the form-level procedure that was added to the IG_Leads_Reports
form for the sample integrating application. Note that it examines the report option
information passed in through the syReportData composite. If a specific report
option name is named, that option is displayed in the window.

Procedure: OpenOptionFromList

in syReportData rptData;

{Open the Report Options window.}


open form IG_Leads_Reports;
open window 'Leads Report Options';

{Based on the data passed in, display the appropriate report option.}
'Report ID' of window 'Leads Report Options' = rptData:'Report ID';

if rptData:'Report ID' = ReptID_LeadsWithOptions then


'(L) Report Name' of window 'Leads Report Options' = "Leads";
end if;

if rptData:'Report ID' = ReptID_LeadsList then


'(L) Report Name' of window 'Leads Report Options' = "Leads List";
end if;

{Load the existing options}


call FillOptionsList of form IG_Leads_Reports;

if (rptData:'Report Option Name' <> "") and (rptData:'Report Option Name' <>
➥ getmsg(7487)) then
'(L) Report Options' of window 'Leads Report Options' =
➥ rptData:'Report Option Name';
run script '(L) Report Options' of window 'Leads Report Options';
end if;

320 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

TRIGGER_GetSmartListObjectSeries
This procedure trigger is used only for SmartList favorites. It is used to retrieve
information about a selected SmartList favorite in the Report List. The trigger
processing procedure must have the following parameters:

in DictID nObjectDictID;
in 'Report ID' nObjectID;
inout 'Report Series DictID';
inout 'Report Series ID' nSeriesID;
inout 'Series Name' sSeriesName;

Use the DictID and Report ID parameters to determine whether the SmartList
favorite belongs to your application. If it does, set the other parameters accordingly.
If you don’t use this trigger, the SmartList items for your integration will be
assigned to the System series.

TRIGGER_GetProcessIDs
This procedure trigger is used only for reports that can be sent to a process server.
The trigger processing procedure must have the following parameters:

inout syReportData ReportData;


inout 'Process DictID' nProcessDictID;
inout 'Process ID' nProcessID;

Use the syReportData composite to find the identity of the report. If it’s your report
and can be sent to a process server, the trigger processing script must supply the
Process DictID and Process ID values.

Printing and viewing reports


The Action Pane for each Report List contains items that allow the user to view or
print the selected report. To handle viewing and printing, you must register a
procedure trigger for the PrintReport procedure of the syReportList form. The
following example shows the registration for this trigger from the sample
integrating application.

l_result = Trigger_RegisterProcedure(script PrintReport of form syReportList,


➥ TRIGGER_AFTER_ORIGINAL, script IG_ReportList_PrintReport);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The trigger processing procedure must handle both of these cases for your reports.
It must have the following parameters:

in syReportData RptData;
in ReportDestOptions RptDestOpts;
in boolean fPreview;

The fPreview flag is a boolean value passed into the procedure that is true if the user
chose View or false if the user chose Print. If View was chosen, the report should be
displayed on the screen. For reports that use report options, override any
destination settings for the option and print the report to the screen.

INTEGRATION GUIDE 321


PA RT 6 LI ST S

If Print was chosen, the action required depends on the type of report. Simple
reports should always be printed to the printer. For reports that use report options,
the destination should be set as indicated by the ReportDestOptions composite that
was passed into the trigger processing procedure. The values for this composite
were set when the report option was retrieved for the report. They may have been
updated by the user if the “Ask Each Time” flag had been set for the report option.

For reports that use report options, you should always retrieve the option specified
in the syReportData composite. Use the information in the report option to control
sorting, restrictions, and other characteristics for the report.

For reports that print from a window, the trigger processing procedure must open
the window from with the report will be run.

The following example is the trigger processing procedure that handles viewing
and printing reports for the sample integrating application. It demonstrates how to
print a simple report to the screen or to the printer. It also shows how a report that
uses a report option processed. Finally, it demonstrates how a report generated from
an window is processed.

in syReportData RptData;
in ReportDestOptions RptDestOpts;
in boolean fPreview;

local boolean ToScreen, ToPrinter;


local integer ExportType;
local string ExportName;
local string report_name;

{Print the specified report, based on the information passed in}

if RptData:'Product ID' = IG_PROD_ID then


{It's one of our reports to print}
if RptData:'Report ID' = ReptID_LeadsSimple then
if fPreview = true then
run report IG_Leads destination true, false;
else
run report IG_Leads destination false, true;
end if;
end if;

if (RptData:'Report ID' = ReptID_LeadsWithOptions) or


➥ (RptData:'Report ID' = ReptID_LeadsList) then
{It's the Leads or Leads List report which uses a report option.}
report_name = GetReport(RptData:'Report ID') of form
➥ IG_Leads_Reports;

{Retrieve the option.}


'Report ID' of table IG_Leads_ROPT = integer(RptData:'Report Option
➥ ID');
'Report Option Name' of table IG_Leads_ROPT = RptData:'Report Option
➥ Name';

get table IG_Leads_ROPT;


if err() = OKAY then

322 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

{Did the user ask for a preview (to View the report)?}
if fPreview = true then
{Print the report using the options, but always to the screen}
ToScreen = true;
ToPrinter = false;
ExportType = 0;
ExportName = "";
else
ToScreen = RptDestOpts:'Print to Screen';
ToPrinter = RptDestOpts:'Print to Printer';
ExportType = RptDestOpts:'Export Type';
ExportName = RptDestOpts:'File Export Name';
end if;

if 'Sort By' of table IG_Leads_ROPT = 1 then {Lead ID}


run report with name report_name sort by 'Lead ID' of table
➥ IG_Leads_MSTR legends "Lead ID" destination ToScreen,
➥ ToPrinter, ExportType, ExportName;
end if;

if 'Sort By' of table IG_Leads_ROPT = 2 then {Name}


run report with name report_name sort by 'Lead Name' of table
➥ IG_Leads_MSTR legends "Name" destination ToScreen,
➥ ToPrinter, ExportType, ExportName;
end if;

if 'Sort By' of table IG_Leads_ROPT = 3 then {State}


run report with name report_name sort by 'State' of table
➥ IG_Leads_MSTR legends "State" destination ToScreen,
➥ ToPrinter, ExportType, ExportName;
end if;
else
error "Could not retrieve report option " + RptData:'Report Option
➥ Name' + ".";
end if;
end if;

if RptData:'Report ID' = ReptID_LeadsQuick then


call IG_Leads_QuickReport, REPORTDEST_TO_SCREEN;
end if;

if RptData:'Report ID' = ReptID_ContactHistory then


open form IG_Contact_History;
end if;
end if;

Custom actions
Most actions the user will need to perform for a report in a Report List are
automatically added to the Action Pane. In some cases you might want to create
your own custom actions, such as when you add an “other” report type to a Report
List.

Adding and processing custom actions for a Report List is done using the same
techniques and for card lists or transaction lists. Refer to Chapter 27, “Action Pane,”
for details about adding to the Action Pane for a list.

INTEGRATION GUIDE 323


PA RT 6 LI ST S

Composite definitions
Several composites are used when working with Report Lists. Use the information
about these composites as you write scripts for your Report List integration.

syReportData
The syReportData composite contains information about a specific report in the
Report List.

Component Data Type Description


Report Type Integer Specifies the type of report. Refer to Report types on page 310 for a list.
Product ID Integer The ID of the product to which the report belongs.
Report Series DictID Integer The ID of the product that defines the report series the report is part of. If it’s a
predefined Microsoft Dynamics GP core series, the value will be 0.
Report Series ID Integer Uniquely identifies the report series (within the report series defined for the
specified product) that the report will be assigned to.
Report Category ID Integer Specified the category the report is assigned to.
Report ID Integer The unique ID for the report. For SmartList favorites, this is the object ID
(ASI_Favorite_Type).
Report Option ID Currency The ID of the report option.
Report Option Name String The name of the report option to use for the report. For SmartList favorites, this
contains the favorite name. Leave this component blank to have all SmartList
favorites of the specified type listed.
My Report Name String The name assigned to the report when it was added to the My Reports list.
VisibleTo Integer For SmartList favorites, specifies who can see the item:
1 - SMARTLIST_VISIBLETO_SYSTEM - Visible to all users in all companies
2 - SMARTLIST_VISIBLETO_COMPANY - Visible to users in a specific company
3 - SMARTLIST_VISIBLETO_USERCLASS - Visible to users in a specific class
4 - SMARTLIST_VISIBLETO_USERID - Visible to a specific user
User ID String The SmartList favorite User ID. Applies only when VisibleTo is set to 4.
User Class String The SmartList favorite User Class. Applies only when VisibleTo is set to 3.
Company ID Integer The SmartList favorite Company ID. Applies only when VisibleTo is set to 2.
String A 255 String A generic string that can be used to help identify reports.
Report Options Table Ref Reference A reference to a table that contains report option information. Integrating
applications can use this reference if needed in their implementation.
Report Names Table Ref Reference A reference to a table that contains report option names. Integrating
applications can use this reference if needed in their implementation.
DictID Integer The ID of the dictionary that contains the definition for the report.
Resid Integer The resource ID of the report.

324 IN T E G R AT I O N G U ID E
C H A P T E R 3 1 R E P O R T L IS T S

ReportDestOptions
The ReportDestOptions composite is used to pass report destination information
into the procedure that displays or prints reports.

Component Data Type Description


Control Type Integer Not used for Report List.
Ask Each Time Check Box Indicates whether the user should be asked for the report’s
destination.
Print to Screen Check Box The value true specifies printing to the screen.
Print to Printer Check Box The value true specifies printing to the printer.
Print to File Check Box The value true specifies printing to a file.
Export File Type Drop-down List Not used for Report List.
File Export Name String Specifies the complete path for the export file
Export Type Integer Specifies the type to use for the export file. Use the following
constants to specify the value: TEXTFILE, TABFILE, COMMAFILE,
HTMLFILE, PDFFILE
If File Existing Radio Group Specifies the action if the export file already exists:
0 - Append
1 - Replace

ListObjState
The ListObjState composite provides access to the Report List window. The
following are the components of this composite used for the Report List:

Component Data Type Description


SubList Long integer Indicates with report series is being displayed.
Table Reference Table reference A reference to the report list temporary table.
SortIndex Integer Indicates which index to use when filling the Report List from the
temporary table.
ActionsBDLRef Field reference Obsolete
ListOptionsDDLRef Field reference Obsolete
DefaultAction Long integer Contains the ID of the default action to execute when the user
double-clicks a row in the Report List.
Find Text String Contains the string to search for in the Report List.

INTEGRATION GUIDE 325


326 IN T E G R AT I O N G U ID E
PART 7: SMARTLIST
Part 7: SmartList
Use the information in this portion of the documentation to learn about integrating
with the SmartList feature. The following is a list of the topics discussed, along with
a brief explanation of each:

• Chapter 32, “SmartList Overview,” explains how the SmartList works, and
describes how you can integrate with it.

• Chapter 33, “Adding to SmartList Objects,” describes how to add new columns
and Go To items to existing SmartLists.

• Chapter 34, “Creating New SmartList Objects,” describes how to create new
SmartList objects for your integration.

• Chapter 35, “SmartList Procedure Reference,” provides reference information


about the procedures that you will add to your dictionary to support a
SmartList integration.

328 IN T E G R AT I O N G U ID E
Chapter 32: SmartList Overview
SmartList is a powerful tool that allows users to drill into the data contained in the
accounting system. By integrating with SmartList, you can make the data for your
integration available for users to query. Information about SmartList is divided into
the following sections:

• How SmartList works


• Integration types
• Integration technique
• Explorer procedures
• SmartList objects

How SmartList works


The fundamental components of SmartList are the SmartList objects. Each SmartList
object contains the instructions needed for the SmartList to access and display a
specific type of information, such as customer records. Each SmartList object must
define the following:

• SmartList object type ID, which is an integer that uniquely identifies the
SmartList object

• A list of all of the columns that can be displayed by the SmartList object

• A set of default columns

• Go To links that allow the user to perform actions on the selected row

When a user chooses to SmartList object type to display, appropriate records are
read based on the SmartList object definition and displayed in the SmartList
window. Users can customize the search by doing the following:

• Choose columns they want to display, as well as the position order of the
columns

• Specify search criteria that limits the data to be displayed

If the SmartList object is optimized for SQL Server, a SQL query is used to select the
records to be displayed in the SmartList. Otherwise, SmartList will manually search
the tables used for the SmartList object and display each matching row in the
SmartList.

INTEGRATION GUIDE 329


PA RT 7 S M A R T L I S T

Integration types
Two types of integrations are possible with SmartList. You can add new columns
and Go To items to existing SmartList objects. For example, the following
illustration shows two new columns added to the Customers SmartList object by
the sample integrating application. An additional Go To item was also to this
SmartList object.

The Last Contact and Last


Contact Salesperson
columns were added to the
Customers SmartList object.

You can also create new SmartList objects that provide access to the data for your
integration. For instance, the following illustration shows the SmartList displaying
lead information using the Leads SmartList object defined in the sample integrating
application.

The new Leads SmartList


object provides access to
lead information.

330 IN T E G R AT I O N G U ID E
C H A P T E R 3 2 S M A R T LI S T O V E R V I E W

Integration technique
Creating a SmartList integration is a rather complex task. You will add several items
to your integrating application’s dictionary during the process. These include the
following:

Global variables
If you will be creating a new SmartList object for your integration, you will need to
create a global variable that will hold the key values for the row that is being added
to the SmartList.

Triggers and processing procedures


Object triggers registered to activate when the SmartList window is opened are
used to add new columns and Go To items to existing SmartList objects. They are
also used to create new SmartList objects. Trigger processing procedures perform
the steps necessary to add columns and Go To items to SmartList objects.

Global procedures
You will add several global procedures with special names that will be called
automatically by the SmartList. These procedures will supply SmartList with
information needed to display data, perform Go To actions, and so on. All of these
procedures will begin with the word Explorer, which is the internal name used for
SmartList.

The Explorer procedures you add to your dictionary will be shared by all of the
SmartList objects you create, as well as the new columns and Go To items you add
to existing SmartList objects. The code you add to these procedures must use the
parameters passed into the procedure to know which SmartList object is requesting
information.

For example, “Explorer_Get_Table_Name” is one of the procedures you will add for
your SmartList integration. This procedure returns the technical name of a table that
contains the data for a specific column. The procedure has the following
parameters:

inout string l_Table_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in integer IN_Doc_Type;

Notice the parameters that specify the SmartList object and field being queried. You
will use these parameters to know when one of your SmartList objects or columns is
being queried.

You will learn about the specific procedures in Chapter 33, “Adding to SmartList Objects,”
and Chapter 34, “Creating New SmartList Objects.”

INTEGRATION GUIDE 331


PA RT 7 S M A R T L I S T

Testing
You will have better results if you complete your SmartList integration code before
testing it. All of the SmartList procedures work together, so any missing procedures
will cause runtime errors.

Remember that SmartList resources are stored in a third-party dictionary, so they


can only be accessed with the runtime engine. You cannot test your SmartList
integration with test mode.

The SmartList column and Go To records are stored in tables in the system database.
As you test, you may need to manually remove SmartList columns and Go To items
that you added for your integration. If incorrect parameter values were used when
you added these items, subsequent attempts to re-add the corrected items will fail
because the records already exist. The column information is stored in the
ASITAB20 table, while the Go To information is stored in the ASIEXP60 table.

Explorer procedures
Your integration will call several procedures defined in the SmartList dictionary.
These procedures perform actions like creating new SmartList objects, adding or
removing columns from a SmartList object, and so on. All of these procedures
beginwith the word Explorer, which is the internal name used for SmartList.

Since these procedures are defined in another third-party dictionary, you must call
them using the call with name statement. When using this statement, the procedure
names are passed in as strings, and there is no compile-time checking. Be sure to
type them carefully and watch for runtime errors.

SmartList objects
This section lists the SmartList objects that are defined for Microsoft Dynamics GP.
You can add additional columns and Go To items to these objects. The constant used
to refer to the object, along with the tables and join information for the object are
listed.

Account Summary
Object type value 13
Constant SMARTLIST_OBJECTTYPE_ACCOUNTSUMMARY
Tables GL10110 - GL_Account_SUM_MSTR
GL10111 - GL_Account_SUM_HIST
GL00100 - GL_Account_MSTR
Joins GL10110 left-outer join to GL00100
GL10111 left-outer join to GL00100

332 IN T E G R AT I O N G U ID E
C H A P T E R 3 2 S M A R T LI S T O V E R V I E W

Account Transactions
Object type value 12
Constant SMARTLIST_OBJECTTYPE_ACCOUNTTRANSACTIONS
Tables GL10001 - GL_TRX_LINE_WORK
GL20000 - GL_YTD_TRX_OPEN
GL30000 - GL_Account_TRX_HIST
MC40200 - MC_Currency_SETP
GL00100 - GL_Account_MSTR
GL10000 - GL_TRX_HDR_WORK
Joins GL10001 left-outer join to MC40200
GL10001 left-outer join to GL00100
GL10001 left-outer join to GL10000
GL20000 left-outer join to GL00100
GL20000 left-outer join to GL10000
GL30000 left-outer join to GL00100

Accounts
Object type value 1
Constant SMARTLIST_OBJECTTYPE_ACCOUNTS
Tables GL00100 - GL_Account_MSTR
Joins None

Bank Transactions
Object type value 22
Constant SMARTLIST_OBJECTTYPE_BANKTRANSACTIONS
Tables CM20300 - CM_Recipt
CM20200 - CM_Transaction
Joins None

Customer Addresses
Object type value 15
Constant SMARTLIST_OBJECTTYPE_CUSTOMERADDRESSES
Tables RM00102 - RM_Customer_MSTR_ADDR
RM00101 - RM_Customer_MSTR
SY01200 - coINetAddrs
Joins RM00102 left-outer join to RM00101
RM00102 left-outer join to SY01200

Customer Items
Object type value 24
Constant SMARTLIST_OBJECTTYPE_CUSTOMERITEMS
Tables SOP60300 - sopCustomerItemXref
IV00101 - IV_Item_MSTR
RM00101 - RM_Customer_MSTR
RM00103 - RM_Customer_MSTR_SUM
Joins SOP60300 left-outer join to IV00101
SOP60300 left-outer join to RM00101
SOP60300 left-outer join to RM00103

INTEGRATION GUIDE 333


PA RT 7 S M A R T L I S T

Customers
Object type value 2
Constant SMARTLIST_OBJECTTYPE_CUSTOMERS
Tables RM00101 - RM_Customer_MSTR
Joins None

Employee Summary
Object type value 32
Constant SMARTLIST_OBJECTTYPE_EMPLOYEESUMMARY
Tables UPR00100 - UPR_MSTR
UPR00900 - UPR_Employee_SUM
UPR00901 - UPR_Employee_Tips_SUM
UPR00300 - UPR_MSTR_Tax_Info
UPR00900 - UPR_Employee_SUM
Joins UPR00100 left-outer join to UPR00900
UPR00100 left-outer join to UPR00901
UPR00100 left-outer join to UPR00300
UPR00900 left-outer join to UPR00901

Employees
Object type value 5
Constant SMARTLIST_OBJECTTYPE_EMPLOYEES
Tables UPR00100 - UPR_MSTR
UPR00300 - UPR_MSTR_Tax_Info
UPR00102 - uprMstrAddress
Joins UPR00100 left-outer join to UPR00300
UPR00100 left-outer join to UPR00102

Inventory Transactions
Object type value 19
Constant SMARTLIST_OBJECTTYPE_INVENTORYTRANSACTIONS
Tables IV10001 - IV_TRX_WORK_LINE
IV40201 - IV_UofM_SETP_HDR
IV10000 - IV_TRX_WORK_HDR
IV30300 - IV_TRX_HIST_LINE
IV30200 - IV_TRX_HIST_HDR
IV00101 - IV_Item_MSTR
Joins IV10001 left-outer join to IV00101
IV10001 left-outer join to IV10000
IV30300 left-outer join to IV00101
IV30300 left-outer join to IV30200
IV00101 left-outer join to IV40201

334 IN T E G R AT I O N G U ID E
C H A P T E R 3 2 S M A R T LI S T O V E R V I E W

Item Quantities
Object type value 11
Constant SMARTLIST_OBJECTTYPE_ITEMQUANTITIES
Tables IV00102 - IV_Item_MSTR_QTYS
IV00103 - IV_Item_MSTR_VNDR
PM00200 - PM_Vendor_MSTR
IV00101 - IV_Item_MSTR
IV40201 - IV_UofM_SETP_HDR
Joins IV00102 left-outer join to IV00103
IV00102 left-outer join to PM00200
IV00102 left-outer join to IV00101
IV00101 left-outer join to IV40201

Items
Object type value 4
Constant SMARTLIST_OBJECTTYPE_ITEMS
Tables IV00101 - IV_Item_MSTR
Joins None

Landed Cost Group ID


Object type value 31
Constant SMARTLIST_OBJECTTYPE_LANDEDCOSTGROUPID
Tables IV41101 - ivLandedCostGroup
IV41102 - ivLandedCostGroupDetails
IV41100 - ivLandedCost
Joins IV41101 left-outer join to IV41102
IV41102 left-outer join to IV41100

Landed Cost ID
Object type value 30
Constant SMARTLIST_OBJECTTYPE_LANDEDCOSTID
Tables IV41100 - ivLandedCost
Joins None

Multidimensional Analysis
Object type value 14
Constant SMARTLIST_OBJECTTYPE_MDA
Tables DTA10200 - DTA_Transaction_Codes_WORK
DTA10100 - DTA_Transaction_Groups_WORK
GL00100 - GL_Account_MSTR
Joins DTA10200 left-outer join to DTA10100
DTA10200 left-outer join to GL00100

INTEGRATION GUIDE 335


PA RT 7 S M A R T L I S T

Payables Transactions
Object type value 9
Constant SMARTLIST_OBJECTTYPE_PAYABLESTRANSACTIONS
Tables PM10000 - PM_Transaction_WORK
MC020103 - MC_PM_Transactions
PM00200 - PM_Vendor_MSTR
PM00201 - PM_Vendor_MSTR_SUM
PM20000 - PM_Transaction_OPEN
PM30200 - PM_Paid_Transaction_HIST
Joins PM10000 left-outer join to MC020103
PM10000 left-outer join to PM00200
PM10000 left-outer join to PM00201
PM20000 left-outer join to MC020103
PM20000 left-outer join to PM00200
PM20000 left-outer join to PM00201
PM30200 left-outer join to MC020103
PM30200 left-outer join to PM00200
PM30200 left-outer join to PM00201

Payroll Historical Transactions


Object type value 18
Constant SMARTLIST_OBJECTTYPE_PAYROLLHISTORICALTRX
Tables UPR30300 - UPR_Transaction_HIST
UPR00100 - UPR_MSTR
UPR00300 - UPR_MSTR_Tax_Info
UPR00102 - uprMstrAddress
Joins None

Payroll Transactions
Object type value 10
Constant SMARTLIST_OBJECTTYPE_PAYROLLTRANSACTIONS
Tables UPR10302 - UPR_TRX_Batch_Detail
UPR00100 - UPR_MSTR
UPR00300 - UPR_MSTR_Tax_Info
UPR00102 - uprMstrAddress
Joins UPR10302 left-outer join to UPR00100
UPR10302 left-outer join to UPR00300
UPR00100 left-outer join to UPR00102

Prospects
Object type value 17
Constant SMARTLIST_OBJECTTYPE_PROSPECTS
Tables SOP00200 - SOP_Prospect_MSTR
Joins None

336 IN T E G R AT I O N G U ID E
C H A P T E R 3 2 S M A R T LI S T O V E R V I E W

Purchase Line Items


Object type value 21
Constant SMARTLIST_OBJECTTYPE_PURCHASELINEITEMS
Tables POP10110 - POP_POLine
POP10100 - POP_PO
IV00101 - IV_Item_MSTR
PM00200 - PM_Vendor_MSTR
PM00201 - PM_Vendor_MSTR_SUM
RM00101 - RM_Customer_MSTR
RM00103 - RM_Customer_MSTR_SUM
POP30110 - POP_POLineHist
POP30100 - POP_POHist
IV40201 - IV_UofM_SETP_HDR
Joins POP10110 left-outer join to POP10100
POP10110 left-outer join to IV00101
POP10110 left-outer join to PM00200
POP10110 left-outer join to PM00201
POP10100 left-outer join to RM00101
POP10100 left-outer join to RM00103
POP30110 left-outer join to POP30100
POP30110 left-outer join to IV00101
POP30110 left-outer join to PM00200
POP30110 left-outer join to PM00201
POP30100 left-outer join to RM00101
POP30100 left-outer join to RM00103
IV00101 left-outer join to IV40201

Purchase Orders
Object type value 7
Constant SMARTLIST_OBJECTTYPE_PURCHASEORDERS
Tables POP10100 - POP_PO
PM00200 - PM_Vendor_MSTR
PM00201 - PM_Vendor_MSTR_SUM
RM00101 - RM_Customer_MSTR
RM00103 - RM_Customer_MSTR_SUM
POP30100 - POP_POHist
Joins POP10100 left-outer join to PM00200
POP10100 left-outer join to PM00201
POP10100 left-outer join to RM00101
POP10100 left-outer join to RM00103
POP30100 left-outer join to PM00200
POP30100 left-outer join to PM00201
POP30100 left-outer join to RM00101
POP30100 left-outer join to RM00103

INTEGRATION GUIDE 337


PA RT 7 S M A R T L I S T

Receivables Transactions
Object type value 8
Constant SMARTLIST_OBJECTTYPE_RECEIVABLESTRANSACTIONS
Tables RM10301 - RM_Sales_WORK
RM00101 - RM_Customer_MSTR
MC020102 - MC_RM_Transactions
RM00103 - RM_Customer_MSTR_SUM
RM20101 - RM_OPEN
RM30101 - RM_HISTORY
Joins RM10301 left-outer join to RM00101
RM10301 left-outer join to MC020102
RM10301 left-outer join to RM00103
RM20101 left-outer join to RM00101
RM20101 left-outer join to MC020102
RM20101 left-outer join to RM00103
RM30101 left-outer join to RM00101
RM30101 left-outer join to MC020102
RM30101 left-outer join to RM00103

Receivings Line Items


Object type value 28
Constant SMARTLIST_OBJECTTYPE_RECEIVINGSLINEITEMS
Tables POP10310 - POP_ReceiptLine
POP10300 - POP_Receipt
ASIV0001 - ASI_POP_ReceiptLine_QTYS
IV00101 - IV_Item_MSTR
POP30310 - POP_ReceiptLineHist
POP30300 - POP_ReceiptHist
IV40201 - IV_UofM_SETP_HDR
Joins POP10310 left-outer join to POP10300
POP10310 left-outer join to ASIV0001
POP10310 left-outer join to IV00101
POP30310 left-outer join to POP30300
POP30310 left-outer join to ASIV0001
POP30310 left-outer join to IV00101
IV00101 left-outer join to IV40201

Receivings Transactions
Object type value 27
Constant SMARTLIST_OBJECTTYPE_RECEIVINGSTRANSACTIONS
Tables POP10300 - POP_Receipt
PM00201 - PM_Vendor_MSTR_SUM
POP10306 - POP_ReceiptUserDefined
POP30300 - POP_ReceiptHist
Joins POP10300 left-outer join to PM00201
POP10300 left-outer join to POP10306
POP30300 left-outer join to PM00201
POP30300 left-outer join to POP10306

338 IN T E G R AT I O N G U ID E
C H A P T E R 3 2 S M A R T LI S T O V E R V I E W

Sales Line Items


Object type value 20
Constant SMARTLIST_OBJECTTYPE_SALESLINEITEMS
Tables SOP10200 - SOP_LINE_WORK
IV00101 - IV_Item_MSTR
SOP10100 - SOP_HDR_WORK
SOP10106 - sopUsrDefWorkHist
RM00101 - RM_Customer_MSTR
RM00103 - RM_Customer_MSTR_SUM
SOP30300 - SOP_LINE_HIST
SOP30200 - SOP_HDR_HIST
IV40201 - IV_UofM_SETP_HDR
Joins SOP10200 left-outer join to IV00101
SOP10200 left-outer join to SOP10100
SOP10200 left-outer join to SOP10106
SOP10100 left-outer join to RM00101
SOP10100 left-outer join to RM00103
SOP30300 left-outer join to IV00101
SOP30300 left-outer join to SOP30200
SOP30300 left-outer join to SOP10106
SOP30200 left-outer join to RM00101
SOP30200 left-outer join to RM00103
IV00101 left-outer join to IV40201

Sales Transactions
Object type value 6
Constant SMARTLIST_OBJECTTYPE_SALESTRANSACTIONS
Tables SOP10100 - SOP_HDR_WORK
SOP10106 - sopUsrDefWorkHist
RM00101 - RM_Customer_MSTR
RM00103 - RM_Customer_MSTR_SUM
SOP30200 - SOP_HDR_HIST
Joins SOP10100 left-outer join to SOP10106
SOP10100 left-outer join to RM00101
SOP10100 left-outer join to RM00103
SOP30200 left-outer join to SOP10106
SOP30200 left-outer join to RM00101
SOP30200 left-outer join to RM00103

Tax Detail Transactions


Object type value 29
Constant SMARTLIST_OBJECTTYPE_TAXDETAILTRANSACTIONS
Tables TX30000 - taxHistory
TX00201 - TX_Detail_MSTR
GL00100 - GL_Account_MSTR
Joins TX30000 left-outer join to TX00201
TX30000 left-outer join to GL00100

INTEGRATION GUIDE 339


PA RT 7 S M A R T L I S T

Vendor Addresses
Object type value 16
Constant SMARTLIST_OBJECTTYPE_VENDORADDRESSES
Tables PM00300 - PM_Address_MSTR
PM00200 - PM_Vendor_MSTR
SY01200 - coINetAddrs
Joins PM00300 left-outer join to PM00200
PM00300 left-outer join to SY01200

Vendor Items
Object type value 23
Constant SMARTLIST_OBJECTTYPE_VENDORITEMS
Tables IV00103 - IV_Item_MSTR_VNDR
IV00101 - IV_Item_MSTR
PM00200 - PM_Vendor_MSTR
Joins IV00103 left-outer join to IV00101
IV00103 left-outer join to PM00200

Vendors
Object type value 3
Constant SMARTLIST_OBJECTTYPE_VENDORS
Tables PM00200 - PM_Vendor_MSTR
PM00201 - PM_Vendor_MSTR_SUM
PA00001 - paCustomerVendorMSTR
RM00101 - RM_Customer_MSTR
Joins PM00200 left-outer join to PM00201
PM00200 left-outer join to PA00001
PM00200 left-outer join to RM00101

340 IN T E G R AT I O N G U ID E
Chapter 33: Adding to SmartList Objects
You can add additional columns and Go To items to existing SmartList objects.
Information about adding these items is contained in the following sections:

• Columns
• Go To items

Columns
Additional columns you add to a SmartList object will reference data related to the
object. For example, the sample integrating application adds columns to the
Customers SmartList object that track customer contact history information. The
new columns appear identical to those that exist for the object.

Trigger to add columns


Additional columns should be added when the SmartList window is being opened.
At that time, the resources in the SmartList dictionary will be available so the
columns can be added. The following example is a portion of the Startup script for
the sample integrating application. It registers a focus trigger for the ASI_Explorer
form which is the main form for the SmartList. Notice that the trigger is registered
by name, since the form is located in the SmartList dictionary, not the core
dictionary.

l_result = Trigger_RegisterFocusByName(SMARTLIST, "form ASI_Explorer",


➥ TRIGGER_FOCUS_PRE, TRIGGER_AFTER_ORIGINAL, script
➥ SmartList_AddCustomerColumns);
if l_result <> SY_NOERR then
warning "Focus trigger registration for SmartList failed.";
end if;

The trigger processing procedure that runs when the trigger is activated will add
the new columns to the Customer SmartList object. Use the
Explorer_Add_Column_To_Object procedure in the SmartList dictionary to add
the new columns. When you add a column, you specify the following:

• The product and SmartList object to which a column is being added


• The unique ID of the column (typically the field’s resource ID)
• The label to display for the column
• The initial width for the column
• The technical name of the global field used for the column
• Whether the column will appear by default for the object
• The type of data the column will display
• The type of list (used if the field is a list-type field)

INTEGRATION GUIDE 341


PA RT 7 S M A R T L I S T

The following trigger processing procedure from the sample integrating application
shows how two columns are added to the Customers SmartList object.

local integer l_error;


local string l_message;
local integer display_sequence, field_sequence;

{Add additional columns to the Customer object for SmartList}


call with name "Explorer_Add_Column_To_Object" in dictionary SMARTLIST,
DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
IG_PROD_ID,
resourceid(field 'First Contact Date'),
"First Contact",
technicalname(field 'First Contact Date'),
false, {Do not include in default query}
SMARTLIST_DATATYPE_DATE,
1,
false,
false,
display_sequence,
field_sequence,
l_error;

if l_error <> OKAY and l_error <> 17 then


l_message = getmsg(22003);
substitute l_message, "Explorer_Add_Column_To_Object", str(l_error);
error l_message;
end if;

call with name "Explorer_Add_Column_To_Object" in dictionary SMARTLIST,


DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
IG_PROD_ID,
resourceid(field 'Contact Salesperson ID'),
"First Contact Salesperson",
technicalname(field 'Contact Salesperson ID'),
false, {Do not include in default query}
SMARTLIST_DATATYPE_STRING,
1,
false,
false,
display_sequence,
field_sequence,
l_error;

Retrieving the table name


Add the When SmartList displays columns for the selected object, it must retrieve which
Explorer_Get_Table_ table the field used for the column can be found in. The Explorer_Get_Table_Name
Name procedure. procedure will be called by SmartList to perform this action. In this procedure, you
will return the table technical name for the field used in the columns you added to a
SmartList object.

The following is the Explorer_Get_Table_Name procedure that retrieves the table


technical name for the columns added to the Customers SmartList object. The fields
for the columns added all come from the IG_Contact_History_MSTR table.

342 IN T E G R AT I O N G U ID E
C H A P T E R 3 3 AD DI NG T O S M AR TL IST OBJE CT S

Procedure name: Explorer_Get_Table_Name

inout string l_Table_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in integer IN_Doc_Status;

if IN_Object_Dict_ID = DYNAMICS then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then
l_Table_Name = technicalname(table IG_Contact_History_MSTR);
end if;
end if;

Retrieving column datatypes


Add the As SmartList works with a SmartList object, it must be told what type of data is
Explorer_Get_Datatype found in each column. The Explorer_Get_Datatype procedure will be called by
procedure. SmartList to perform this action. In this procedure, you will set the datatype for
each column you added to a SmartList object.

The following is the Explorer_Get_Datatype procedure that retrieves the column


datatypes for the columns added to the Customers SmartList object. Note the else
clause of the case statement. This is necessary so that the “Any Field” search feature
of SmartList works properly.

Procedure name: Explorer_Get_Datatype

inout integer IO_Datatype;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

{Handle cases for objects already defined in Microsoft Dynamics GP}


if IN_Object_Dict_ID = DYNAMICS then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then
if IN_Field_Dict_ID = IG_PROD_ID then
case IN_Field_ID
in[resourceid(field 'First Contact Date')]
IO_Datatype = SMARTLIST_DATATYPE_DATE;
in[resourceid(field 'Contact Salesperson ID')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in[resourceid(field 'Last Contact Date')]
IO_Datatype = SMARTLIST_DATATYPE_DATE;
in[resourceid(field 'Contact Salesperson ID 2')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
else
{The "Any" field case for searching}
IO_Datatype = SMARTLIST_DATATYPE_ALL;
end case;
end if;
end if;
end if;

INTEGRATION GUIDE 343


PA RT 7 S M A R T L I S T

Retrieving column values


Add the As SmartList fills with data, each column value must be supplied as a string. The
Explorer_Get_Field_ Explorer_Get_Field_As_String_From_Table procedure will be called by SmartList to
As_String_From_Table retrieve the string value to use for a column as each row of the SmartList is filled.
procedure. This procedure must have the following parameters:

inout string IO_String;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in boolean IN_Searching;
in string IN_Master_ID;
inout integer IO_Datatype;
inout long IO_Long;
inout date IO_Date;
inout currency IO_Currency;
inout time IO_Time;

The IN_Master_ID parameter will contain the values of the key fields for the
primary key of the main table for the SmartList object. You will use these key fields
to retrieve the appropriate record from your table for the row being displayed in the
SmartList. Refer to SmartList objects on page 332 for a list of the primary tables that
correspond to the SmartList object types.

The field values passed in though the IN_Master_ID parameter will be padded with
spaces to each field’s specified length. For example, a field with the STR30 datatype
will be padded to a length of 30. Your code must parse the string into the individual
field values.

After your code has retrieved the appropriate record from your table, it must set the
inout parameters for the column you added. The value of the IO_String parameter
must be set to the string value you want displayed in the SmartList. If necessary,
you can apply formatting to this string. For instance, you could use the format()
function to apply formatting to a currency value.

Your code must set the IO_Datatype parameter, which specifies the underlying
datatype for the column. Then it must set the value of the corresponding parameter
for the datatype. For example, if the column displays a currency value, you will set
the IO_Datatype parameter to SMARTLIST_DATATYPE_CURRENCY and set the
IO_Currency parameter to the actual currency value for the column.

The following is the Explorer_Get_Field_As_String_From_Table procedure from the


sample integrating application. Based on the key value passed in through the
IN_Master_ID parameter, it retrieves the appropriate record from the
IG_Contact_History_MSTR table. It then sets the IO_String parameter and the
appropriate datatype parameters.

344 IN T E G R AT I O N G U ID E
C H A P T E R 3 3 AD DI NG T O S M AR TL IST OBJE CT S

Procedure name: Explorer_Get_Field_As_String_From_Table

inout string IO_String;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in boolean IN_Searching;
in string IN_Master_ID;

inout integer IO_Datatype;


inout long IO_Long;
inout date IO_Date;
inout currency IO_Currency;
inout time IO_Time;

if (IN_Object_Dict_ID = DYNAMICS) and (IN_Field_Dict_ID = IG_PROD_ID) then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then
'Customer Number' of table IG_Contact_History_MSTR = IN_Master_ID;
get table IG_Contact_History_MSTR;
if err() = OKAY then
case IN_Field_ID
in[resourceid(field 'First Contact Date')]
IO_Datatype = SMARTLIST_DATATYPE_DATE;
IO_Date = 'First Contact Date' of table
➥ IG_Contact_History_MSTR;
IO_String = str('First Contact Date' of table
➥ IG_Contact_History_MSTR);
in[resourceid(field 'Contact Salesperson ID')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
IO_String = 'Contact Salesperson ID' of table
➥ IG_Contact_History_MSTR;
in[resourceid(field 'Last Contact Date')]
IO_Datatype = SMARTLIST_DATATYPE_DATE;
IO_Date = 'Last Contact Date' of table
➥ IG_Contact_History_MSTR;
IO_String = str('Last Contact Date' of table
➥ IG_Contact_History_MSTR);
in[resourceid(field 'Contact Salesperson ID 2')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
IO_String = 'Contact Salesperson ID 2' of table
➥ IG_Contact_History_MSTR;
end case;
end if;
end if;
end if;

Retrieving list field type


Add the Most list fields are 1-based and number the items in the list 1, 2, 3, and so on. The
Explorer_Get_DDL_ exception is radio groups, which are 0-based and number the items 0, 1, 2, and so
Type procedure. on. If you are adding a list field as a column to a SmartList, you must use the
Explorer_Get_DDL_Type procedure to tell SmartList how the items in the list field
are numbered. The value 1 indicates a 1-based list field, while the value 0 indicates a
0-based list field.

INTEGRATION GUIDE 345


PA RT 7 S M A R T L I S T

The following is the Explorer_Get_DDL_Type procedure for the sample integrating


application. All of the list fields from the sample that are used for SmartList
columns are 1-based, so the value 1 is returned.

Procedure name: Explorer_Get_DDL_Type

out integer OUT_DDL_Type;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

{All of the drop-down lists in the sample are 1-based}


if IN_Object_Dict_ID = IG_PROD_ID then
OUT_DDL_Type = 1;
end if;

Retrieving list field values


Add the To make it easier for the user to create SmartList search criteria, the items for list
Explorer_Fill_Range_ field columns are displayed in the Search window. For instance, the following
DDLs_From_Field_ID illustration shows the choices displayed for the Qualified list column.
procedure.

You will add the Explorer_Fill_Range_DDLs_From_Field_ID procedure to your


application to retrieve the the values for the list columns you have added. This
procedure must have the following parameters:

in integer IN_Object_DictID;
in integer IN_Object_Type;
in integer IN_FieldDictID;
in integer IN_FieldID;
inout anonymous field IO_From_DDL;
inout anonymous field IO_To_DDL;

The IO_From_DDL and IO_To_DDL parameters contain references to the two drop-
down lists that appear in the Search window. Your code must fill these drop-down
lists with the values for the list field of the column the user selected. List fields must
be window fields to have their static values read by sanScript code. You will need to
place an instance of the list field on a hidden window so its static values can be
accessed. A hidden window on a command form is a good place to add the hidden
list field.

The following is the Explorer_Fill_Range_DDLs_From_Field_ID procedure for the


sample integrating application. When the Qualified column is searched, it sets the
static values for the drop-down lists that are displayed in the Search window.
Notice that it references an instance of the Qualified Lead list field on a hidden
window so that the static items can be retrieved.

346 IN T E G R AT I O N G U ID E
C H A P T E R 3 3 AD DI NG T O S M AR TL IST OBJE CT S

Procedure name: Explorer_Fill_Range_DDLs_From_Field_ID

in integer IN_Object_DictID;
in integer IN_Object_Type;
in integer IN_FieldDictID;
in integer IN_FieldID;
inout anonymous field IO_From_DDL;
inout anonymous field IO_To_DDL;

local integer i;

if IN_Object_DictID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
if IN_FieldID = resourceid(field 'Qualified Lead') then
{Clear the drop-down lists before filling them}
clear field IO_From_DDL;
clear field IO_To_DDL;
for i = 1 to countitems('Qualified Lead' of window Dummy of form
➥ Command_IG_Sample) do
add item itemname('Qualified Lead' of window Dummy of form
➥ Command_IG_Sample, i) to field IO_From_DDL;
add item itemname('Qualified Lead' of window Dummy of form
➥ Command_IG_Sample, i) to field IO_To_DDL;
end for;
end if;
end if;
end if;

SQL optimization
SmartList can perform optimized searches when used with SQL Server. To take
advantage of this optimization for the columns you have added, you must indicate
that you have added the necessary procedures to support the optimization. These
additional procedures will be called by SmartList as it searches data in the new
columns you have added.

Since SQL Server is supported for all products, we recommend that you support SQL
optimization for the columns you add to existing SmartList objects.

Add the To indicate that the new columns you have added support SQL optimization, you
Explorer_Optimize_ will add the Explorer_Optimize_For_SQL procedure to your integration. This
For_SQL procedure. procedure should return true if you support optimization for the object, and false if
you do not.

The following is the Explorer_Optimize_For_SQL procedure from the sample


integrating application. The sample adds columns to the Customers SmartList
object. It provides the additional procedures needed to support SQL optimization,
so it returns the value true when asked about whether the Customers SmartList
object is optimized.

Procedure name: Explorer_Optimize_For_SQL

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field;
inout boolean IO_Optimize;

INTEGRATION GUIDE 347


PA RT 7 S M A R T L I S T

{By default, assume not optimized}


IO_Optimize = false;
{Customers SmartList object additional columns are optimized}
if IN_Object_Dict_ID = DYNAMICS then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then
IO_Optimize = true;
warning "Customers stuff is optimized";
end if;
end if;

Retrieving SQL field information


Add the Most SmartList objects are optimized for SQL Server. To allow searching based on
Explorer_Get_SQL_ the columns you add to a SQL-optimized object, you must add the
Field_Info procedure. Explorer_Get_SQL_Field_Info procedure to your application. This procedure
returns the following for each column:

• Table technical name of the table that stores the data for the column
• ID of the dictionary containing the table that stores the data for the column
• Type of list field used for the column (if applicable)

This information is used when generating the SQL query used to search for
matching records.

The following is the Explorer_Get_SQL_Field_Info procedure from the sample


integrating application. For the sample, all of the fields for the additional columns
come from the IG_Contact_History_MSTR table.

Procedure name: Explorer_Get_SQL_Field_Info

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field;
inout string IO_Table_Name;
inout integer IO_Table_Dict_ID;
inout integer IO_DDL_Type;

if IN_Object_Dict_ID = DYNAMICS then


if IN_Field_Dict_ID = IG_PROD_ID then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then
IO_Table_Name = technicalname(table IG_Contact_History_MSTR);
IO_Table_Dict_ID = IG_PROD_ID;
IO_DDL_Type = 1;
end if;
end if;
end if;

Setting SQL join information


Add the For SmartList objects that are optimized for SQL Server, it’s necessary to describe
Explorer_Get_SQL_ how the tables used for additional columns are related to the main table for the
Join_Info procedure. SmartList object. You will add the Explorer_Get_SQL_Join_Info procedure to your
application to do this. In this procedure you will call the
Explorer_Set_SQL_Join_Info procedure in the SmartList dictionary to define the
join that describes how the main table for the SmartList object is related to the table
that contains data for the columns you’ve added. You will call this procedure once
for each field that is part of the join.

348 IN T E G R AT I O N G U ID E
C H A P T E R 3 3 AD DI NG T O S M AR TL IST OBJE CT S

Several types of joins are supported, but virtually all joins needed for SmartList are left-
outer joins.

The following is the Explorer_Get_SQL_Join_Info procedure from the sample


integrating application. In the sample, columns are added to the Customers
SmartList object. The main table for this object is the RM_Customer_MSTR table.
The data for the new columns comes from the IG_Contact_History_MSTR table.
This means that a join must be made from the RM_Customer_MSTR table to the
IG_Contact_History_MSTR table. The key field these two tables share in common is
the Customer Number. There are 0 or 1 records in the IG_Contact_History_MSTR
table for each record on the RM_Customer_MSTR table, so a left-outer join is
appropriate.

Procedure name: Explorer_Get_SQL_Join_Info

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
inout integer l_Doc_Status;

local integer i, l_Exp_Error;


local string l_From_Table, l_From_Field, l_To_Table, l_To_Field;
local integer l_From_Table_Dict_ID, l_To_Table_Dict_ID, l_Join_Type;

if IN_Object_Dict_ID = DYNAMICS then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then

{Set the characteristics of the join}


l_From_Table = technicalname(table RM_Customer_MSTR);
l_From_Table_Dict_ID = DYNAMICS;
l_From_Field = technicalname(field 'Customer Number');
l_To_Table = technicalname(table IG_Contact_History_MSTR);
l_To_Table_Dict_ID = IG_PROD_ID;
l_To_Field = technicalname(field 'Customer Number');
l_Join_Type = SMARTLIST_JOINTYPE_LEFTOUTER;

{Add the join}


call with name "Explorer_Set_SQL_Join_Info" in dictionary SMARTLIST,
l_From_Table,
l_From_Table_Dict_ID,
l_From_Field,
l_To_Table,
l_To_Table_Dict_ID,
l_To_Field,
l_Join_Type,
l_Exp_Error;

{Check for a join error}


if l_Exp_Error <> 0 then
warning "SQL join error: " + str(l_Exp_Error);
end if;
end if;
end if;

INTEGRATION GUIDE 349


PA RT 7 S M A R T L I S T

Overriding field names


Add the In special cases, the name used for a field will change depending upon the type of
Explorer_Get_SQL_ document the field is contained in. For example, this issue occurrs for inventory
Override_Field_Name transactions. If the inventory document being displayed in SmartList comes from
procedure. the “work” table, the document number field is named IV Document Number.
However, if the document comes from the “history” table, the document
number field is named Document Number. You will add the
Explorer_Get_SQL_Override_Field_Name procedure to your application to handle
these special cases. This procedure must return the appropriate field name to use,
based on the document type.

If you don’t have field names that change based on the document type, this
procedure should return the empty string. This causes the original field name to be
used.

The following is the Explorer_Get_SQL_Override_Field_Name procedure for the


sample integrating application. There are no field names that change based on the
document type, so an empty string is returned for the field name.

out string OUT_Field_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_Number;
in integer IN_Doc_Type;

clear OUT_Field_Name;

Go To items
Go To items in SmartList provide quick navigation to the windows in the
accounting system that allow you to view of modify the selected item. You can add
additional Go To items to existing SmartList objects.

Trigger to add Go To items


Additional Go To items should be added when the SmartList window is being
opened. At that time, the resources in the SmartList dictionary will be available so
the Go To items can be added. The following example is a portion of the Startup
script for the sample integrating application. It registers a focus trigger for the
ASI_Explorer form which is the main form for the SmartList. Notice that the trigger
is registered by name, since the form is located in the SmartList dictionary, not the
core dictionary.

l_result = Trigger_RegisterFocusByName(SMARTLIST, "form ASI_Explorer",


➥ TRIGGER_FOCUS_PRE, TRIGGER_AFTER_ORIGINAL, script
➥ SmartList_AddCustomerGoTo);
if l_result <> SY_NOERR then
warning "Focus trigger registration for SmartList failed.";
end if;

350 IN T E G R AT I O N G U ID E
C H A P T E R 3 3 AD DI NG T O S M AR TL IST OBJE CT S

The trigger processing procedure that runs when the trigger is activated will add
the new Go To items to the Customer SmartList object. Use the
Explorer_Add_GoTo_Item procedure in the SmartList dictionary to add the new
Go To items. When you add a Go To item, you specify the following:

• The product and SmartList object to which a Go To item is being added


• The text to display for the Go To item (use a dash for a separator item)
• The dictionary ID of the product that contains the Go To processing code
• The unique ID of the Go To item
• Whether the Go To item will be the default action for the SmartList object

The following trigger processing procedure from the sample integrating application
shows how an additional Go To item is added to the Customers SmartList object.

local integer l_error;


local string l_message;

call with name "Explorer_Add_GoTo_Item" in dictionary SMARTLIST,


DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
"Contact History",
IG_PROD_ID,
resourceid(form IG_Contact_History), {Unique ID for this form}
false, {Not the default Go To item}
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
set l_message to getmsg(22002);
substitute l_message, "Explorer_Add_GoTo_Item", str(l_error);
error l_message;
end if;

Processing Go To items
Add the The additional Go To items you add must be processed by the procedure named
Explorer_GoTo_Button Explorer_GoTo_Button that you will add to your dictionary. This procedure must
procedure. have the following parameters:

inout anonymous field IN_ListView;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_GoTo_Dict_ID;
in integer IN_GoTo_Item;

The procedure will examine the values passed into these parameters to determine
whether it must process the Go To item. If it should, the list view field for the Smart
List is passed in as an anonymous field. This allows the code to find the currently-
selected line and perform the specified action for that item.

The following is the Explorer_GoTo_Button procedure for the sample integrating


application. If the user chooses the Contact History item for the Customers
SmartList, this code will find the first selected customer and display the contact
history record for that customer.

INTEGRATION GUIDE 351


PA RT 7 S M A R T L I S T

inout anonymous field IN_ListView;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_GoTo_Dict_ID;
in integer IN_GoTo_Item;

local long selected_item;


local string LeadID;
local string CustomerID;

{Is this the Go To item added to the Customer object?}


if IN_Object_Dict_ID = DYNAMICS then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then
if IN_GoTo_Item = resourceid(form IG_Contact_History) then
{Try to find the first customer selected in the list}
selected_item = ListView_SelectionGet(IN_ListView, 1);
if selected_item <> 0 then
CustomerID = ListView_ItemGetLabel(IN_ListView,
➥ selected_item);
open form RM_Customer_Maintenance;
'Customer Number' of window RM_Customer_Maintenance of form
➥ RM_Customer_Maintenance = CustomerID;
run script 'Customer Number' of window RM_Customer_Maintenance
➥ of form RM_Customer_Maintenance;
open form IG_Contact_History;
'Customer Number' of window 'Contact History' of form
➥ IG_Contact_History = CustomerID;
run script 'Customer Number' of window 'Contact History' of
➥ form IG_Contact_History;
end if;
end if;
end if;
end if;

352 IN T E G R AT I O N G U ID E
Chapter 34: Creating New SmartList Objects
You can create new SmartList objects that provide access to data for your
integration. Information abuot creating these objects is contained in the following
sections:

• Creating the SmartList object


• SmartList security
• Object name
• Object columns
• Retrieving the table name
• Retrieving column datatypes
• Retrieving column values
• Retrieving list field types
• Retrieving list field values
• Adding a single row to SmartList
• Retrieving records for the SmartList
• Starting the retrieve and display process
• SQL optimization
• Go To items
• Integrating with Report List

Creating the SmartList object


A new SmartList object should be created when the SmartList window is being
opened. At that time, the resources in the SmartList dictionary will be available so
the new object can be added. A focus trigger is typically used to indicate when the
SmartList window is being opened. The trigger processing procedure will define
the new SmartList object.

The following example is a portion of the Startup script for the sample integrating
application. It registers a focus trigger for the ASI_Explorer form which is the main
form for the SmartList. Notice that the trigger is registered by name, since the form
is located in the SmartList dictionary, not the core dictionary.

l_result = Trigger_RegisterFocusByName(SMARTLIST, "form ASI_Explorer",


➥ TRIGGER_FOCUS_PRE, TRIGGER_AFTER_ORIGINAL, script
➥ SmartList_CreateLeadObject);
if l_result <> SY_NOERR then
warning "Focus trigger registration for SmartList failed.";
end if;

The trigger processing procedure that runs in response to this trigger performs
several tasks. It uses the Explorer_Add_Object procedure to define the new
SmartList object. It also adds columns and Go To items to the new object. To
simplify the code, these actions are usually performed in separate procedures.

The following is the trigger processing procedure that creates the Leads SmartList
object for the sample integrating application. Each new SmartList object you create
must have an ID that is unique for your product. This ID will be used throughout
the code for the new SmartList object, so you will want to create a constant for the
ID. For the Leads object, the constant SMARTLIST_OBJECTTYPE_LEADS was
created. The columns and Go To items for the new SmartList object are added in
separate procedures.

INTEGRATION GUIDE 353


PA RT 7 S M A R T L I S T

Procedure name: SmartList_CreateLeadObject


local integer l_error;

{Create the new SmartList object}


call with name "Explorer_Add_Object" in dictionary SMARTLIST,
IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
"Leads",
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
error "Error creating Lead SmartList object";
end if;

{Add columns to the SmartList}


call SmartList_CreateLeadObjectColumns;

{Add the GoTo to the SmartList}


call SmartList_CreateLeadObjectGoto;

SmartList security
Each SmartList object has a corresponding security task operation in Microsoft
Dynamics GP. This allows the administrator to control access to each SmartList.
Consider adding your SmartList to existing security tasks so users assigned to those
tasks can access it. Refer to Chapter 36, “Security,” for more information.

Object name
Add the The name for a SmartList object will appear throughout the SmartList user
Explorer_Get_Object_ interface. The Explorer_Get_Object_Name procedure will be called by the SmartList
Name procedure. each time the object’s name is needed. This procedure should return the name of the
object, including a trailing space at the end.

The following is the Explorer_Get_Object_Name procedure for the sample


integrating application. It returns the name of the new Leads SmartList object
created by the sample.

Procedure name: Explorer_Get_Object_Name

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
inout string IO_Object_Name;

clear IO_Object_Name;
if IN_Object_Dict_ID = IG_PROD_ID then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
IO_Object_Name = "Leads ";
end if;
end if;

Object columns
Use the Explorer_Add_Column_To_Object procedure in the SmartList dictionary
to add the columns to the new SmartList object. When you add a column, you
specify the following:

354 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

• The product and SmartList object to which a column is being added


• The unique ID of the column (typically the field’s resource ID)
• The label to display for the column
• The technical name of the global field used for the column
• Whether the column will appear by default for the object
• The type of data the column will display
• The type of list (used if the field is a list-type field)

The following is a portion of the procedure in the sample integrating application


that defines the columns for the Leads SmartList object.
local integer l_error;
local integer display_sequence,field_sequence;
local string l_message;

{Lead ID}
call with name "Explorer_Add_Column_To_Object" in dictionary SMARTLIST,
IG_PROD_ID, {dictionary}
SMARTLIST_OBJECTTYPE_LEADS, {object}
IG_PROD_ID, {found where}
resourceid(field 'Lead ID'), {field id}
"Lead ID", {display name}
technicalname(field 'Lead ID'), {column name}
true, {Included in the default query}
SMARTLIST_DATATYPE_STRING,
1, {Not a radio group}
false, {Not advanced lookup field}
false, {Not user defined field}
display_sequence,
field_sequence,
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
set l_message to getmsg(22003);
substitute l_message, "Explorer_Add_Column_To_Object", str(l_error);
error l_message;
end if;

{Lead Name}
call with name "Explorer_Add_Column_To_Object" in dictionary SMARTLIST,
IG_PROD_ID, {dictionary}
SMARTLIST_OBJECTTYPE_LEADS, {object}
IG_PROD_ID, {found where}
resourceid(field 'Lead Name'), {field id}
"Lead Name", {display name}
technicalname(field 'Lead Name'), {column name}
true, {Included in the default query}
SMARTLIST_OBJECTTYPE_LEADS,
1, {Not a radio group}
false, {Not advanced lookup field}
false, {Not user defined field}
display_sequence,
field_sequence,
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
set l_message to getmsg(22003);
substitute l_message, "Explorer_Add_Column_To_Object", str(l_error);
error l_message;
end if;

INTEGRATION GUIDE 355


PA RT 7 S M A R T L I S T

Retrieving the table name


Add the When SmartList displays columns for the new object, it must retrieve which table
Explorer_Get_Table_ the field used for the column can be found in. The Explorer_Get_Table_Name
Name procedure. procedure will be called by SmartList to perform this action. In this procedure, you
will return the table technical name for the field used in the columns you added to
the new SmartList object.

The following is the Explorer_Get_Table_Name procedure that retrieves the table


technical name for the columns added to the Leads SmartList object. The fields for
the columns added all come from the IG_Leads_MSTR table.

Procedure name: Explorer_Get_Table_Name

inout string l_Table_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in integer IN_Doc_Status;

if IN_Object_Dict_ID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
l_Table_Name = technicalname(table IG_Leads_MSTR);
end if;
end if;

Retrieving column datatypes


Add the As SmartList works with a SmartList object, it must be told what type of data is
Explorer_Get_Datatype found in each column. The Explorer_Get_Datatype procedure will be called by
procedure. SmartList to perform this action. In this procedure, you will set the datatype for
each column you added to the new SmartList object.

The following is the Explorer_Get_Datatype procedure that retrieves the column


datatypes for the columns added to the Leads SmartList object. Note the else clause
of the case statement. This is necessary so that the “Any Field” search feature of
SmartList works properly.

Procedure name: Explorer_Get_Datatype

inout integer IO_Datatype;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

if IN_Object_Dict_ID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
case IN_Field_ID
in [resourceid(field 'Lead ID')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Lead Name')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Lead Business Category')]
IO_Datatype = SMARTLIST_DATATYPE_DDL;

356 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

in [resourceid(field 'Potential Revenue')]


IO_Datatype = SMARTLIST_DATATYPE_CURRENCY;
in [resourceid(field 'Contact')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 1')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 2')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'City')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'State')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Zip')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Phone 1')]
IO_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Phone 2')]
IO_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Fax')]
IO_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Salesperson ID')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Qualified Lead')]
IO_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Qualification Date')]
IO_Datatype = SMARTLIST_DATATYPE_DATE;
in [resourceid(field 'Lead Source')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
else
{The "Any" field case for searching}
IO_Datatype = SMARTLIST_DATATYPE_ALL;
end case;
end if;
end if;

Retrieving column values


Add the To enable the built-in iterative search capability for SmartList, each column value
Explorer_Get_Field_As must be supplied as a string. This will be required if you choose not to use SQL-
_String_From_Table optimized searching. The Explorer_Get_Field_As_String_From_Table procedure
procedure. will be called by SmartList to retrieve the string values for the columns that are
being searched. This procedure must have the following parameters:

inout string IO_String;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in boolean IN_Searching;
in string IN_Master_ID;
inout integer IO_Datatype;
inout long IO_Long;
inout date IO_Date;
inout currency IO_Currency;
inout time IO_Time;

INTEGRATION GUIDE 357


PA RT 7 S M A R T L I S T

If you were integrating with an existing SmartList object, you would use the
IN_Master_ID parameter which would contain the key information needed to
retrieve the record with fields to display. Because this is a new SmartList object, this
parameter will not be set. Instead, a global variable named SmartList_Master_ID is
used to pass the key information into this procedure. You must add this global
variable to your integrating application. It has the following characteristics:

Global variable name: SmartList_Master_ID


Global field name: SmartList_Master_ID
Datatype name: SmartList_Master_ID
Control type: String
Keyable length: Typically 30

The keyable length for this global variable must be long enough to support the
longest key values you will pass to the procedure to retrieve each row of data for
your SmartList object.

After your code has used the key information from the SmartList_Master_ID global
variable to retrieve the appropriate record from your table, it must set the inout
parameters for the column you added. The value of the IO_String parameter must
be set to the string value you want to be searchable by the SmartList. If necessary,
you can apply formatting to this string. For instance, you could use the format()
function to apply formatting to a currency value.

Your code must set the IO_Datatype parameter, which specifies the underlying
datatype for the column. Then it must set the value of the corresponding parameter
for the datatype. For example, if the column displays a currency value, you will set
the IO_Datatype parameter to SMARTLIST_DATATYPE_CURRENCY and set the
IO_Currency parameter to the actual currency value for the column.

The following is the Explorer_Get_Field_As_String_From_Table procedure from the


sample integrating application. Based on the key value passed in through the
IN_Master_ID parameter, it retrieves the appropriate record from the
IG_Leads_MSTR table. It then sets the IO_String parameter and the appropriate
datatype parameters.

Procedure name: Explorer_Get_Field_As_String_From_Table

inout string IO_String;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in boolean IN_Searching;
in string IN_Master_ID;

inout integer IO_Datatype;


inout long IO_Long;
inout date IO_Date;
inout currency IO_Currency;
inout time IO_Time;

{Handle columns for new SmartList objects that are not SQL-optimized}
if IN_Object_Dict_ID = IG_PROD_ID then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
{Read the record for the row being populated}

358 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

'Lead ID' of table IG_Leads_MSTR = SmartList_Master_ID of globals;


get table IG_Leads_MSTR;
if err() = OKAY then
case IN_Field_ID
in [resourceid(field 'Lead ID')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
IO_String = 'Lead ID' of table IG_Leads_MSTR;
in [resourceid(field 'Lead Name')]
IO_Datatype = SMARTLIST_DATATYPE_STRING;
IO_String = 'Lead Name' of table IG_Leads_MSTR;
in [resourceid(field 'Lead Business Category')]
{Need a "helper" window field to get the category name}
'Lead Business Category' of window Dummy of form
➥ Command_IG_Sample = 'Lead Business Category' of table
➥ IG_Leads_MSTR;
IO_String = itemname('Lead Business Category' of window Dummy
➥ of form Command_IG_Sample, 'Lead Business Category' of table
➥ IG_Leads_MSTR);
IO_Long = 'Lead Business Category' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Potential Revenue')]
IO_String = format('Potential Revenue' of table IG_Leads_MSTR,
➥ true, true, 2, SYSTEMNEG);
IO_Currency = 'Potential Revenue' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_CURRENCY;
in [resourceid(field 'Contact')]
IO_String = 'Contact' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 1')]
IO_String = 'Address 1' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 2')]
IO_String = 'Address 2' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'City')]
IO_String = 'City' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'State')]
IO_String = 'State' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Zip')]
IO_String = 'Zip' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Phone 1')]
IO_String = 'Phone 1' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Phone 2')]
IO_String = 'Phone 2' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Fax')]
IO_String = 'Fax' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Salesperson ID')]
IO_String = 'Salesperson ID' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Qualified Lead')]

INTEGRATION GUIDE 359


PA RT 7 S M A R T L I S T

{Need a "helper" window field to get the qualification status}


'Qualified Lead' of window Dummy of form Command_IG_Sample =
➥ 'Qualified Lead' of table IG_Leads_MSTR;
IO_String = itemname('Qualified Lead' of window Dummy of form
➥ Command_IG_Sample, 'Qualified Lead' of table
➥ IG_Leads_MSTR);
IO_Long = 'Qualified Lead' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Qualification Date')]
IO_String = str('Qualification Date' of table IG_Leads_MSTR);
IO_Date = 'Qualification Date' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_DATE;
in [resourceid(field 'Lead Source')]
IO_String = 'Lead Source' of table IG_Leads_MSTR;
IO_Datatype = SMARTLIST_DATATYPE_STRING;
end case;
end if;
end if;
end if;

Retrieving list field types


Add the Most list fields are 1-based and number the items in the list 1, 2, 3, and so on. The
Explorer_Get_DDL_ exception is radio groups, which are 0-based and number the items 0, 1, 2, and so
Type procedure. on. If you are adding a list field as a column to a SmartList, you must use the
Explorer_Get_DDL_Type procedure to tell SmartList how the items in the list field
are numbered. The value 1 indicates a 1-based list field, while the value 0 indicates a
0-based list field.

The following is the Explorer_Get_DDL_Type procedure for the sample integrating


application. All of the list fields from the sample that are used for SmartList
columns are 1-based, so the value 1 is returned.

Procedure name: Explorer_Get_DDL_Type

out integer OUT_DDL_Type;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

{All of the drop-down lists in the sample are 1-based}


if IN_Object_Dict_ID = IG_PROD_ID then
OUT_DDL_Type = 1;
end if;

Retrieving list field values


Add the To make it easier for the user to create SmartList search criteria, the items for list
Explorer_Fill_Range_ field columns are displayed in the Search window. For instance, the following
DDLs_From_Field_ID illustration shows the choices displayed for the Qualified list column.
procedure.

360 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

You will add the Explorer_Fill_Range_DDLs_From_Field_ID procedure to your


application to retrieve the the values for the list columns you have added. This
procedure must have the following parameters:

in integer IN_Object_DictID;
in integer IN_Object_Type;
in integer IN_FieldDictID;
in integer IN_FieldID;
inout anonymous field IO_From_DDL;
inout anonymous field IO_To_DDL;

The IO_From_DDL and IO_To_DDL parameters contain references to the two drop-
down lists that appear in the Search window. Your code must fill these drop-down
lists with the values for the list field of the column the user selected. List fields must
be window fields to have their static values read by sanScript code. You will need to
place an instance of the list field on a hidden window so its static values can be
accessed. A hidden window on a command form is a good place to add the hidden
list field.

The following is the Explorer_Fill_Range_DDLs_From_Field_ID procedure for the


sample integrating application. When the Qualified column is searched, it sets the
static values for the drop-down lists that are displayed in the Search window.
Notice that it references an instance of the Qualified Lead list field on a hidden
window so that the static items can be retrieved.

Procedure name: Explorer_Fill_Range_DDLs_From_Field_ID

in integer IN_Object_DictID;
in integer IN_Object_Type;
in integer IN_FieldDictID;
in integer IN_FieldID;
inout anonymous field IO_From_DDL;
inout anonymous field IO_To_DDL;

local integer i;

if IN_Object_DictID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
if IN_FieldID = resourceid(field 'Qualified Lead') then
{Clear the drop-down lists before filling them}
clear field IO_From_DDL;
clear field IO_To_DDL;

for i = 1 to countitems('Qualified Lead' of window Dummy of form


➥ Command_IG_Sample) do
add item itemname('Qualified Lead' of window Dummy of form
➥ Command_IG_Sample, i) to field IO_From_DDL;
add item itemname('Qualified Lead' of window Dummy of form
➥ Command_IG_Sample, i) to field IO_To_DDL;
end for;
end if;
end if;
end if;

INTEGRATION GUIDE 361


PA RT 7 S M A R T L I S T

Adding a single row to SmartList


You will add a procedure to your integrating dictionary that will add a single row to
the SmartList for the new SmartList object you are creating. This procedure will use
the Explorer_AddItem_To_ListView procedure to add the item to the list view. The
procedure will have an array of the fields that should be added as columns for the
list view. You will use the Explorer_Add_SubItem_To_ListView procedure to add
the additional columns selected by the user.

This procedure is directly adding items to the list view that the user will see, any formatting
to apply (such as currency formatting) must be done in this procedure.

As an example, the following is the SmartList_Leads_FillOneRowAtTime procedure


that is defined for the sample integrating application. It is called by several other
procedures to add individual rows for the Leads SmartList object.

Procedure name: SmartList_Leads_FillOneRowAtTime

in integer IN_Total_SubItems;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in long IN_Record_Count;
inout table IG_Leads_MSTR;

local long n;
local integer l_Count;
local string l_Field_As_String;
local long l_Field_As_Integer;
local date l_Field_As_Date;
local currency l_Field_As_Currency;
local time l_Field_As_Time;
local integer l_Datatype;
local boolean b_Success;

call with name "Explorer_AddItem_To_ListView" in dictionary SMARTLIST,


'Lead ID' of table IG_Leads_MSTR,
IN_Record_Count,
"Leads",
n;

set l_Count to 1;

while (l_Count <= IN_Total_SubItems) do


case IN_Field_List[l_Count]
in [resourceid(field 'Lead ID')]
l_Field_As_String = 'Lead ID' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Lead Name')]
l_Field_As_String = 'Lead Name' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Lead Business Category')]
{Need a "helper" window field to get the category name}
'Lead Business Category' of window Dummy of form Command_IG_Sample
➥ = 'Lead Business Category' of table IG_Leads_MSTR;
l_Field_As_String = itemname('Lead Business Category' of window
➥ Dummy of form Command_IG_Sample, 'Lead Business Category' of

362 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

➥ table IG_Leads_MSTR);
l_Field_As_Integer = 'Lead Business Category' of table
➥ IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Potential Revenue')]
l_Field_As_String = format('Potential Revenue' of table
➥ IG_Leads_MSTR, true, true, 2, SYSTEMNEG);
l_Field_As_Currency = 'Potential Revenue' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_CURRENCY;
in [resourceid(field 'Contact')]
l_Field_As_String = 'Contact' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 1')]
l_Field_As_String = 'Address 1' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 2')]
l_Field_As_String = 'Address 2' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'City')]
l_Field_As_String = 'City' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'State')]
l_Field_As_String = 'State' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Zip')]
l_Field_As_String = 'Zip' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Phone 1')]
l_Field_As_String = FormatPhoneNumber('Phone 1' of table
➥ IG_Leads_MSTR);
l_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Phone 2')]
l_Field_As_String = FormatPhoneNumber('Phone 2' of table
➥ IG_Leads_MSTR);
l_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Fax')]
l_Field_As_String = FormatPhoneNumber('Fax' of table
➥ IG_Leads_MSTR);
l_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Salesperson ID')]
l_Field_As_String = 'Salesperson ID' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Qualified Lead')]
{Need a "helper" window field to get the qualification status}
'Qualified Lead' of window Dummy of form Command_IG_Sample =
➥ 'Qualified Lead' of table IG_Leads_MSTR;
l_Field_As_String = itemname('Qualified Lead' of window Dummy of
➥ form Command_IG_Sample, 'Qualified Lead' of table
➥ IG_Leads_MSTR);
l_Field_As_Integer = 'Qualified Lead' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Qualification Date')]
l_Field_As_String = str('Qualification Date' of table
➥ IG_Leads_MSTR);
l_Field_As_Date = 'Qualification Date' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_DATE;

INTEGRATION GUIDE 363


PA RT 7 S M A R T L I S T

in [resourceid(field 'Lead Source')]


l_Field_As_String = 'Lead Source' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
end case;

call with name "Explorer_AddSubItem_To_ListView" in dictionary SMARTLIST,


n,
l_Count,
l_Field_As_String,
l_Field_As_Integer,
l_Field_As_Date,
l_Field_As_Currency,
l_Field_As_Time,
l_Datatype,
b_Success;

increment l_Count;
end while;

Retrieving records for the SmartList


Another procedure for your integration will manually retrieve the records that will
be displayed for the new SmartList object. This procedure will be used when all
records for the object type are to be displayed, and no search criteria has been
specified. It will also be used when search criteria have been supplied, but you have
chosen not to use the SQL-optimized search built into SmartList.

This procedure sets the SmartList_Master_ID global variable that was described in
Retrieving column values on page 357.

This procedure will also be called when the SmartList object is used with a reminder
in Microsoft Dynamics GP. When you create a SmartList favorite, it can also be
saved as a reminder that appears on the home page. When used for a reminder, a
summary containing the total number of records, or the total of the values of a
specific column is returned from the procedure. When the summary is being
generated, the user stop action and the maximum number of records setting for the
SmartList query are ignored. This ensures that all records in the table are examined
for the summary.

As an example, the following is the SmartList_GetLeadRecords procedure that is


defined for the sample integrating application. It is called by the
Explorer_Get_Records_Background procedure to add Leads items to the SmartList.

Procedure name: SmartList_GetLeadRecords

in integer IN_Total_SubItems;
in Explorer_BOOL_List IN_Searching;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
in Explorer_INT_List IN_Datatype;
in Explorer_INT_List IN_Type;
in Explorer_STR30_List IN_Search_From;
in Explorer_STR30_List IN_Search_To;
in Explorer_BOOL_List IN_Match_Case;

364 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

in integer IN_Global_Search_Type;
in Explorer_Field_Comparison IN_Field_Comparison;
in Explorer_Start_Comp_Field_ID IN_Start_Comp_Field_ID;
in Explorer_Start_Comp_Field_Dict IN_Start_Comp_Field_Dict;
in Explorer_End_Comp_Field_ID IN_End_Comp_Field_ID;
in Explorer_End_Comp_Field_Dict IN_End_Comp_Field_Dict;

inout long IO_Max_Records;

in boolean IN_GetSummary;
in integer IN_Summary_Type; {0 = Number of records, 1 = Total of Column}
inout long IO_SummaryCount;
in integer IN_nSummaryFieldDictID;
in integer IN_nSummaryFieldID;
inout currency IO_ColumnTotal;

local boolean b_Stop, b_Found;


local long l_Record_Count,SQL_Context;
local integer l_Key,Error;

local currency IO_Currency;


local string IO_String;
local integer IO_Datatype;
local long IO_Long;
local date IO_Date;
local time IO_Time;

{This block of code will be run only if the Explorer_Optimize_For_SQL


procedure returns false}
if 'SQL Server' of globals > 0 and (IN_Searching[1] or IN_Searching[2] or
➥ IN_Searching[3] or IN_Searching[4]) then
call with name "Explorer_SQL_Search_Generic" in dictionary SMARTLIST,
IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
IN_Searching,
IN_Field_Dict_ID,
IN_Field,
IN_Datatype,
IN_Type,
IN_Search_From,
IN_Search_To,
IN_Match_Case,
IN_Field_Comparison,
IN_Start_Comp_Field_ID,
IN_Start_Comp_Field_Dict,
IN_End_Comp_Field_ID,
IN_End_Comp_Field_Dict,
IN_Global_Search_Type,
SQL_Context,
Error,
IN_GetSummary,
IN_Summary_Type,
IO_SummaryCount,
IN_nSummaryFieldDictID,
IN_nSummaryFieldID,
IO_ColumnTotal;

INTEGRATION GUIDE 365


PA RT 7 S M A R T L I S T

{If Error returns -1, then a sequential search should be used}


if Error = OKAY then
call Explorer_Process_SQL_Data, IG_PROD_ID,
➥ SMARTLIST_OBJECTTYPE_LEADS, IN_Total_SubItems, IN_Dict_List,
➥ IN_Field_List, IO_Max_Records, SQL_Context;
abort script;
end if;
end if;

{This is the traditional SmartList code that works for all database types}

set l_Record_Count to 0;
set l_Key to 1;
call with name "Explorer_Check_Stop_Processing" in dictionary SMARTLIST,
➥ b_Stop;

{ Loop through table to get records }


get first table IG_Leads_MSTR by number l_Key;
while err() <> EOF do

{Check for additional exit criteria when a standard request is performed.}


{These checks are not done when a summary is being performed.}
if IN_GetSummary = false then

{ Was the maximum number of records exceeded? }


if l_Record_Count >= IO_Max_Records then
exit while;
end if;

{ Was Stop chosen? }


if b_Stop = true then
exit while;
end if;
end if;

{Set the global SmartList Master ID}


SmartList_Master_ID of globals = 'Lead ID' of table IG_Leads_MSTR;

call with name "Explorer_Search_Generic" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
IN_Searching,
IN_Field_Dict_ID,
IN_Field,
IN_Datatype,
IN_Type,
IN_Search_From,
IN_Search_To,
IN_Match_Case,
IN_Global_Search_Type,

IN_Field_Comparison,
IN_Start_Comp_Field_ID,
IN_Start_Comp_Field_Dict,
IN_End_Comp_Field_ID,
IN_End_Comp_Field_Dict,
b_Found;

366 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

if b_Found then
increment l_Record_Count;

{ Is a summary being requested? }


if IN_GetSummary = false then
{ No summary is being requested }
call foreground SmartList_Leads_FillOneRowAtTime,
IN_Total_SubItems,
IN_Dict_List,
IN_Field_List,
l_Record_Count,
table IG_Leads_MSTR;
else
{ A summary is being requested. Return data based on the summary
type requested. }
if IN_Summary_Type = 0 then
{ Total number of records is requested }
increment IO_SummaryCount;
end if;

if IN_Summary_Type = 1 then
{ A total is being requested for the specified field }
clear IO_Currency;

call Explorer_Get_Field_As_String_From_Table,
IO_String,
IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
IN_nSummaryFieldDictID,
IN_nSummaryFieldID,
(IN_Searching[1] or IN_Searching[2] or IN_Searching[3] or
➥ IN_Searching[4]),
'Lead ID' of table IG_Leads_MSTR,
IO_Datatype,
IO_Long,
IO_Date,
IO_Currency,
IO_Time;

{ Increase the total by the returned currency amount }


IO_ColumnTotal = IO_ColumnTotal + IO_Currency;
end if;
end if;
end if;

get next table IG_Leads_MSTR by number l_Key;


call with name "Explorer_Check_Stop_Processing" in dictionary SMARTLIST,
➥ b_Stop;
end while;

INTEGRATION GUIDE 367


PA RT 7 S M A R T L I S T

Starting the retrieve and display process


Retrieving and displaying records for a SmartList object requires multiple
procedures to be called. Which procedures are called depend on the following
factors:

• Whether all of the records for the SmartList object are being displayed, or search
criteria are specified so that only certain records are displayed.

• Whether the SmartList object is optimized for SQL Server.

The Explorer_Get_Records_Background procedure is called by SmartList to start


the process of displaying records when no search criteria have been specified by the
user. This procedure is also called when search criteria have been supplied, but SQL
optimization has not been implemented for the SmartList object.

The following is the Explorer_Get_Records_Background procedure that is defined


for the sample integrating application. It is called by the SmartList to begin adding
records to the SmartList window.

Procedure name: Explorer_Get_Records_Background


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
in Explorer_INT_List IN_Type;
in Explorer_STR30_List IN_Search_From;
in Explorer_STR30_List IN_Search_To;
in Explorer_BOOL_List IN_Match_Case;
in integer IN_Global_Search_Type;
in integer IN_Total_Sub_Items;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in Explorer_Field_Comparison IN_Field_Comparison;
in Explorer_Start_Comp_Field_ID IN_Start_Comp_Field_ID;
in Explorer_Start_Comp_Field_Dict IN_Start_Comp_Field_Dict;
in Explorer_End_Comp_Field_ID IN_End_Comp_Field_ID;
in Explorer_End_Comp_Field_Dict IN_End_Comp_Field_Dict;
in Explorer_Start_Date_Token_DDL IN_Date_Token_From;
in Explorer_End_Date_Token_DDL IN_Date_Token_To;
inout long IO_Max_Records;

in boolean IN_GetSummary;
in integer IN_SummaryType; {0 = Number of records, 1 = Total of Column}
inout long IO_nSummaryCount;
in integer IN_nSummaryFieldDictID;
in integer IN_nSummaryFieldID;
inout currency IO_cyColumnTotal;

local integer i;
local Explorer_BOOL_List l_Searching;
local Explorer_INT_List l_Datatype;

368 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

if IN_Object_Dict_ID=IG_PROD_ID and IN_Object_Type=SMARTLIST_OBJECTTYPE_LEADS


➥ then
{Fill the list of Leads}
for i = 1 to 4 do
if empty(IN_Field[i]) then
set l_Searching[i] to false;
clear l_Datatype[i];
else
set l_Searching[i] to true;
call Explorer_Get_Datatype,
l_Datatype[i],
IN_Object_Dict_ID,
IN_Object_Type,
IN_Field_Dict_ID[i],
IN_Field[i];
end if;
end for;

call SmartList_GetLeadRecords,
IN_Total_Sub_Items,
l_Searching,
IN_Dict_List,
IN_Field_List,
IN_Field_Dict_ID,
IN_Field,
l_Datatype,
IN_Type,
IN_Search_From,
IN_Search_To,
IN_Match_Case,
IN_Global_Search_Type,
IN_Field_Comparison,
IN_Start_Comp_Field_ID,
IN_Start_Comp_Field_Dict,
IN_End_Comp_Field_ID,
IN_End_Comp_Field_Dict,
IO_Max_Records,
IN_GetSummary,
IN_SummaryType,
IO_nSummaryCount,
IN_nSummaryFieldDictID,
IN_nSummaryFieldID,
IO_cyColumnTotal;
end if;

If SQL optimization has been implemented for the SmartList object and the user has
specified search criteria, the Explorer_Process_SQL_Data procedure will be called
instead. The SmartList will have generated a SQL results set that contains the key
values of the records that match the search criteria. This results set is passed into the
Explorer_Process_SQL_Data procedure, where the current row will be retrieved
and displayed in the SmartList.

INTEGRATION GUIDE 369


PA RT 7 S M A R T L I S T

The following is the Explorer_Process_SQL_Data procedure that is defined for the


sample integrating application. It is called by the SmartList to add records to the
SmartList window when search criteria have been specified for a SQL-optimized
SmartList object. Note how it retrieves the current item from the SQL results set
passed in to display the record.

Procedure name: Explorer_Process_SQL_Data

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Total_SubItems;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in long IN_Record_Count;
inout long SQL_Context;

local long status;


local string data_value;

if IN_Object_Dict_ID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
{Display the current item in the results set. SmartList will move to
➥ the next item automatically.}
status = SQL_GetData(SQL_Context, 1, data_value);

{Read the record based on the key retrieved.}


'Lead ID' of table IG_Leads_MSTR = data_value;
get table IG_Leads_MSTR;

{Call the routine to display the record}


call SmartList_Leads_FillOneRowAtTime, IN_Total_SubItems,
➥ IN_Dict_List, IN_Field_List, IN_Record_Count, table IG_Leads_MSTR;
end if;
end if;

SQL optimization
SmartList can perform optimized searches when used with SQL Server. To take
advantage of this optimization, you must indicate that your new SmartList object is
optimized for SQL, and provide several additional procedures that will be used by
SmartList when it searches the data for the new object.

Since SQL Server is supported for all products, we recommend that you make your new
SmartList objects optimized for SQL Server.

Indicating optimized objects


The Explorer_Optimize_For_SQL procedure is used to indicate that a specific
SmartList object is optimized for SQL. This procedure should return the value true
if the object is optimized, and false if it is not. When true is specified, SmartList will
call additional procedures that are needed for implementing SQL-optimized
searches.

370 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

The following is the Explorer_Optimize_For_SQL procedure from the sample


integrating application. The sample defines the new Leads SmartList object. It
provides the additional procedures needed to support SQL optimization, so it
returns the value true when asked about whether the Leads SmartList object is
optimized.

Procedure name: Explorer_Optimize_For_SQL

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field;
inout boolean IO_Optimize;

{By default, assume not optimized}


IO_Optimize = false;

{Leads SmartList object is optimized}


if IN_Object_Dict_ID = IG_PROD_ID then
if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
IO_Optimize = true;
end if;
end if;

Retrieving SQL field information


Add the To allow searching based on the columns you add to a SQL-optimized object, you
Explorer_Get_SQL_ must add the Explorer_Get_SQL_Field_Info procedure to your application. This
Field_Info procedure. procedure returns the following for each column:

• Table technical name of the table that stores the data for the column
• ID of the dictionary containing the table that stores the data for the column
• Type of list field used for the column (if applicable)

This information is used when generating the SQL query used to search for
matching records.

The following is the Explorer_Get_SQL_Field_Info procedure from the sample


integrating application. For the Leads SmartList object defined by the sample, all of
the fields for the columns come from the IG_Leads_MSTR table.

Procedure name: Explorer_Get_SQL_Field_Info


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field;
inout string IO_Table_Name;
inout integer IO_Table_Dict_ID;
inout integer IO_DDL_Type;

if IN_Object_Dict_ID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
IO_Table_Name = technicalname(table IG_Leads_MSTR);
IO_Table_Dict_ID = IG_PROD_ID;
IO_DDL_Type = 1;
end if;
end if;

INTEGRATION GUIDE 371


PA RT 7 S M A R T L I S T

Setting SQL join information


Add the For SmartList objects optimized for SQL Server, it’s necessary to describe how any
Explorer_Get_SQL_ additional tables used for columns are related to the main table for the SmartList
Join_Info procedure. object. You will add the Explorer_Get_SQL_Join_Info procedure to your application
to do this. In this procedure you will call the Explorer_Set_SQL_Join_Info
procedure in the SmartList dictionary to define the join that describes how the main
table for the SmartList object is related to any additional tables that contains data for
the columns you’ve added. You will call this procedure once for each field that is
part of the join.

Several types of joins are supported, but virtually all joins needed for SmartList are left-
outer joins.

The following is the Explorer_Get_SQL_Join_Info procedure from the sample


integrating application. In the sample, the main table for this object is the
IG_Leads_MSTR table, and there are no additional tables used. The procedure
creates an empty join to indicate no other tables are used.

Procedure name: Explorer_Get_SQL_Join_Info

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
inout integer l_Doc_Status;

local string l_From_Table, l_From_Field, l_To_Table, l_To_Field;


local integer l_From_Table_Dict_ID, l_To_Table_Dict_ID, l_Join_Type,
➥ l_Exp_Error;

if IN_Object_Dict_ID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
l_From_Table = technicalname(table IG_Leads_MSTR);
l_From_Table_Dict_ID = IG_PROD_ID;
l_From_Field = "";
l_To_Table = "";
l_To_Table_Dict_ID = 0;
l_To_Field = "";
l_Join_Type = 0;

call with name "Explorer_Set_SQL_Join_Info" in dictionary SMARTLIST,


l_From_Table,
l_From_Table_Dict_ID,
l_From_Field,
l_To_Table,
l_To_Table_Dict_ID,
l_To_Field,
l_Join_Type,
l_Exp_Error;
end if;
end if;

372 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

Retrieving SQL query fields


Add the When SmartList retrieves search results for a SQL-optimized object, it must be told
Explorer_Get_SQL_ which fields are the key fields that uniquely identify each row in the results. These
Query_Fields fields will be included in the results set used to display the records that match the
procedure. search criteria. You will add the Explorer_Get_SQL_Query_Fields procedure to
your application to specify which fields to include in the key for your new
SmartList object. The Explorer_Set_SQL_Query_Field procedure in the SmartList
dictionary is used to specify each key field.

The following is the Explorer_Get_SQL_Query_Fields procedure for the sample


integrating application. The sample defines the Leads SmartList object, which is
optimized for SQL Server. The Lead ID field uniquely identifies each lead record, so
this procedure specifies that the Lead ID will be included in the results set
generated by the SmartList search.

Procedure name: Explorer_Get_SQL_Query_Fields

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;

local integer l_Exp_Error, l_Dict, l_Sequence;


local string l_Table, l_Field;

if IN_Object_Dict_ID = IG_PROD_ID then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_LEADS then
l_Table = technicalname(table IG_Leads_MSTR);
l_Dict = IG_PROD_ID;
l_Field = technicalname(field 'Lead ID');
call with name "Explorer_Set_SQL_Query_Field" in dictionary SMARTLIST,
l_Sequence,
l_Table,
l_Dict,
l_Field,
l_Exp_Error;
end if;
end if;

Overriding field names


Add the In special cases, the name used for a field will change depending upon the type of
Explorer_Get_SQL_ document the field is contained in. For example, this issue occurrs for inventory
Override_Field_Name transactions. If the inventory document being displayed in SmartList comes from
procedure. the “work” table, the document number field is named IV Document Number.
However, if the document comes from the “history” table, the document
number field is named Document Number. You will add the
Explorer_Get_SQL_Override_Field_Name procedure to your application to handle
these special cases. This procedure must return the appropriate field name to use,
based on the document type.

If you don’t have field names that change based on the document type, this
procedure should return the empty string. This causes the original field name to be
used.

INTEGRATION GUIDE 373


PA RT 7 S M A R T L I S T

The following is the Explorer_Get_SQL_Override_Field_Name procedure for the


sample integrating application. There are no field names that change based on the
document type, so an empty string is returned for the field name.

Procedure name: Explorer_Get_SQL_Override_Field_Name

out string OUT_Field_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_Number;
in integer IN_Doc_Type;

clear OUT_Field_Name;

Go To items
Go To items in SmartList provide quick navigation to the windows in the
accounting system that allow you to view of modify the selected item. You can add
additional Go To items to new SmartList objects you create.

Adding Go To items
Use the Explorer_Add_GoTo_Item procedure in the SmartList dictionary to add
the Go To items. When you add a Go To item, you specify the following:

• The product and SmartList object to which a Go To item is being added


• The text to display for the Go To item (use a dash for a separator item)
• The dictionary ID of the product that contains the Go To processing code
• The unique ID of the Go To item
• Whether the Go To item will be the default action for the SmartList object

The following procedure from the sample integrating application that adds the Go
To items for the Leads SmartList object created by the sample. Notice how the
separator item is added to the list.

Procedure name: SmartList_CreateLeadObjectGoto

local integer l_error;


local string l_message;

call with name "Explorer_Add_GoTo_Item" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
"View",
IG_PROD_ID,
resourceid(form IG_Lead_Maintenance), {Unique ID for this form}
true, {Will be the default Go To item}
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
set l_message to getmsg(22002);
substitute l_message, "Explorer_Add_GoTo_Item", str(l_error);
error l_message;
end if;

374 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

call with name "Explorer_Add_GoTo_Item" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
"-",
IG_PROD_ID,
1, {Unique ID for this form}
false, {Will not be the default Go To item}
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
set l_message to getmsg(22002);
substitute l_message, "Explorer_Add_GoTo_Item", str(l_error);
error l_message;
end if;

call with name "Explorer_Add_GoTo_Item" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
"Lead Inquiry",
IG_PROD_ID,
resourceid(form IG_Lead_Inquiry), {Unique ID for this form}
false, {Will not be the default Go To item}
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
set l_message to getmsg(22002);
substitute l_message, "Explorer_Add_GoTo_Item", str(l_error);
error l_message;
end if;

Processing Go To items
Add the The Go To items you add must be processed by the procedure named
Explorer_GoTo_Button Explorer_GoTo_Button that you will add to your dictionary. This procedure must
procedure. have the following parameters:

inout anonymous field IN_ListView;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_GoTo_Dict_ID;
in integer IN_GoTo_Item;

The procedure will examine the values passed into these parameters to determine
whether it must process the Go To item. If it should, the list view field for the Smart
List is passed in as an anonymous field. This allows the code to find the currently-
selected line and perform the specified action for that item.

The following is the Explorer_GoTo_Button procedure for the sample integrating


application. If the user chooses one of the Go To items for the Leads SmartList, this
code will find and display the first selected lead.

Procedure name: Explorer_GoTo_Button

inout anonymous field IN_ListView;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_GoTo_Dict_ID;
in integer IN_GoTo_Item;

INTEGRATION GUIDE 375


PA RT 7 S M A R T L I S T

local long selected_item;


local string LeadID;

if IN_Object_Dict_ID = IG_PROD_ID then


{Is it the Lead Maintenance form?}
if (IN_GoTo_Dict_ID = IG_PROD_ID) and (IN_GoTo_Item = resourceid(form
➥ IG_Lead_Maintenance)) then
{Try to find the first Lead selected in the list}
selected_item = ListView_SelectionGet(IN_ListView, 1);
if selected_item <> 0 then
LeadID = ListView_ItemGetLabel(IN_ListView, selected_item);
open form IG_Lead_Maintenance;
'Lead ID' of window 'Lead Maintenance' of form IG_Lead_Maintenance
➥ = LeadID;
run script 'Lead ID' of window 'Lead Maintenance' of form
➥ IG_Lead_Maintenance;
end if;
end if;

{Is it the Lead Inquiry form?}


if (IN_GoTo_Dict_ID = IG_PROD_ID) and (IN_GoTo_Item = resourceid(form
➥ IG_Lead_Inquiry)) then
{Try to find the first Lead selected in the list}
selected_item = ListView_SelectionGet(IN_ListView, 1);
if selected_item <> 0 then
LeadID = ListView_ItemGetLabel(IN_ListView, selected_item);
open form IG_Lead_Inquiry;
'Lead ID' of window 'IG_Lead_Inquiry' of form IG_Lead_Inquiry =
➥ LeadID;
run script 'Lead ID' of window IG_Lead_Inquiry of form
➥ IG_Lead_Inquiry;
end if;
end if;
end if;

Integrating with Report List


SmartList favorites can be included in the Report List. If you create a new SmartList
object, consider making the favorites for that object available in the Report List. You
will do this in the code that adds reports to a Report List. Refer to Chapter 31,
“Report Lists,” for more information about adding to a Report List.

For example, the following code is part of the procedure that adds to the Report List
for the sample integrating application. This code makes favorites for the new Leads
SmartList object available in the Report List.
{SmartList Favorite}
clear field RptData;
RptData:'Report Type' = REPORTTYPE_SMARTLISTFAVORITE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = IG_PROD_ID;
RptData:'Report Series ID' = 1;
RptData:'Report ID' = SMARTLIST_OBJECTTYPE_LEADS;
RptData:'Report Option Name' = "";
RptData:'VisibleTo' = SMARTLIST_VISIBLETO_SYSTEM;

status = AddReport(RptData) of form syReportList;

376 IN T E G R AT I O N G U ID E
C H A P T E R 3 4 C R E A T I N G N EW S M A R TL I S T O B J E C T S

By default, SmartList objects you create will be listed with the “3rd Party” series
assigned to them. To have the SmartList items assigned to a different series, you
must create a procedure trigger for the GetSmartListObjectSeries procedure of the
syReportList form. The following example shows this trigger from the sample
integrating application.

l_result = Trigger_RegisterProcedure(script GetSmartListObjectSeries of form


➥ syReportList, TRIGGER_AFTER_ORIGINAL, script SmartList_GetObjectSeries);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The trigger processing procedure examines which SmartList object is being added
to the Report List. If it’s the Leads object, the series is set to “Sales”.

in DictID nObjectDictID;
in 'Report ID' nObjectID;
inout 'Report Series DictID' nSeriesDictID;
inout 'Report Series ID' nSeriesID;
inout 'Series Name' sSeriesName;

if nObjectDictID = IG_PROD_ID then


if nObjectID = SMARTLIST_OBJECTTYPE_LEADS then
sSeriesName = "Sales";
end if;
end if;

INTEGRATION GUIDE 377


378 IN T E G R AT I O N G U ID E
Chapter 35: SmartList Procedure Reference
When creating a SmartList integration, you will add several procedures to your
dictionary that are called automatically by the SmartList code. This portion of the
documentation describes these procedures.

• Explorer_Fill_Range_DDLs_From_Field_ID
• Explorer_Get_Datatype
• Explorer_Get_DDL_Type
• Explorer_Get_Field_As_String_From_Table
• Explorer_Get_Object_Name
• Explorer_Get_Records_Background
• Explorer_Get_SQL_Field_Info
• Explorer_Get_SQL_Join_Info
• Explorer_Get_SQL_Override_Field_Name
• Explorer_Get_SQL_Query_Fields
• Explorer_Get_Table_Name
• Explorer_Get_User_Defined_Prompt
• Explorer_GoTo_Button
• Explorer_Optimize_For_SQL
• Explorer_Process_SQL_Data

Explorer_Fill_Range_DDLs_From_Field_ID
This procedure is called to retrieve all of the valid selections in a list field. The
values are used in the Search window for SmartList.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_FieldID;
inout anonymous field IO_From_DDL;
inout anonymous field IO_To_DDL;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which list values are being retrieved.

IN_FieldID – An integer specifying the resource ID of the field for which list values
are being retrieved.

IO_From_DDL – An anonymous reference to a drop-down list field in to which the


list items from the specified field should be added.

IO_To_DDL – An anonymous reference to a drop-down list field in to which the list


items from the specified field should be added.

INTEGRATION GUIDE 379


PA RT 7 S M A R T L I S T

Explorer_Get_Datatype
This procedure is called by SmartList whenever it must determine the datatype for a
column or field. Based on the parameter values passed in, the procedure must
return the datatype for specified column or field.

The procedure must have the following parameters:

inout integer IO_Datatype;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

IO_Datatype – An integer that must be set by the procedure to indicate the datatype
of the specified column or field. The value corresponds to one of the following:

Datatype Constant Value


Integer SMARTLIST_DATATYPE_INTEGER 1
Long integer SMARTLIST_DATATYPE_LONG 2
Date SMARTLIST_DATATYPE_DATE 3
Currency SMARTLIST_DATATYPE_CURRENCY 4
String SMARTLIST_DATATYPE_STRING 5
Boolean SMARTLIST_DATATYPE_BOOLEAN 6
Drop-down list SMARTLIST_DATATYPE_DDL 7
Account index SMARTLIST_DATATYPE_ACCOUNTINDEX 8
Account number SMARTLIST_DATATYPE_ACCOUNTNUMBER 9
Phone number SMARTLIST_DATATYPE_PHONENUMBER 10
Social Security number SMARTLIST_DATATYPE_SSN 11
Time SMARTLIST_DATATYPE_TIME 12

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which the datatype is being retrieved.

IN_Field_ID – An integer specifying the resource ID of the field for which the
datatype is being retrieved.

380 IN T E G R AT I O N G U ID E
C H A P T E R 3 5 S M A R T LI S T P R O C E D U R E R E FE R E N C E

Explorer_Get_DDL_Type
This procedure is called for list columns added to a SmartList object. If the list field
for the column is 0-based (radio groups) the value 0 should be returned. If the list
field for the column is 1-based (all other types of list fields) the value 1 should be
returned.

The procedure must have the following parameters:

out integer OUT_DDL_Type;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

OUT_DDL_Type – An integer that must be set by the procedure to indicate the type
of list field for the field. The value 0 indicates a 0-based list, while the value 1
indicates a 1-based list.

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which the list type is being retrieved.

IN_Field_ID – An integer specifying the resource ID of the field for which the list
type is being retrieved.

Explorer_Get_Field_As_String_From_Table
This procedure returns the string representation and the underlying data in the
native datatype for a column. It is used when displaying data for additional
columns added to core SmartList objects. It is also used in the iterative fallback
searching code for SmartList objects that are not SQL-optimized.

The procedure must have the following parameters:

inout string IO_String;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in boolean IN_Searching;
in string IN_Master_ID;
inout integer IO_Datatype;
inout long IO_Long;
inout date IO_Date;
inout currency IO_Currency;
inout time IO_Time;

INTEGRATION GUIDE 381


PA RT 7 S M A R T L I S T

IO_String – A string that must be set by the procedure to indicate the string
representation of the data in the specified field or column.

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which the string representation is being retrieved.

IN_Field_ID – An integer specifying the resource ID of the field for which the string
representation is being retrieved.

IN_Searching – A boolean that indicates whether SmartList is calling this procedure


as part of a search. The value true indicates SmartList is searching, while false
indicates it is not. The string representation of a field may need to be different when
a search is being performed.

IN_Master_ID – When additional columns are being added to a core SmartList


object, this string field will contain the primary key values for the main table used
for the SmartList object. Refer to SmartList objects on page 332 for a list of the
primary tables that correspond to the SmartList object types. The field values
passed in though the IN_Master_ID parameter will be padded with spaces to each
field’s specified length. For example, a field with the STR30 datatype will be
padded to a length of 30. Your code must parse the string into the individual field
values. Use the key values to retrieve the corresponding record that contains the
additional columns you want to display.

IO_Datatype – An integer that must be set by the procedure that specifies the field or
column’s underlying datatype. The value corresponds to one of the following:

Datatype Constant Value


Integer SMARTLIST_DATATYPE_INTEGER 1
Long integer SMARTLIST_DATATYPE_LONG 2
Date SMARTLIST_DATATYPE_DATE 3
Currency SMARTLIST_DATATYPE_CURRENCY 4
String SMARTLIST_DATATYPE_STRING 5
Boolean SMARTLIST_DATATYPE_BOOLEAN 6
Drop-down list SMARTLIST_DATATYPE_DDL 7
Account index SMARTLIST_DATATYPE_ACCOUNTINDEX 8
Account number SMARTLIST_DATATYPE_ACCOUNTNUMBER 9
Phone number SMARTLIST_DATATYPE_PHONENUMBER 10
Social Security number SMARTLIST_DATATYPE_SSN 11
Time SMARTLIST_DATATYPE_TIME 12

IO_Long – If the underlying datatype of the column is an integer or long integer, the
procedure should set this parameter to the field’s native integer or long integer
value.

IO_Date – If the underlying datatype of the column is a date, the procedure should
set this parameter to the field’s native date value.

382 IN T E G R AT I O N G U ID E
C H A P T E R 3 5 S M A R T LI S T P R O C E D U R E R E FE R E N C E

IO_Currency – If the underlying datatype of the column is a currency, the procedure


should set this parameter to the field’s native currency value.

IO_Time – If the underlying datatype of the column is a time, the procedure should
set this parameter to the field’s native time value.

Explorer_Get_Object_Name
This procedure retrieves the name of the specified SmartList object. For proper
display, the name should have a trailing space.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
inout string IO_Object_Name;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IO_Object_Name – A string that must be set by the procedure to indicate the name of
the specified SmartList object. For proper display, the name should have a trailing
space.

Explorer_Get_Records_Background
This procedure begins the process of retrieving and displaying records for a
SmartList object. It is called when no search criteria have been specified. It is also
called when search criteria are specified, but the SmartList object has not been
optimized for SQL Server. Most of the parameters for this script will simply be
passed to other SmartList procedures.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
in Explorer_INT_List IN_Type;
in Explorer_STR30_List IN_Search_From;
in Explorer_STR30_List IN_Search_To;
in Explorer_BOOL_List IN_Match_Case;
in integer IN_Global_Search_Type;
in integer IN_Total_Sub_Items;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in Explorer_Field_Comparison IN_Field_Comparison;
in Explorer_Start_Comp_Field_ID IN_Start_Comp_Field_ID;
in Explorer_Start_Comp_Field_Dict IN_Start_Comp_Field_Dict;
in Explorer_End_Comp_Field_ID IN_End_Comp_Field_ID;
in Explorer_End_Comp_Field_Dict IN_End_Comp_Field_Dict;
in Explorer_Start_Date_Token_DDL IN_Date_Token_From;

INTEGRATION GUIDE 383


PA RT 7 S M A R T L I S T

in Explorer_End_Date_Token_DDL IN_Date_Token_To;
inout long IO_Max_Records;
in boolean IN_GetSummary;
in integer IN_SummaryType;
inout integer IO_nSummaryCount;
in integer IN_nSummaryFieldDictID;
in integer IN_nSummaryFieldID;
inout currency IO_cyColumnTotal;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An array of four integers containing the IDs of the dictionaries


that define the fields being searched.

IN_Field – An array of four integers containing the resource IDs of the fields that are
being searched.

IN_Type – An array of four integers that represent the type of search being
performed on each search field.

IN_Search_From – An array of four strings that the search fields will be compared to.

IN_Search_To – An array of four strings that the search fields will be compared to.

IN_Match_Case – An array of four boolean values indicating whether the search


should match case.

IN_Global_Search_Type – An integer indicating whether the search is “Match All” or


“Match 1 or More”.

IN_Total_Sub_Items – An integer that specifies the total number of subitems that will
appear in the SmartList.

IN_Dict_List – Any array of 256 integers that contain the product IDs of the fields to
be added to the SmartList.

IN_Field_List – An array of 256 integers that contain the resource IDs of the fields to
be added to the SmartList.

IN_Field_Comparison – An array of four booleans indicating whether the search is a


field to field comparison.

IN_Start_Comp_Field_ID – An array of four integers that contain the resource IDs of


the fields to be compared.

IN_Start_Comp_Field_Dict – An array of four integers that contain the product IDs of


the fields to be compared.

IN_End_Comp_Field_ID – An array of four integers that contain the resource IDs of


the fields to be compared.

384 IN T E G R AT I O N G U ID E
C H A P T E R 3 5 S M A R T LI S T P R O C E D U R E R E FE R E N C E

IN_End_Comp_Field_Dict – An array of four integers that contain the product IDs of


the fields to be compared.

IN_Date_Token_From – An array of four integers that contain the starting date token.

IN_Date_Token_To – An array of four integers that contain the ending date token.

IO_Max_Records – A long integer containing the maximum number of records that


should be displayed in the SmartList.

IN_GetSummary – A boolean. The value true indicates the procedure is being called
to generate a custom reminder. Records are not being added to the SmartList
window. Instead, record counts or column totals are being returned.

IN_SummaryType – An integer that indicates the type of summary being generated.


The value 0 indicates a record count is being returned. The value 1 indicates a
column total is being returned.

IO_nSummaryCount – An integer containing the total number of records found


when a record count summary is being generated for a reminder.

IN_nSummaryFieldDictID – The product ID that contains the field for which


summary information is being generated.

IN_nSummaryFieldID – The resource ID of the field for which summary information


is being generated.

IO_cyColumnTotal – A currency containing the total of the column for the records
found when a column total summary is being generated for a reminder.

Explorer_Get_SQL_Field_Info
This procedure retrieves information about the table and field used for a column in
the SmartList object. The information is used in the query generated while
searching the data for the SmartList object.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field;
inout string IO_Table_Name;
inout integer IO_Table_Dict_ID;
inout integer IO_DDL_Type;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which information is being retrieved.

INTEGRATION GUIDE 385


PA RT 7 S M A R T L I S T

IN_Field_ID – An integer specifying the resource ID of the field for which


information is being retrieved.

IO_Table_Name – A string that must be set by the procedure to indicate the technical
name of the table that contains the specified field.

IO_Table_Dict_ID – An integer that must be set by the procedure to indicate the


dictionary ID of the product that defines the field and table.

IO_DDL_Type – An integer that must be set by the procedure to indicate the type of
list field used for the field. The value 0 indicates a 0-based list, while the value 1
indicates a 1-based list. If the field isn’t a list, specify the value 1.

Explorer_Get_SQL_Join_Info
This procedure is used for SQL-optimized SmartList objects to indicate how any
additional tables used for the object are related to the main table. The procedure
must create at least one record by calling Explorer_Set_SQL_Join_Info to be
optimized.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
inout integer Doc_Type;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An array of four integers containing the IDs of the dictionaries


that define the fields being searched.

IN_Field – An array of four integers containing the resource IDs of the fields that are
being searched.

Doc_Type – An integer indicating the type of document being displayed in


SmartList. The value will be 1 for a Work document, 2 for an Open document, or 3
for a History document.

386 IN T E G R AT I O N G U ID E
C H A P T E R 3 5 S M A R T LI S T P R O C E D U R E R E FE R E N C E

Explorer_Get_SQL_Override_Field_Name
This procedure is used in special cases where a field name changes, depending
upon the document types. For example, in the Inventory Work table, the field
identifying a document is called IV Document Number. In the Inventory History
table it is called Document Number. This procedure will examine the document
type and supply the correct name for the field.

The procedure must have the following parameters:

out string OUT_Field_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_Number;
in integer IN_Doc_Type;

OUT_Field_Name – A string that must be set by the procedure to the appropriate


technical name for the column, based on the document type indicated.

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which an alternate name is being retrieved.

IN_Field_Number – An integer specifying the resource ID of the field for which an


alternate name is being retrieved.

IN_Doc_Type – An integer that indicates which type of document the SmartList is


processing. The value will be 1 for a Work document, 2 for an Open document, or 3
for a History document.

Explorer_Get_SQL_Query_Fields
This procedures specifies which fields are the key fields to use for a query of a SQL-
optimized SmartList object. The procedure Explorer_Set_SQL_Query_Field is
called once for each field that is part of the key for the query.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object.

INTEGRATION GUIDE 387


PA RT 7 S M A R T L I S T

Explorer_Get_Table_Name
This procedure retrieves the technical name of the table that contains the field
definition used for a SmartList column.

The procedure must have the following parameters:

inout string OUT_Table_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;
in integer IN_Doc_Type;

OUT_Table_Name – A string that must be set by the procedure to the appropriate


technical name for the table that contains the field specified by the other
parameters.

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which the table name is being retrieved.

IN_Field_ID – An integer specifying the resource ID of the field for which the table
name is being retrieved.

IN_Doc_Type – An integer that indicates which type of document the SmartList is


processing. The value will be 1 for a Work document, 2 for an Open document, or 3
for a History document.

Explorer_Get_User_Defined_Prompt
This procedure is called when the columns for a SmartList object have been created
with the user-defined flag set to true. The procedure must look up the name to use
for the column.

The procedure must have the following parameters:

inout string OUT_Display_Name;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field_ID;

OUT_Display_Name – A string that must be set by the procedure to the name to use
for the column.

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object.

388 IN T E G R AT I O N G U ID E
C H A P T E R 3 5 S M A R T LI S T P R O C E D U R E R E FE R E N C E

IN_Field_Dict_ID – An integer specifying the ID of the dictionary that defines the


field for which a user-defined prompt is being used.

IN_Field_ID – An integer specifying the resource ID of the field for which a user-
defined prompt is being used.

Explorer_GoTo_Button
This procedure processes the Go To actions that were added to a SmartList object.

The procedure must have the following parameters:

inout anonymous field IN_ListView;


in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_GoTo_Dict_ID;
in integer IN_GoTo_Item;

IN_ListView – A reference passed into the procedure that allows access to the List
View field in the SmartList window. This field must be accessed to determine the
current selection.

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

IN_GoTo_Dict_ID – An integer specifying the ID of the dictionary that defined the


Go To item.

IN_GoTo_Item – An integer specifying the unique ID of the Go To item to be


processed.

Explorer_Optimize_For_SQL
This procedure indicates whether a specific SmartList object has been optimized for
SQL Server. The procedure will be called multiple times, once for each field the user
includes in the SmartList search.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Field_Dict_ID;
in integer IN_Field;
inout boolean IO_Optimize;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object. For SmartLists


defined in the core application, the value corresponds to one of the constants
defined in SmartList objects on page 332.

INTEGRATION GUIDE 389


PA RT 7 S M A R T L I S T

IN_Field_Dict_ID – An integer containing the ID of the dictionary that defines the


field being searched.

IN_Field – An integer containing the resource ID of the field being searched.

IO_Optimize – A boolean that must be set by the procedure to specify whether the
SmartList object or additional columns are optimized for SQL Server. The value true
indicates the object is optimized, while false indicates it is not.

Explorer_Process_SQL_Data
This procedure is called when a SmartList object optimized for SQL Server is used,
and search criteria have been specified. The SmartList will generate a SQL results
set that contains the key values for the records to be displayed. This results set is
passed into this procedure where it can be used to display the appropriate records.

The procedure must have the following parameters:

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in integer IN_Total_SubItems;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in long IN_Record_Count;
inout long SQL_Context;

IN_Object_Dict_ID – An integer specifying the ID of the dictionary that defines the


SmartList object.

IN_Object_Type – An integer specifying the type of SmartList object.

IN_Total_SubItems – An integer containing the number of additional columns that


are to be displayed in the SmartList.

IN_Dict_List– An array of 256 integers containing the product IDs for the fields that
are to be displayed as columns in the SmartList.

IN_Field_List – An array of 256 integers containing the resource IDs for the fields
that are to be displayed as columns in the SmartList.

IN_Record_Count – A long integer containing the current number of items displayed


in the SmartList list view field.

SQL_Context – A long integer containing a reference to the SQL results set that
contains the key values for the items to be displayed.

390 IN T E G R AT I O N G U ID E
PART 8: APPLICATION SERVICES
Part 8: Application Services
Several services are available within Microsoft Dynamics GP that your integrating
application can use. The following items are discussed:

• Chapter 36, “Security,” describes how to use the security features in Microsoft
Dynamics GP.

• Chapter 37, “Home Pages,” explains how to integrate with Home Pages dis-
played in Microsoft Dynamics GP.

• Chapter 38, “Setup Checklist,” describes how to integrate setup windows with
the Setup Checklist.

• Chapter 39, “Online Help,” explains how to implement online help for your
integrating application.

• Chapter 40, “Unified Communications,” explains how to implement support


for Unified Communications in your integrating application.

392 IN T E G R AT I O N G U ID E
Chapter 36: Security
Security in the Microsoft Dynamics GP application is controlled at several levels.
Your integration with Microsoft Dynamics GP should use the security features
provided to ensure that the application remains secure. Information about security
is divided into the following sections:

• Microsoft Dynamics GP security model


• Adding security data
• Security tasks
• Security task operations
• Security roles
• Checking security access
• Excluding resources from security checks
• Removing security information
• Creating a new security resource type
• System password
• Database security

Microsoft Dynamics GP security model


In the Microsoft Dynamics GP security model, a user has default access to only the
forms necessary to access the core application. The user must be assigned to one or
more roles that provide access to the forms, reports, tables, lists, and SmartLists
needed to complete specific tasks. The system administrator assigns to the
appropriate roles to each user.

You should consider creating new tasks that provide access to the resources needed
to complete the actions provided by your integrating application. For instance, the
sample integrating application creates a task that controls access to lead
management functionality.

You may also want to create additional roles that include the tasks you’ve defined,
making it easy for the Microsoft Dynamics GP system administrator to grant access
to your integration. Your integrating application should not assign roles to specific
users. That should be done only by the system administrator.

If your integration works closely with a particular Microsoft Dynamics GP form,


you may want to add an operation to the predefined task or tasks that provides
access to the form. This additional operation specifies the resources are used for
your integration. For example, if your integration defines a form that extends the
Customer Maintenance form, you might want to add this to the “CARD_0201” task,
which controls access to customer and address functionality.

The Alternate/Modified Forms and Reports window is used to grant access to


alternate versions of forms or reports, which are part of a third-party integrating
dictionary. Refer to Controlling form access on page 31 and Controlling report access on
page 48 for more information about accessing alternate forms and reports.

INTEGRATION GUIDE 393


PA RT 8 AP P LI C A TI O N S E R V IC E S

Adding security data


Refer to One method to add security data for your integrating application is to use a
Security scripts on procedure that is run after the system administrator successfully logs into Microsoft
page 603 for details Dynamics GP. The following example is a portion of the Startup procedure for the
about the functions sample integrating application. It registers a procedure trigger that is activated
used to add security when a user successfully logs into Microsoft Dynamics GP.
data.
local integer l_result;

l_result = Trigger_RegisterProcedure(script Add_Successful_Login_Record,


➥ TRIGGER_AFTER_ORIGINAL, script IG_CreateSecurityData);
if l_result <> SY_NOERR then
warning "Procedure trigger for adding security data failed.";
end if;

In the trigger processing procedure, the security tasks, security task operations, and
security roles for the integrating application are created.

The reports available in the various security setup windows in Microsoft Dynamics GP are a
good way to verify that the security data for your integrating application has been installed
correctly.

Security tasks
Security tasks are groups of operations that users can perform in Microsoft
Dynamics GP. Microsoft Dynamics GP contains numerous predefined tasks. One
task in Microsoft Dynamics GP has special significance. The DEFAULTUSER task
contains all of the operations that every user of the system can perform. If you have
resources in your integration that every user should be able to access, you will add
them to the DEFAULTUSER task.

Security task elements


Each security task has the following elements:

Task ID This value uniquely identifies the security task. When creating new
security tasks, be sure to follow the naming convention used for the predefined
tasks in Microsoft Dynamics GP. The task names use the following convention:

Type_Module_Sequence

The Type indicates the type of task. Typically, it will be ADMIN, CARD, INQ, RPT,
or TRX. The Module indicates the module or application for which the task is
defined. The Sequence is a numeric value that differentiates similar tasks.

Task Name This is the name that is displayed for the task. It should be
descriptive, indicates what sort of tasks it is providing access to.

Task Description The description provides additional detail about exactly what
resources the security task provides access to.

Category The category is used to group related security tasks.

394 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

Creating security tasks


To create a security task in Microsoft Dynamics GP, use the CreateSecurityTask()
function of the sySecurityTask form. The following example uses this function to
create the CARD_IGSAMPLE_01 security task for the sample integrating
application.

local long status;


local string taskID;

taskID = "CARD_IGSAMPLE_01";
status = CreateSecurityTask(taskID, {ID}
"Maintain leads", {Name}
"Maintain lead information and setup.", {Description}
CATEGORY_SALES of form sySecurityRoleEntry)
of form sySecurityTask;

You can use the Exists() -- Security Task function to find out whether a task has been
defined.

Security task operations


A security task operation is a specific resource in Microsoft Dynamics GP for which
security access can be controlled.

Security task operation elements


A security task will have several security task operations assigned to it. These are
the resources to which access is being granted. Each security task operation has the
following elements:

Task ID This is the ID of the security task to which an operation is being added.
You can add operations to your own tasks, or to existing Microsoft Dynamics GP
tasks.

Product ID This specifies the dictionary that contains the resource for which a
security operation is being added.

Resource type This indicates the type of resource for which a security operation
is being added. The value corresponds to one of the following constants:

Contant Value
TABLETYPE 1
FORMTYPE 2
REPORTTYPE 23
SECURITYTYPE_LISTS 900
SECURITYTYPE_SMARTLISTOBJECT 1000

Security ID The security ID is a long integer value that identifies the specific
resource for which a security operation is being added. The following table lists the
security resource types and the corrensponding security ID values:

Security resource type Security ID


Tables Table Resource ID
Forms Form Resource ID
Reports Report Resource ID

INTEGRATION GUIDE 395


PA RT 8 AP P LI C A TI O N S E R V IC E S

Security resource type Security ID


Lists Dictionary-specific ID for the list
SmartLists Dictionary-specific ID for the SmartList object

To build the security ID for a list, use the BuildDictSpecificID() function. The
following constants are defined for the portions of the list for which security can be
controlled:

Constant Description
LISTSECURITYTYPE_LIST The base list
LISTSECURITYTYPE_PREVPANE The information pane for the list
LISTSECURITYTYPE_CUSTOMIZE The customization capability for the list

Use one of these constants as the product ID (first parameter) for the
BuildDictSpecificID() function. Use the unique integer identifier you assigned to
the list as the action (second parameter).

To build the security ID for a SmartList object, use the BuildDictSpecificID()


function. Use your dictionary ID (first parameter) and the ID value you assigned to
the SmartList object you created as the action (second parameter).

Adding security task operations


To add a security task operation to a task in Microsoft Dynamics GP, use the
AddSecurityTaskOperation() function of the sySecurityTaskOperations form. The
following example uses this function to add various security operations to the
CARD_IGSAMPLE_01 security task for the sample integrating application.
local long status;
local string taskID;

taskID = "CARD_IGSAMPLE_01";

{Lead Maintenance form}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
FORMTYPE,
resourceid(form IG_Lead_Maintenance))
of form sySecurityTaskOperations;

{Leads report}
status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
REPORTTYPE,
resourceid(report IG_Leads))
of form sySecurityTaskOperations;

{Lead master table}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
TABLETYPE,
resourceid(table IG_Leads_MSTR))
of form sySecurityTaskOperations;

396 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

{Leads list - Base List}


{The value 1 is the ID of the Lead list}
status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
SECURITYTYPE_LISTS,
BuildDictSpecificID(LISTSECURITYTYPE_LIST, 1))
of form sySecurityTaskOperations;

{Leads list - Information Pane}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
SECURITYTYPE_LISTS,
BuildDictSpecificID(LISTSECURITYTYPE_PREVPANE, 1))
of form sySecurityTaskOperations;

{Leads list - Customization}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
SECURITYTYPE_LISTS,
BuildDictSpecificID(LISTSECURITYTYPE_CUSTOMIZE, 1))
of form sySecurityTaskOperations;

{Leads SmartList}
status = AddSecurityTaskOperation(taskID,
SMARTLIST,
1000, {Use constant SECURITYTYPE_SMARTLISTOBJECT in GP 10 SP1 and later}
BuildDictSpecificID(IG_PROD_ID, SMARTLIST_OBJECTTYPE_LEADS))
of form sySecurityTaskOperations;

You can use the Exists() -- Security Task Operation function to find out whether a
security operation has already been added to a security task.

Security roles
Each user in Microsoft Dynamics GP is assigned to one or more security roles. Each
security role contains a set of security operations that can be accessed by users in
that role.

Security role elements


Each security role has the following elements:

Role ID This value uniquely identifies the security role. The role ID should be in
uppercase.

Role Name This is the name that is displayed for the security role. It should be
descriptive, indicating what sort of tasks it is providing access to.

Role Description The description provides additional detail about exactly what
resources the security role provides access to.

INTEGRATION GUIDE 397


PA RT 8 AP P LI C A TI O N S E R V IC E S

Creating security roles


To create a security role in Microsoft Dynamics GP, use the CreateSecurityRole()
function of the sySecurityRole form. The following example uses this function to
create the LEAD GENERATION security role for the sample integrating
application.

local long status;


local string roleID;

{Add the Lead Generation security role}


roleID = "LEAD GENERATION";
if Exists(roleID) of form sySecurityRole = false then
{Role does not exist, so create it}
status = CreateSecurityRole(roleID, {ID}
"Lead Generation", {Name}
"Tasks include creating and updating customer leads.") {Description}
of form sySecurityRole;
end if;

You can use the Exists() -- Security Role function to find out whether a security role has
already been created.

Adding tasks to security roles


To add tasks to a security role, use the AddTaskToRole() function of the
sySecurityTaskRole form. The following example uses this function to add the
CARD_IGSAMPLE_01 security task to the LEAD GENERATION security role.
local long status;
local string roleID;

roleID = "LEAD GENERATION";


status = AddTaskToRole(roleID, "CARD_IGSAMPLE_01") of form
➥ sySecurityTaskRole;

You can use the Exists() -- Security Task Role function to find out whether a security task
has already been added to a security role.

Checking security access


You may need to find out whether a specific user has access to a resource in
Microsoft Dynamics GP. For example, security access is checked for each metric that
can appear on the user’s home page. If the user doesn’t have security access to the
forms that access the data used for the metric, the metric should not be available to
display.

Microsoft Dynamics GP provides the Security() function that you can use to check
the security access for a form, report, or table. The following example shows how
this function is used to find whether the current user has access to the
IG_Contact_History form.
local integer dict_ID = 3333;
local integer result;

result = Security(dict_ID, FORMTYPE, resourceid(form IG_Contact_History));

398 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

Excluding resources from security checks


You may not want to have security access checked for a specific resource. For
example, a command form you create for your integration should be excluded from
security checks so it is always available to every user.

To exclude a form from the security check, set the Title property of the main
window for the form to the value ~internal~. Use this for forms that must be
opened, but won’t display windows, such as command forms.

To exclude any type of resource (including forms) from security checks, register a
function trigger for the ExcludeFromSecurity() function of the sySecurityTaskEntry
form. This function is called each time a resource is accessed, allowing the script to
determine whether the resource should be excluded from security. The following
example shows the trigger registration for this function:
local integer l_result;

l_result = Trigger_RegisterFunction(function ExcludedFromSecurity of form


➥ sySecurityTaskEntry, TRIGGER_AFTER_ORIGINAL, function
➥ IG_ExcludeFromSecurity);
if l_result <> SY_NOERR then
warning "Trigger registration for excluding security items failed.";
end if;

The following is the trigger processing function that excludes items from security
checks for the sample integrating application. If the specific resource indicated by
the parameters passed to the function should be excluded from security checks, the
procedure sets the return value of the function to true. Notice that the function first
checks the return value passed into the function. If it has the value true, other code
has (such as core Dynamics GP code) has determined that the item should be
excluded from security checks. Thus, no action needs to be performed by this
function.

function returns boolean exclude;

in integer dict_ID;
in long security_ID;
in integer security_restype;

{If the resource has already been excluded, then don't do further processing.}
if exclude = false then
{Is it our resource to check?}
if dict_ID = IG_PROD_ID then
{Is it an item to exclude?}
if security_restype = FORMTYPE then
if security_ID = resourceid(form IG_Lead_Inquiry) then
exclude = true;
end if;
end if;
end if;
end if;

INTEGRATION GUIDE 399


PA RT 8 AP P LI C A TI O N S E R V IC E S

Removing security information


If you are removing your product from a Microsoft Dynamics GP installation, you
may want to remove the security information that you defined for your product.
You can use the DeleteSecurityForProduct() function to do this. This function
removes the security task operations and modified/alternate forms and reports
settings for your integration.

We recommend using this function to remove security data, rather than removing the items
directly from the tables that store the security data.

Creating a new security resource type


Your integration may have an additional resource type for which you want to
control security access. This new security resource type will appear just like any of
the built-in security resource types such as windows or reports. Creating a new
security resource type requires several steps. The remainder of this section describes
how to add a new security resource type (named New Security Type), with two
series (Series 1 and Series 2), and the corresponding security operations. The
Security Task Setup window with the new security resource type is shown in the
following illustration.

This new security


resource type was
added.

Adding the security resource type


The security resource type must be added to the list of types in the Security Task
Setup window. Do this by creating a procedure trigger for the
AddOtherSecurityType procedure of the sySecurityTaskEntry form. The following
example shows the registration for this trigger.

l_result = Trigger_RegisterProcedure(script AddOtherSecurityType of form


➥ sySecurityTaskEntry, TRIGGER_AFTER_ORIGINAL, script IG_Security_AddType);
if l_result <> SY_NOERR then
warning "Procedure trigger registration to create security type failed.";
end if;

The following is the trigger processing procedure that adds a new security resource
type to the list of types in the Security Task Setup window. Notice how the ID for
the security resource type is saved as the data value for the list item.

400 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

When specifying the value for the security item type, be sure to use values other than those
defined by the core Dynamics GP product. Values below 100 are reserved for Dynamics GP.

in integer dict_ID;

if isopen(window syTaskEntry of form sySecurityTaskEntry) then


if dict_ID = IG_PROD_ID then
{New security resource type with value 1}
add item "New Security Type", 100 to '(L) SecurityType' of window
➥ syTaskEntry of form sySecurityTaskEntry;
end if;
end if;
Adding the series for the selected type
After the user has chosen the new security resource type, the Series drop-down list
in the Security Task Setup window must be populated with values appropriate to
the new type. This is done by creating a procedure trigger for the
LoadSecuritySeriesDDL procedure of the sySecurityTaskEntry form. The following
example shows the registration for this trigger.

l_result = Trigger_RegisterProcedure(script LoadSecuritySeriesDDL of form


➥ sySecurityTaskEntry, TRIGGER_AFTER_ORIGINAL, script
➥ IG_Security_AddSeriesItems);
if l_result <> SY_NOERR then
warning "Trigger registration to add series for security type failed.";
end if;

The following is the trigger processing procedure that adds the series items for the
new security resource type. Notice how the ID for each series is saved as the data
value for the list item.

in integer dict_ID;
in long security_type;

if isopen(window syTaskEntry of form sySecurityTaskEntry) then

if dict_ID = IG_PROD_ID then


{It's our product, so add the security series items}
if security_type = 100 then
{Add the items}
add item "Series 1", 1 to field '(L) SecuritySeries' of window
➥ syTaskEntry of form sySecurityTaskEntry;
add item "Series 2", 2 to field '(L) SecuritySeries' of window
➥ syTaskEntry of form sySecurityTaskEntry;

{Set the security resource type use by the core Dynamics GP code}
Restype of window syTaskEntry of form sySecurityTaskEntry = 100;
end if;
end if;
end if;

INTEGRATION GUIDE 401


PA RT 8 AP P LI C A TI O N S E R V IC E S

Displaying items of the selected security type


After the user has selected the type and series for the new security resource type,
the Access List must be filled with the items of that type. This is done by creating a
procedure trigger for the Load3rdPartyOperationsIntoLV procedure of the
sySecurityTaskEntry form. The following example shows the registration for this
trigger.

l_result = Trigger_RegisterProcedure(script Load3rdPartyOperationsIntoLV of


➥ form sySecurityTaskEntry, TRIGGER_AFTER_ORIGINAL, script
➥ IG_Security_LoadItemsForType);
if l_result <> SY_NOERR then
warning "Trigger registration to add items for security type failed.";
end if;

The following is the trigger processing procedure that adds the items for the new
security resource type that are in the selected series. It must set up the database
infrastructure for the Security Task Entry window. For each item, the procedure
does the following:

• It uses the SetIndex procedure to specify which task is being added.

• It call the Get() function to retrieve the status of that task, which indicates
whether the task had previously been marked and saved by the user.

• Based on the status, the LoadListView procedure to add the task to the list in
the appropriate state.

in integer dict_ID;
in integer security_type;
in integer security_series;

local sySecurityTaskOperationsState TaskOperationsState;


local long status;

if isopen(window syTaskEntry of form sySecurityTaskEntry) then


if dict_ID = IG_PROD_ID then
if security_type = 100 then
status = Create(TaskOperationsState, table
➥ sySecurityAssignTaskOperations) of form
➥ sySecurityTaskOperations;
if status <> OKAY then
abort script;
end if;

if security_series = 1 then
{Look up the security status of each item as it is added, so
that the marked or unmarked state can be set}

{Series 1 Item 1 -- ID is 101}


call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
101,
security_type;

402 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 101",
➥ 101, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 101",
➥ 101, security_type, dict_ID, false;
end if;

{Series 1 Item 2 -- ID is 102}


call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
102,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 102",
➥ 102, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 102",
➥ 102, security_type, dict_ID, false;
end if;
end if;

if security_series = 2 then
{Series 2 Item 1 -- ID is 201}
call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
201,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 201",
➥ 201, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 201",
➥ 201, security_type, dict_ID, false;
end if;

INTEGRATION GUIDE 403


PA RT 8 AP P LI C A TI O N S E R V IC E S

{Series 2 Item 2 -- ID is 202}


call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
202,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 202",
➥ 202, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 202",
➥ 202, security_type, dict_ID, false;
end if;
end if;

call ClearRange of form sySecurityTaskOperations,


➥ TaskOperationsState;
call Destroy of form sySecurityTaskOperations,
➥ TaskOperationsState;
end if;
end if;
end if;

Retrieving information for reports


Reports in Microsoft Dynamics GP provide information about the tasks assigned to
users. When you add a new security type, you must also register three additional
triggers that allow reports to retrieve the security resource type, series, and name of
the operations you are defining for that type.

To retrieve the security type name, register a procedure trigger for the
GetResourceTypeforTaskSetupReport() global function. The following example
shows the registration for the function trigger that retrieves the type for a security
task.
l_result = Trigger_RegisterFunction(function
➥ GetResourceTypeforTaskSetupReport, TRIGGER_AFTER_ORIGINAL, function
➥ IG_Security_GetType);
if l_result <> SY_NOERR then
warning "Function trigger registration for retrieving task type failed.";
end if;

The following is the trigger processing procedure that retrieves the name for a
security resource type.
function returns string sType;

in 'Security Resource Type' security_type;


in integer dict_ID;
in 'Security ID' security_ID;

404 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

if dict_ID = IG_PROD_ID then


if security_type = 100 then
sType = "New Security Type";
end if;
end if;

To retrieve the series name for a security task, register a procedure trigger for the
GetResourceSeriesforTaskSetupReport() global function. The following example
shows the registration for the function trigger that retrieves the series for a task.
l_result = Trigger_RegisterFunction(function
➥ GetResourceSeriesforTaskSetupReport, TRIGGER_AFTER_ORIGINAL, function
➥ IG_Security_GetSeries);
if l_result <> SY_NOERR then
warning "Trigger registration for retrieving task series failed.";
end if;

The following is the trigger processing procedure that retrieves the series name for a
security task.
function returns string sSeries;

in 'Security Resource Type' security_type;


in integer dict_ID;
in 'Security ID' security_ID;
out integerseries_value;
if dict_ID = IG_PROD_ID then
if security_type = 100 then
case security_ID
in[101]
sSeries = "Series 1";
in[102]
sSeries = "Series 1";
in[201]
sSeries = "Series 2";
in[202]
sSeries = "Series 2";
end case;
end if;
end if;

To retrieve the name for an operation, register a procedure trigger for the
GetResourceNameforTaskSetupReport() global function. The following example
shows the registration for the function trigger that retrieves the name for a security
operation.
l_result = Trigger_RegisterFunction(function
➥ GetResourceNameforTaskSetupReport, TRIGGER_AFTER_ORIGINAL, function
➥ IG_Security_GetOperationName);
if l_result <> SY_NOERR then
warning "Trigger registration for retrieving operation name failed.";
end if;

INTEGRATION GUIDE 405


PA RT 8 AP P LI C A TI O N S E R V IC E S

The following is the trigger processing procedure that retrieves the name for a
security operation.
function returns string sName;

in 'Security Resource Type' security_type;


in integer dict_ID;
in 'Security ID' security_ID;

if dict_ID = IG_PROD_ID then

if security_type = 100 then


case security_ID
in[101]
sName = "Item 101";
in[102]
sName = "Item 102";
in[201]
sName = "Item 201";
in[202]
sName = "Item 202";
end case;
end if;
end if;

System password
Access to certain system-level actions in controlled through the use of the system
password, which was defined when Microsoft Dynamics GP was installed. When a
user tries to access one of these restricted actions, a password dialog is displayed,
prompting them for the system password. The user must supply the appropriate
system password to continue.

The user must supply the


system password.

You may have system-level functionality in your integrating application, such as


setup or configuration windows, that should be restricted in this same manner. You
can use the GetValidSystemPassword() function provided by Microsoft Dynamics
GP to prompt the user for the system password. If they enter the correct password,
you can allow them to access the restricted functionality.

The following example is the form pre script for the IG_Sample_Setup form. It uses
the GetValidSystemPassword() function to restrict access to the setup window for
the sample integrating application.

local boolean result;

result = GetValidSystemPassword();

if result = false then


close form IG_Sample_Setup;
abort script;
end if;

406 IN T E G R AT I O N G U ID E
C H A P T E R 3 6 S EC U R IT Y

Carefully consider where you place the GetValidSystemPassword() function to


control access. For example, when restricting access for a form, place the function in
the form pre script. This ensures that the restriction code is run, regardless of how
the form is opened.

Database security
Microsoft Dynamics GP uses security features provided by SQL Server to help
maintain security of data in the accounting system. Each user added to Microsoft
Dynamics GP is also a SQL user. To maintain security, it’s important to grant only
the SQL access privileges that are necessary for specific user to perform tasks in the
accounting system.

The “sa” and “DYNSA” users


Some actions you need to perform for your integration, such as creating tables, must
be performed by a user that has sufficient SQL privileges. You might consider
performing these actions while running Microsoft Dynamics GP as “sa”, the built-in
SQL Server administrator user. We discourage using the “sa” user for this purpose.
The “sa” user has unlimited access privileges to the SQL server, and should be used
sparingly to help keep the system secure.

Instead, we suggest using the “DYNSA” user when peforming administrator


actions like creating tables and stored procedures. The “DYNSA” user is created
during the Microsoft Dynamics GP installation just for this purpose. It has sufficient
SQL privileges to perform administrative actions like creating tables, but only in
databases used by the Microsoft Dynamics GP application. Limiting the access of
the “DYNSA” user helps keep the SQL server more secure.

Coding your application


You may want to code your integrating application so that administrative tasks can
be performed properly when running as either the “DYNSA” or “sa” user. Refer to
Creating SQL tables on page 35 for more information about doing this.

You might also choose to use the syUserInRole() function to determine what SQL
Server privileges the current user has. If the user is in a SQL Server role that has the
necessary privileges to perform the SQL task, such as creating tables, you can allow
the operation to proceed. Otherwise, your application should prevent the user from
accessing the functionality, or display an appropriate error message indicating the
lack of privileges.

INTEGRATION GUIDE 407


408 IN T E G R AT I O N G U ID E
Chapter 37: Home Pages
A Home Page in Microsoft Dynamics GP provides links to key areas of the
application, allows access to relevant reports, and presents data metrics that are
important to the user. Several roles are defined in the Microsoft Dynamics GP
application, such as Accounting Manager or Customer Service Representative. The
initial set of items displayed on a Home Page depends on the role the user chose.
Users can customize the Home Page by adding or removing items.

You can make content for your integration available for use on Home Pages. You
can also add items to the template Home Page for each role in Microsoft Dynamics
GP. When a user chooses that role, your items will be included on the initial Home
Page constructed for them.

Information about home pages is divided into the following sections:

• Roles
• Adding additional roles
• Adding to Home Page templates
• Adding Quick Links
• Adding reports
• Metric overview
• SSRS metrics
• OWC metrics
• Creating OWC metrics
• Writing an OWC metric procedure
• Making OWC metrics available
• OWC Metric chart reference

Roles
Several roles have been defined in Microsoft Dynamics GP. Each user selects a role
that best describes the tasks they perform in the system. The initial content
displayed on the user’s Home Page is based on the role they selected. The following
table lists the roles defined and the corresponding constant used to refer to the role.
You will use these constants when adding Home Page items for your integration.

Role Constant
Accounting Manager ROLE_ACCOUNTINGMGR
Accounts Payable ROLE_ACCOUNTPAYABLES
Accounts Receivable ROLE_ACCOUNTRECV
Bookkeeper ROLE_BOOKKEEPER
Certified Accountant ROLE_CERTACCOUNTANT
Collections Manager ROLE_COLLECTIONSMGR
Customer Service Rep ROLE_CUSTSVCREP
Dispatcher ROLE_DISPATCHER
Human Resources ROLE_HR
IT Operations Manager ROLE_ITOPSMGR
Materials Manager ROLE_MATERIALSMGR
None ROLE_NONE
Operations Manager ROLE_OPSMGR
Order Processor ROLE_ORDERPROCESSOR
Payroll ROLE_PAYROLL

INTEGRATION GUIDE 409


PA RT 8 AP P LI C A TI O N S E R V IC E S

Role Constant
Production Manager ROLE_PRODMGR
Production Planner ROLE_PRODPLANNER
Purchasing Agent ROLE_PURCHAGENT
Purchasing Manager ROLE_PURCHMGR
Shipping and Receiving ROLE_SHIPPINGRECVING
Shop Supervisor ROLE_SHOPSUPERVISOR
Warehouse Manager ROLE_WAREHOUSEMGR

Adding additional roles


You can add additional roles for your integrating application that will be displayed
in the Select Home Page window. For example the Lead Generation role is added by
the sample integrating application.

This role is added by the


sample integrating
application.

Adding the list item for the role


The following is a portion of the Startup script for the sample integrating
application. It registers a procedure trigger that will add a new role to the list in the
Select Home Page window.

l_result = Trigger_RegisterProcedure(script LoadRoleListBox of form


syHomePageRole, TRIGGER_AFTER_ORIGINAL, script IG_HomePage_AddRole);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for LoadRoleListBox failed.";
end if;

The following example is the IG_HomePage_AddRole procedure for the sample


integrating application. It adds the “Lead Generation” role to the list, and specifies
the integer ID for the new role as the data item for the list entry.

in long iIndustry;

{Add a new role}


if iIndustry = INDUSTRY_OTHER then
add item "Lead Generation", ROLE_LEADGENERATOR to field '(L) RoleListBox'
➥ of window SelectHomePage of form syHomePageRole;
end if;

410 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

The industry the user selected will be passed as a parameter for the trigger
processing procedure. The value will correspond to one of the following constants:

Industry Constant
Education INDUSTRY_EDUCATION
Finacial Services INDUSTRY_FINANCIALSERVICES
Government INDUSTRY_GOVERNMENT
Healthcare INDUSTRY_HEALTHCARE
Manufacturing INDUSTRY_MANUFACTURING
Media & Entertainment INDUSTRY_MEDIAENTERTAINMENT
Non Profit INDUSTRY_NONPROFIT
Other INDUSTRY_OTHER
Retail INDUSTRY_RETAIL
Services INDUSTRY_SERVICES
Telecommunications INDUSTRY_TELECOM
Transportation & Logistics INDUSTRY_TRANSPORTATION
Utilities INDUSTRY_UTILITIES
Wholesale & Distribution INDUSTRY_WHOLESALE

When specifying the integer value that indentifies a new role, use the following
guidelines:

• Role values 100 to 120 are used by Microsoft Dynamics GP.

• The value you pick must not conflict with other integrating applications, so try
to pick a value that is unique for your integration. For instance, consider using
the product ID for your integrating application.

The sample integrating application uses its product ID 3333 to identify the role it adds to
Microsoft Dynamics GP.

Selecting the role


When the user selects a role in the list, a description of the role is displayed. The
following is a portion of the Startup script for the sample integrating application. It
registers a focus trigger that will display a description when the new role is selected.
l_result = Trigger_RegisterFocus(anonymous('(L) RoleListBox' of window
➥ SelectHomePage of form syHomePageRole), TRIGGER_FOCUS_CHANGE,
➥ TRIGGER_AFTER_ORIGINAL, script IG_HomePage_LookupRoleDescription);
if l_result <> SY_NOERR then
warning "Focus trigger registration for role description failed.";
end if;

The following example is the IG_HomePage_LookupRoleDescription procedure


for the sample integrating application. It displays a description for the “Lead
Generation” role when this role is selected in the Select Home Page window.
if itemdata('(L) RoleListBox' of window SelectHomePage of form
➥ syHomePageRole, '(L) RoleListBox' of window SelectHomePage of form
➥ syHomePageRole) = ROLE_LEADGENERATOR then
'(L) RoleDescription' of window SelectHomePage of form syHomePageRole =
➥ "Tasks for this role would include finding and managing potential
➥ customer leads.";
end if;

INTEGRATION GUIDE 411


PA RT 8 AP P LI C A TI O N S E R V IC E S

Building the Home Page


If the user chooses the new role you added and clicks OK, your code must handle
the entire process of building the Home Page for the user. The following is a portion
of the Startup script for the sample integrating application. It registers a procedure
trigger that will build a home page for the new role added.
l_result = Trigger_RegisterProcedure(script BuildHomePageForRole of form
➥ syHomePageRole, TRIGGER_AFTER_ORIGINAL, script IG_HomePage_BuildHomePage);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for Build Home Page failed.";
end if;

The process of building a Home Page requires using several procedures and
functions defined on the Home Page forms for Microsoft Dynamics GP. These are
described in << Ref goes here>>. Refer to the example for the Create() function to
see the IG_HomePage_BuildHomePage trigger processing procedure. for the
sample integrating application. This procedure builds the Home Page when the
user has chosen the “Lead Generation” role.

Roles for list view sharing


When you create a new role for a Home Page, you may want to make this role
available for use when sharing list views. To do this, you will register a procedure
trigger for the FillRolesLookup procedure of the syListViewCustomize form. The
following example shows this registration for the sample integrating application.
l_result = Trigger_RegisterProcedure(script FillRolesLookup of form
➥ syListViewCustomize, TRIGGER_AFTER_ORIGINAL, script IG_Lists_AddRole);
if l_result <> SY_NOERR then
warning "Procedure trigger registration for FillRolesLookup failed.";
end if;

The trigger processing precedure that runs in response to this trigger will add the
new role to the list of roles the user can select from when sharing a list view. The
following example is the IG_Lists_AddRole trigger processing procedure that adds
a new role to this list.
local long nItemIndex;

{Add the Lead Generation role}


nItemIndex = ListView_ItemAdd('(L) RoleList' of window RoleLookup of form
➥ syListViewCustomize, GetHomePageRoleName(ROLE_LEADGENERATOR),
➥ ROLE_LEADGENERATOR, 0);

Adding to Home Page templates


An integrating application can add the following items to a Home Page template for
a role:

• Quick Links
• Reports
• Metrics

When a user chooses that role, any items you add to the template will be included
on that user’s initial Home Page.

Users who have already chosen a role before your integration was installed will have to
manually add items to their Home Page.

412 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

The Microsoft Dynamics GP dictionary contains form-level procedures defined in


the syHomePageRole form that are used as the templates when setting up a Home
Page for a user. You will create triggers for the procedures that set up the Home
Page for the roles you want to add items to. The following table lists the procedures
of the syHomePageRole form that set up the Quick Links, metrics, and reports for a
role:

Role Quick Link and metric procedure Reports procedure


Accounting Manager SetupAccountingManagerRole SetupAccountingManagerReports
Accounts Payable SetupAccountsPayableRole SetupAccountsPayableReports
Accounts Receivable SetupAccountReceivablesRole SetupAccountReceivablesReports
Bookkeeper SetupBookkeeperRole SetupBookkeeperReports
Certified Accountant SetupAccountantRole SetupAccountantReports
Collections Manager SetupCollectionsManagerRole SetupCollectionsManagerReports
Customer Service Rep SetupCustomerServiceRole SetupCustomerServiceReports
Dispatcher SetupDispatcherRole SetupDispatcherReports
Human Resources SetupHRManagerRole SetupHRManagerReports
IT Operations Manager SetupITManagerRole SetupITManagerReports
Materials Manager SetupMaterialsManagerRole SetupMaterialsManagerReports
Operations Manager SetupOperationsManagerRole SetupOperationsManagerReports
Order Processor SetupOrderProcessorRole SetupOrderProcessorReports
Payroll SetupPayrollRole SetupPayrollReports
Production Manager SetupProductionManagerRole SetupProductionManagerReports
Production Planner SetupProductionPlannerRole SetupProductionPlannerReports
Purchasing Agent SetupPurchasingAgentRole SetupPurchasingAgentReports
Purchasing Manager SetupPurchasingManagerRole SetupPurchasingManagerReports
Shipping and Receiving SetupShippingRole SetupShippingReports
Shop Supervisor SetupShopSupervisorRole SetupShopSupervisorReports
Warehouse Manager SetupWarehouseManagerRole SetupWarehouseManagerReports

The following is a portion of the Startup script for the sample integrating
application. It registers two procedure triggers that will add Home Page items to the
templates for the Customer Service Rep and Operations Manager roles.

l_result = Trigger_RegisterProcedure(script SetupCustomerServiceRole of form


➥ syHomePageRole, TRIGGER_AFTER_ORIGINAL, script IG_HomePage_SetupRoles);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

l_result = Trigger_RegisterProcedure(script SetupOperationsManagerRole of


➥ form syHomePageRole, TRIGGER_AFTER_ORIGINAL, script
➥ IG_HomePage_SetupRoles);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

INTEGRATION GUIDE 413


PA RT 8 AP P LI C A TI O N S E R V IC E S

The trigger processing procedures will actually add the items to the Home Page
template for the specific role. The trigger processing procedure to add Quick Links
and metrics must have the following parameters:

in integer iIndustry;
in integer iUserRole;

The trigger processing procedure to add report items must have the following
parameter:

in integer iUserRole;

The commands that you will use to add the various types of items are described in the
following sections.

Adding Quick Links


Quick Links on a Home Page allow users to quickly access windows in Microsoft
Dynamics GP, external applications, and web pages that are important to their role.
Commands you have defined can be used as Quick Links to provide access to
windows in your integration.

Refer to Part 11, Script The AddQuickLink procedure of the syHomePageQuickLinks form is used to add
Reference, for a quick links to a Home Page template. You will use this command in the trigger
complete description processing procedure that adds Home Page items for your integration.
of the procedure.
The following example is a portion of the IG_HomePage_SetupRoles trigger
processing procedure that runs when a new Home Page is created for a user. The
AddQuickLink procedure is called to add a link that opens the Lead Maintenance
window in the sample.

in integer iIndustry;
in integer iUserRole;

local string sUserID;

sUserID = 'User ID' of globals;

{Add a QuickLink for all roles}


call AddQuickLink of form syHomePageQuickLinks,
sUserID,
QL_COMMAND of form syHomePageMain,
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
resourceid(form Command_IG_Sample),
IG_PROD_ID,
Window_GetMainWindowTitle(IG_PROD_ID, technicalname(form
➥ IG_Lead_Maintenance)),
"","","",0,0,0,0,0;

414 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

Adding reports
The My Reports section on a Home Page allows users to easily access any reports
they have added to their “My Reports” list. Any reports in your application that
you have added to the Report List will be available for users to add to their Home
Page. Refer to Chapter 31, “Report Lists,” for information about adding to the
Report List.

It’s possible to add reports to the Home Page template for a role, but we suggest
that you limit the number of reports that you add. The “My Reports” list is designed
to be customized by the user, and shouldn’t be filled with reports that the user
won’t access regularly.

If you do add reports to the Home Page template for a role, adding simple reports
without report options may be the best choice. Reports that have report options
may not be defined at the time the reports are added to the Home Page template.

Refer to Part 11, Script The AddMyReport() function is used to add reports to a Home Page template. The
Reference, for a following example is the IG_HomePage_SetupReports trigger processing procedure
complete description for the sample integrating application. This script runs in response to the user
of this function. choosing to add reports for the Customer Service or Operations Manger role. It
adds the Leads simple report to the user’s My Reports list.

in integer iUserRole;

local syReportData RptData;

{Add a simple report for all roles}


RptData:'Report Type' = REPORTTYPE_SIMPLE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = IG_PROD_ID;
RptData:'Report Series ID' = 1;
RptData:'Report ID' = ReptID_LeadsSimple;
RptData:'Report Option Name' = "Leads";
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);
RptData:'User ID' = 'User ID' of globals;
RptData:'My Report Name' = "Leads";

AddMyReport(RptData) of form syMyReportsObj;

Metric overview
Metrics provide a graphical view of key data that is relevant to a specific role. Two
technologies are used to display metrics:

• SQL Server Reporting Services (SSRS)


• Office Web Components (OWC)

In a default installation of Microsoft Dynamics GP, the OWC metrics are displayed
on the home page. If SQL Server Reporting Services are deployed for Microsoft
Dynamics GP, then SSRS reports are used for the metrics.

Beginning with Microsoft Dynamics GP 2010 R2, the ability to configure which type of
metric you use has changed. After you deploy SSRS reports for Microsoft Dynamics GP, you
must use SSRS reports for the metrics on the home page.

INTEGRATION GUIDE 415


PA RT 8 AP P LI C A TI O N S E R V IC E S

SSRS metrics
The SSRS metrics are based on Microsoft SQL Server Reporting Services (SSRS)
reports that you create using tools like SQL Server Business Development Studio.
The user can select which SSRS reports they want to display as metrics in Microsoft
Dynamics GP.

Size
The space available for the metric on the home page is limited. Be sure that your
metric can fit within the area, and still be readable.

Location
When you deploy your SSRS reports to the Report Server, be sure that they are
placed in the correct location so that they can be found. The SSRS report must be
deployed to this location:

/company/series/Charts And KPIs/

Replace company and series with the company database name and the series name.
For example, if you were deploying sales-related reports for the sample company,
you would deploy reports to this location:

/TWO/Sales/Charts And KPIs/

OWC metrics
The chart control available with the Office Web Components (OWC) is used to
display the OWC metric data. Information displayed by the metric typically comes
from SQL queries issued to retrieve data from the application’s tables.

Metric ID
Each metric you create for your product must have a unique integer ID. We
recommend that you create a constant for this ID. For example, the constant
METRIC_TOP5LEADS represents the unique ID for a metric in the sample
integrating application.

Metric chart
The chart for a metric has several characteristics that define how it displays data.
Each chart can have the following:

Chart type The type of chart to display. Constants for the various chart types are
available in Dexterity. Refer to OWC Metric chart reference on page 424 for a complete
list of the chart types supported.

Name The chart name is displayed at the top of the chart.

Category label The category label is displayed at the bottom of the chart,
describing the categories of data being charted.

Data categories Up to 12 categories of data can be displayed by the chart.

Value label The value label is displayed on the left side of the chart, describing
the values that are being charted.

416 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

Data series with labels Up to 10 data series can be displayed on a chart, along
with labels for each series.

Legend A chart legend that describes each series is shown when the first data
series displayed on the chart has a label provided for it.

The following illustration shows a chart for a metric. The characteristics of the chart
are indicated by the labels applied.

Metric procedure
A separate procedure is used to retrieve the data used to generate the metric.
Typically, pass-through SQL is used to retrieve the data from the application’s
tables. This data is passed back to the Home Page through parameters required for
the metric procedure. You will learn more about this in Writing an OWC metric
procedure on page 421.

Displaying a metric
Each metric that a user adds to their Home Page is processed (data is retrieved)
when the Home Page is loaded or refreshed. The first metric in the user’s list of
metrics is displayed on the page. Other metrics are displayed when the user chooses
them from the list.

Creating OWC metrics


Several scripts and triggers are required when creating and displaying a metric on a
user’s Home Page. This portion of the documentation describes them.

Adding a metric
Refer to Part 11, Script The AddMetric procedure of the syHomePageMetric form is used to add metrics to
Reference, for a a Home Page template. You will use this command in the trigger processing
complete description procedure that adds Quick Links and metrics for your integration.
of this procedure.
The following example is a portion of the IG_HomePage_SetupRoles trigger
processing procedure that runs when a new Home Page is created for a user. The
AddMetric procedure is used to add the “Top 5 Leads” metric to the Home Page.

INTEGRATION GUIDE 417


PA RT 8 AP P LI C A TI O N S E R V IC E S

in integer iIndustry;
in integer iUserRole;

local string sUserID;

sUserID = 'User ID' of globals;

{Add a Metric for the Operations Manager}


if iUserRole = ROLE_OPSMGR then
call AddMetric of form syHomePageMetric,
sUserID,
IG_PROD_ID,
METRIC_TOP5LEADS;
end if;

Metric name
The name for a metric is maintained separately from the metric. You must add a
global procedure named MetricGetName that will be called each time the metric’s
name is displayed. Based on the Metric ID passed into the procedure, the
appropriate metric name should be returned. The procedure must have the
following parameters:
inout string sMetricName;
in 'Metric ID' iMetricID;
in DictID iDictID;

The following example is the MetricGetName procedure for the sample integrating
application. It returns the name of the metric defined for the sample.

inout string sMetricName;


in 'Metric ID' iMetricID;
in DictID iDictID;

{Retrieve metric names}


if iDictID = IG_PROD_ID then
if iMetricID = METRIC_TOP5LEADS then
sMetricName = "Top 5 Leads";
end if;
end if;

Metric security
Since metrics can display sensitive data, it’s important to secure them so only
authorized users can view their content. To control access to metrics, you must add
a global procedure named MetricHasAccess to your application. Based on the
Metric ID passed in, this procedure must determine whether the current user has
access. Typically, the procedure will examine security settings for forms that access
the same data as the metric. It will return true if the user has access to those forms,
or false if they don’t. The procedure must have the following parameters:
inout boolean bAccess;
in 'Metric ID 'iMetricID;
in DictID iDictID;

418 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

The following example is the MetricHasAccess procedure for the sample


integrating application. It uses the Security() function in Microsoft Dynamics GP to
determine whether the current user has access to the Lead Maintenance or Lead
Inquiry forms. If the user has access, the value true is returned to indicate the user
has access to the metric.
inout boolean bAccess;
in 'Metric ID 'iMetricID;
in DictID iDictID;

local integer security_result;


local integer prod_id;

prod_id = IG_PROD_ID;

{Does the user have access to the underlying metric data?}


if iDictID = IG_PROD_ID then
if iMetricID = METRIC_TOP5LEADS then
{Check the maintenance form for access}
security_result = Security(prod_id, FORMTYPE, resourceid(form
➥ IG_Lead_Maintenance));

if security_result = REJECT_RECORD then


{Check the inquiry form for access}
security_result = Security(prod_id, FORMTYPE,
➥ resourceid(form IG_Lead_Inquiry));

if security_result = REJECT_RECORD then


bAccess = false;
else
bAccess = true;
end if;
else
{User has access}
bAccess = true;
end if;
end if;
end if;

INTEGRATION GUIDE 419


PA RT 8 AP P LI C A TI O N S E R V IC E S

Executing a metric
When a Home Page is loaded or refreshed, Microsoft Dynamics GP will execute all
of the metrics that have been added to that page. To execute the metrics you have
defined for your integration, you must add a global procedure named
MetricExecute to your application. This procedure will be called, and the ID of the
metric to execute will be passed in. The procedure must gather the data required for
the metric and return it through the following set of required parameters:

in 'Metric ID' iMetricID;


in DictID iDictID;
inout integer iNumCategories;
inout integer iNumSeries;
inout string sChartType;
inout string sCategories[12];
inout string sSeriesName[10];
inout string sCategoryAxis;
inout string sValueAxis;
inout currency iSeries1Values[12];
inout currency iSeries2Values[12];
inout currency iSeries3Values[12];
inout currency iSeries4Values[12];
inout currency iSeries5Values[12];
inout currency iSeries6Values[12];
inout currency iSeries7Values[12];
inout currency iSeries8Values[12];
inout currency iSeries9Values[12];
inout currency iSeries10Values[12];

The MetricExecute procedure will call the appropriate procedure specific to the
metric to be run. This metric-specific procedure will gather the data for the metric
and return it to the MetricExecute procedure through the inout parameters.

For example, the following is the MetricExecute global procedure for the sample
integrating application. The Microsoft Dynamics GP application will call the
MetricExecute procedure, requesting that the “Top 5 Leads” metric be processed. In
turn, the MetricExecute procedure calls the Metric_Top5Leads procedure which
actually assembles the data for the metric and passes it back to MetricExecute. (You
will learn more about this procedure in Writing an OWC metric procedure on
page 421.)

in 'Metric ID' iMetricID;


in DictID iDictID;
inout integer iNumCategories;
inout integer iNumSeries;
inout string sChartType;
inout string sCategories[12];
inout string sSeriesName[10];
inout string sCategoryAxis;
inout string sValueAxis;
inout currency iSeries1Values[12];
inout currency iSeries2Values[12];
inout currency iSeries3Values[12];
inout currency iSeries4Values[12];
inout currency iSeries5Values[12];
inout currency iSeries6Values[12];
inout currency iSeries7Values[12];

420 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

inout currency iSeries8Values[12];


inout currency iSeries9Values[12];
inout currency iSeries10Values[12];

local long nStatus;

{Is it our metric to process?}


if iDictID = IG_PROD_ID then
if iMetricID = METRIC_TOP5LEADS then
call Metric_Top5Leads,
iNumCategories,
iNumSeries,
sChartType,
sCategoryAxis,
sValueAxis,
sCategories,
iSeries1Values;
end if;
end if;

Notice that only the parameters used for the metric must be passed to the metric procedure.
For instance, since only one series is plotted by the “Top 5 Leads” metric, only one series
data array is passed.

Writing an OWC metric procedure


Each metric should have its own procedure that gathers the data for the metric and
returns the results to be displayed on the user’s Home Page. You can use any
approach to gather the data for the metric. Most metric procedures will use pass-
through SQL to gather the data. Pass-through SQL provides the following
advantages:

• Data in all tables can be accessed

• Querying capabilities of SQL Server are useful for metrics, such as “order by”
and “top” clauses.

Tools like Query Analyzer provided with SQL Server can be used to refine the query before
using it in the sanScript procedure. This will save time as you develop your metrics.

Guidelines
When writing your metric procedure, consider the following guidelines:

• Make any SQL query you use as efficient as possible. The metric will be run
each time the Home Page is loaded or refreshed, so a slow query will make the
application less responsive.

• Always close any pass-through SQL connections you open to avoid wasting
system resources. Consider using the SQL_GetConnection() function of the
XSQLExec form in Microsoft Dynamics GP to retrieve and use the pass-through
SQL connection already maintained by the Microsoft Dynamics GP application.

INTEGRATION GUIDE 421


PA RT 8 AP P LI C A TI O N S E R V IC E S

Example
The following example is the metric procedure for the “Top 5 Leads” metric in the
sample integrating application. The global procedure is named Metric_Top5Leads.
It is called by the MetricExecute global procedure, uses pass-through SQL to
assemble the data for the metric, and returns the data through the inout parameters
for the procedure.
inout integer iNumCategories;
inout integer iNumSeries;
inout string sChartType;
inout string sCategoryAxis;
inout string sValueAxis;
inout string sCategories[12];
inout currency iSeries1Values[12];

local string sDbName;


local long SQL_connection;
local long SQL_status;
local integer index;
local text SQL_Statements;

{Chart Information}
sChartType = CHART_TYPE_COLUMNCLUSTERED;

sCategoryAxis = "Leads";
sValueAxis = "Potential Revenue";
iNumSeries = 1;
iNumCategories = 5;

{Retrieve the current company's database}


sDbName = 'Intercompany ID' of globals;

if 'SQL Server' of globals > 0 then


{Connect to the SQL data source. Use the connections already
maintained by the core application.}
SQL_status = SQL_GetConnection(FOREGROUND, SQL_connection) of form
➥ XSQLExec;
if SQL_status = OKAY then
{Build SQL statement to use the appropriate database.}
SQL_Statements = "use " + sDbName;

{Execute the SQL statements.}


SQL_status = SQL_Execute(SQL_connection, SQL_Statements);
end if;

{SQL query to use}


SQL_Statements = "select top 5 LeadName, PotentialRevenue from
➥ IG001 order by PotentialRevenue desc";
{Execute the SQL statements.}
SQL_status = SQL_Execute(SQL_connection, SQL_Statements);
if SQL_status = 0 then
index = 1;
{Retrieve data from the first results set.}
SQL_status = SQL_FetchNext(SQL_connection);
while SQL_status <> 31 do

422 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

{Get the information about the top leads.}


SQL_status = SQL_GetData(SQL_connection, 1,
➥ sCategories[index]);
SQL_status = SQL_GetData(SQL_connection, 2,
➥ iSeries1Values[index]);

index = index + 1;

SQL_status = SQL_FetchNext(SQL_connection);
end while;

{Clear the results sets and errors.}


SQL_status = SQL_Clear(SQL_connection);
end if;
end if;

Making OWC metrics available


With the Metric Details window, a user can select which metrics they want to add to
their Home Page. You will want any metrics you create to be listed in this window.
To make your metrics available for selection, you must register a procedure trigger
for the LoadAvailableMetrics procedure of the syHomePageMain form. The
following is a portion of the Startup script for the sample integrating application. It
registers a procedure trigger that will make the metrics available in the Metric
Details window.

l_result = Trigger_RegisterProcedure(script LoadAvailableMetrics of


➥ form syHomePageMain, TRIGGER_AFTER_ORIGINAL, script
➥ IG_HomePage_LoadAvailableMetrics);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

The trigger processing procedure that runs in response to trigger must do the
following:

• Check the security access for each of your metrics you want to add to the list.
You can use the MetricHasAccess procedure that you have already added to
your application.

• If the user has access, the metric’s name must be retrieved. You can use the
MetricGetName procedure that you already added to your application.

• Verify that the metric hasn’t already been added to the list. If it hasn’t, the
metric can be added.

INTEGRATION GUIDE 423


PA RT 8 AP P LI C A TI O N S E R V IC E S

The following is the trigger processing procedure that makes the “Top 5 Leads”
metric available in the Metric Details window. The metric list uses the list view
control, so ListView functions are used to add the item. Notice how two additional
subitems are added to the list view to keep track of the product ID and metric ID.

local boolean bAccess;


local long nItemIndex;
local string sName;

{ Top 5 Leads }
call MetricHasAccess, bAccess, METRIC_TOP5LEADS, IG_PROD_ID;
if bAccess then
call MetricGetName, sName, METRIC_TOP5LEADS, IG_PROD_ID;
if empty(sName)= false then
if not ExistsforMetricID('User ID' of globals,
➥ METRIC_TOP5LEADS, IG_PROD_ID) of form syHomePageMetric then
nItemIndex = ListView_ItemAdd('(L) AvailableMetrics' of
➥ window MetricCustomize of form syHomePageMain, sName, 0);
ListView_ItemSetIntSubitem('(L) AvailableMetrics' of
➥ window MetricCustomize of form syHomePageMain,
➥ nItemIndex, COL_DICTID of form syHomePageMain, IG_PROD_ID);
ListView_ItemSetIntSubitem('(L) AvailableMetrics' of
➥ window MetricCustomize of form syHomePageMain,
➥ nItemIndex, COL_METRICID of form syHomePageMain,
➥ METRIC_TOP5LEADS);
end if;
end if;
end if;

OWC Metric chart reference


The following table lists the chart types available for metrics and and the
corresponding constants for them. The 3D chart types are available only if you have
the 2003 version of the Office Web Components.

Category Example Type Constant


Bar Bar clustered CHART_TYPE_BARCLUSTERED
Bar clustered 3D CHART_TYPE_BARCLUSTERED3D
Bar 3D CHART_TYPE_BAR3D
Bar stacked CHART_TYPE_BARSTACKED
Bar stacked (total to 100%) CHART_TYPE_BARSTACKED100
Bar stacked 3D CHART_TYPE_BARSTACKED3D
Bar stacked 3D (total to 100%) CHART_TYPE_BARSTACKED1003D
Column Column clustered CHART_TYPE_COLUMNCLUSTERED
Column clustered 3D CHART_TYPE_COLUMNCLUSTERED3D
Column 3D CHART_TYPE_COLUMN3D
Column stacked CHART_TYPE_COLUMNSTACKED
Column stacked (total to 100%) CHART_TYPE_COLUMNSTACKED100
Column stacked 3D CHART_TYPE_COLUMNSTACKED3D
Column stacked 3D (total to 100%) CHART_TYPE_COLUMNSTACKED1003D

424 IN T E G R AT I O N G U ID E
C H A P T E R 3 7 H O M E P AG E S

Category Example Type Constant


Line Line CHART_TYPE_LINE
Line markers CHART_TYPE_LINE_MARKERS
Line 3D CHART_TYPE_LINE3D
Line overlapped 3D CHART_TYPE_LINEOVERLAPPED3D
Line stacked CHART_TYPE_LINESTACKED
Line stacked markers CHART_TYPE_LINESTACKEDMARKERS
Line stacked (total to 100%) CHART_TYPE_LINESTACKED100
Line stacked markers (total to 100%) CHART_TYPE_LINESTACKED100MARKERS
Line stacked 3D CHART_TYPE_LINESTACKED3D
Line stacked 3D (total to 100%) CHART_TYPE_LINESTACKED1003D
Smooth Line Smooth line CHART_TYPE_SMOOTHLINE
Smooth line markers CHART_TYPE_SMOOTHLINEMARKERS
Smooth line stacked CHART_TYPE_SMOOTHLINESTACKED
Smooth line stacked markers CHART_TYPE_SMOOTHLINESTACKEDMARKERS
Smooth line stacked (total to 100%) CHART_TYPE_SMOOTHLINESTACKED100
Smooth line stacked markers (total to 100%) CHART_TYPE_SMOOTHLINESTACKED100MARKERS
Area Area CHART_TYPE_AREA
Area stacked CHART_TYPE_AREASTACKED
Area stacked (total to 100%) CHART_TYPE_AREASTACKED100
Area 3D CHART_TYPE_AREA3D
Area overlapped 3D CHART_TYPE_AREAOVERLAPPED3D
Area stacked 3D CHART_TYPE_AREASTACKED3D
Area stacked 3D (total to 100%) CHART_TYPE_AREASTACKED1003D
Pie Pie CHART_TYPE_PIE
Pie exploded CHART_TYPE_PIEEXPLODED
Pie stacked CHART_TYPE_PIESTACKED
Pie 3D CHART_TYPE_PIE3D
Pie exploded 3D CHART_TYPE_PIEEXPLODED3D
Radar Radar line CHART_TYPE_RADARLINE
Radar line filled CHART_TYPE_RADARLINEFILLED
Radar line markers CHART_TYPE_RADARLINEMARKERS
Radar smooth line CHART_TYPE_RADARSMOOTHLINE
Radar smooth line markers CHART_TYPE_RADARSMOOTHLINEMARKERS
Doughnut Doughnut CHART_TYPE_DOUGHNUT
Doughnut exploded CHART_TYPE_DOUGHNUTEXPLODED

INTEGRATION GUIDE 425


426 IN T E G R AT I O N G U ID E
Chapter 38: Setup Checklist
The Setup Checklist provides a central access point for setup tasks in Microsoft
Dynamics GP. If you have any setup tasks that must be performed for your
integration, you should consider adding them to the Setup Checklist.

Information about integrating with Setup Checklist is divided into the following
sections:

• Setup Checklist overview


• Setup Checklist structure
• Adding to Setup Checklist
• Help for Setup Checklist items

Setup Checklist overview


If your integrating application has setup steps that should be performed before the
application can be used, you should create setup windows for it. Setup tasks
include specifying default values or selecting proccessing options. Some setup tasks
will be required before the application can be used, while others may be optional.
Traditionally, setup tasks are available throughthe Setup menu.

The Setup Checklist provides a single location to access the setup tasks in Microsoft
Dynamics GP. Setup for a large application like Microsoft Dynamics GP can be an
involved process, so the Setup Checklist window provides features to assign setup
tasks to specific users and track the setup progress. A special HTML Help pane
displays online help information for each setup task as it is completed.

Some setup tasks are


required. Others are optional.

By integrating with the Setup Checklist, the setup for your application can utilize
these features.

INTEGRATION GUIDE 427


PA RT 8 AP P LI C A TI O N S E R V IC E S

Setup Checklist structure


The Setup Checklist has two types of items:

• Setup Checklist Categories


• Setup Checklist Items

An integrating application can add both types of items. The categories in the Setup
Checklist correspond to command lists in the application. The individual items
correspond to commands in the application that are used to open setup windows.
The items in each category should be listed in the suggested order that the setup
tasks be performed.

Setup Checklist categories


group related items.

Each Setup Checklist item


opens a setup window.

Each node in the Setup Checklist tree is uniquely identified by the following:

Dictionary ID This is the ID of the dictionary that contains the command used
for the category or item.

Command Form ID This is the resource ID of the form that contains the
command used for the category or item.

Command ID This is the resource ID of the command used for the category or
item.

Top-level node
The constant SETUPCHECKLIST_TOPLEVEL is used to specify the dictionary ID,
command form ID, and command ID of the top-level node in the Setup Checklist
tree. This node isn’t visible in the tree. You will use this constant when adding items
that appear in the first level of the tree.

First-level nodes
The core set of first-level nodes displayed in the Setup Checklist tree use the same
command list definitions as the Setup submenu that appears in the Tools menu.

428 IN T E G R AT I O N G U ID E
C H A P T E R 3 8 S ET U P C HE C K L IS T

The following table provides information about these command lists.

Category Command form Command


System Command_System CL_System_Setup
Company Command_System CL_Company_Setup
Financial Command_Financial CL_Financial_Setup
Posting Command_System CL_Posting_Setup
Purchasing Command_Purchasing CL_Purchasing_Setup
Inventory Command_Inventory CL_Inventory_Setup
Sales Command_Sales CL_Sales_Setup
Payroll Command_Payroll CL_Payroll_Setup

This is a list of the first-level nodes added by the core Microsoft Dynamics GP application.
Other integrating products may have added first-level nodes to the Setup Checklist tree.

Adding to Setup Checklist


To add items to the Setup Checklist, you will create commands for the items to be
displayed, register a trigger for the procedure that adds items to the Setup
Checklist, and write a trigger processing procedure to add the items.

Creating commands
Create a command or command list for each item or category you want to add to
the Setup Checklist. If you already created commands that you added to the Setup
menu, you can re-use those same commands for the Setup Checklist.

Registering the trigger


To add items to the Setup Checklist, you must register a procedure trigger for the
CreateSetupChecklist procedure in Microsoft Dynamics GP. This procedure is run
each time Microsoft Dynamics GP is launched. The following example from the
sample integrating application shows the registration for this trigger. When the
trigger is activated, the IG_CreateSetupChecklistItems procedure is run.

l_result = Trigger_RegisterProcedure(script CreateSetupChecklist,


➥ TRIGGER_AFTER_ORIGINAL, script IG_CreateSetupChecklistItems);
if l_result <> SY_NOERR then
warning "Procedure trigger registration failed.";
end if;

Trigger processing procedure


Before the processing procedure adds Setup Checklist items, it must first verify that
the items for the integration haven’t already been added. If the items haven’t been
added, the AddSetupChecklistItem() function is used to add them. You can also
use the FindSetupChecklistItem() function to retrieve the location of existing items
in the Setup Checklist. This is useful when adding items to specific locations in the
tree.

The following is the trigger processing procedure that adds Setup Checklist items
for the sample integrating application. Notice how a range is set up to determine
whether Setup Checklist items have been added previously. If they haven’t, items
are added. The FindSetupChecklistItem() function is used to locate the
“Customer” item in the Sales category of the tree. The item is added in the position
following the Customer item.

INTEGRATION GUIDE 429


PA RT 8 AP P LI C A TI O N S E R V IC E S

local integer status;


local integer seq;

{Examine whether the Setup Checklist items have already been added}
range clear table sySetupChecklistMstr;
range table sySetupChecklistMstr where physicalname(CmdDictID of table
➥ sySetupChecklistMstr) + "=" + str(IG_PROD_ID);
get first table sySetupChecklistMstr;

if err() = EOF then

{Find the Customers item}


seq = FindSetupChecklistItem(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command RM_Customer_Maintenance of form Command_Sales)) of
➥ form sySetupChecklistObj;

{Add the new item after the Customers item}


seq = seq + 1;

{Add the Contact History Setup item}


status = AddSetupChecklistItem(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History_Setup of form
➥ Command_IG_Sample),
technicalname(window Contact_History_Setup of form
➥ IG_Contact_History_Setup),
false,
"IG_CHM_NAME",
"ContactHistorySetup.htm") of form sySetupChecklistObj;
end if;

Refer to the description of the AddSetupChecklistItem() for more examples that


show how to add items to the Setup Checklist.

430 IN T E G R AT I O N G U ID E
C H A P T E R 3 8 S ET U P C HE C K L IS T

Help for Setup Checklist items


Every item you add to the Setup Checklist should have a corresponding entry in the
HTML Help file you have created for your product. When the user selects an item in
the Setup Checklist tree, the help topic for that item will be displayed in the Setup
Guide, which is a docked help pane within the application.

When an item is selected,


help for the item is
displayed in the Setup
Guide.

Help file name


To specify the help file name, you must create a constant in your application
dictionary that contains the name of the compiled HTML Help file from which you
want to display topics. You will use this constant in the code that adds items to the
Setup Checklist. For example, the following constant is defined in the sample
integrating application.

Be sure the constant value ends with the .chm extension.

Topic to display
Your code indicates the topic to display by supplying the AddSetupChecklistItem()
function with the complete HTML filename of the topic. Be sure that the name
includes the .htm extension. For example, the topic to display for the Contact
History setup item is “ContactHistorySetup.htm”.

You can’t use a help context number to specify the topic to display, because the specific
HTML Help API being used for the Setup Checklist doesn’t support it.

INTEGRATION GUIDE 431


PA RT 8 AP P LI C A TI O N S E R V IC E S

Topic guidelines
Be aware that the docked HTML Help pane used for the Setup Guide is narrow. Try
to design the help topics to work well in this narrow pane that has limited space.

• Don’t use unnecessary text andkeep the topic as short as possible. Long topics
require scroll bars to be displayed, taking up more screen space.

• Avoid HTML items that cause a lot of horizontal scrolling, such as wide tables
or graphics.

Setup topics for windows in Microsoft Dynamics GP use a special framset to


display information in the Setup Guide. The sample integrating application also
uses this frameset to display information for the Contact History Setup window.
You can examine the ContactHistorySetup.htm file in the sample integrating
application help source to see how this frameset topic is designed. You may want to
use a similar approach for your Setup Checklist help topics.

432 IN T E G R AT I O N G U ID E
Chapter 39: Online Help
Before implementing Microsoft Dynamics GP uses Microsoft HTML Help to display information online.
help for an integrating How you implement help for integrating applications is very similar to how you
application, be sure to implement help for stand-alone Dexterity applications. Therefore, this information
review Dexterity’s will focus primarily on issues that are specific to third-party applications that
online help capabilities integrate with Microsoft Dynamics GP. It includes the following information:
described in Chapter 8,
“HTML Help,” in the • Third-party help responsibilities
Stand-Alone • Using the Microsoft Dynamics GP help model
Application Guide. • Implementing a help system
• Writing a help processing procedure
• Registering the help processing procedure
• Help button
• Creating help source files
• Help issues for integrating applications

The information provided also assumes that you’ll support online help in a manner
similar to Microsoft Dynamics GP. This includes providing window-level context-
sensitivity, and implementing a similar appearance.

Third-party help responsibilities


There are three areas to consider when implementing help: alternate windows,
third-party windows, and alert message dialogs.

Alternate windows
If you distribute alternate windows in your application, the Microsoft Dynamics GP
help system will continue to provide help for the window and all fields originally
displayed in the window. However, your application’s help system will be
responsible for providing field help for all global and local third-party fields you’ve
added.

Third-party windows
Your application’s help system is responsible for displaying help topics for your
windows. This includes any third-party fields added to the window, and any
Microsoft Dynamics GP fields added to the window.

Alert message dialogs


If you choose to, you can implement alert message dialog help in your application.
You can add a Help button to message dialogs displayed by the ask(), getstring(),
error and warning commands. Clicking the Help button starts the help engine and
displays a help topic relating to the message displayed in the modal dialog.

Due to limitations in determining the active application, we recommend that you don’t
implement help for alert message dialogs that are generated from procedure or function
scripts.

INTEGRATION GUIDE 433


PA RT 8 AP P LI C A TI O N S E R V IC E S

Using the Microsoft Dynamics GP help model


The Microsoft Dynamics GP help “model” is the specific implementation of HTML
Help used for Microsoft Dynamics GP, encompassing the user interface for the help
system. Using this help model will make your application look like an integral part
of the system.

To see this model, examine the Develop.chm sample help file included with
Dexterity. For detailed information about the help model, examine the
DevelopHelpSample.zip archive. This archive contains the source files used to
create the sample help file. You can use these source files in the help file for your
application to reproduce the look and feel of the Microsoft Dynamics GP help.

Pay special attention to the GP.css file, which is the cascading style sheet used to
format the information displayed in the help file. This is the same style sheet used to
format Microsoft Dynamics GP help. You can use this cascading style sheet directly
in your help file. You may also choose to create your own style sheet based on the
styles defined in the GP.css style sheet.

Implementing a help system


The following checklist describes a method for implementing help for an
integrating application:

1. Complete your application development.


Typically, you’ll develop your help system after you’ve completed all
development tasks within your development dictionary. With most of your
application complete, there’s less chance of resource IDs changing. Resource
IDs must remain unchanged after you’ve generated help files for context-
sensitivity to work properly.

2. Write a help processing procedure.


Your application will use a help processing procedure to acquire the context ID
of a window, and display the appropriate help topic. The main product
(Microsoft Dynamics GP) and all Dexterity applications that integrate with it
must each use their own help processing procedure. You can find more
information about this subject in Writing a help processing procedure on page 435.

3. Register the procedure.


Your application must also specify which procedure will be used for the help
processing procedure. You can find more information about this subject in
Registering the help processing procedure on page 436.

4. Create help source files.


The information in a help file comes from several different source files. Most of
these source files will be produced by the tool you choose for your help
authoring. Other source files will come from CHAMP, a tool included with
Dexterity. The section titled Creating help source files on page 437 explains the
various source files you will use.

5. Compile the source files to produce the .chm file.


You will use the HTML Help Workshop to create the compiled help file for use
with your application.

434 IN T E G R AT I O N G U ID E
C H A P T E R 3 9 O N L I N E H E L P

6. Test the compiled help file.


Be sure to test the help file in a multidictionary environment using your
extracted application and the same Dynamics.dic dictionary used by your
customers.

Writing a help processing procedure


All Dexterity applications that integrate with Microsoft Dynamics GP each must
have separate help processing procedures. The help processing procedure
ascertains what kind of help the user wants, then issues the appropriate commands
to display that help.

The runtime engine automatically calls the appropriate help processing procedure,
depending on whether the user chooses a third-party or main application item:

Form type Item Processing procedure


Microsoft Dynamics GP Microsoft Dynamics GP window fields Microsoft Dynamics GP
form
Microsoft Dynamics GP window Microsoft Dynamics GP
Third-party window fields Third-party
New local fields Third-party
Additional third-party window and all Third-party
associated window fields.
Third-party form Third-party window fields Third-party
Microsoft Dynamics GP window fields Third-party
Third-party windows Third-party

The following script is the help processing procedure for the sample integrating
application:
{--------------------------------------------------------------
Script name: IG_Help_Processing
Description: Processes online help for the sample application.
--------------------------------------------------------------}
local integer help_type, result;
local long context_number;
local string help_path_and_file;

{Return the location of the current dictionary.}


help_path_and_file = Dict_GetPathname(2);

{Set the complete path to the help file.}


help_path_and_file = help_path_and_file + "DEVELOP.CHM";

{Get the help type for the current situation.}


help_type = WinHelp_GetHelpType();

case help_type
in [HELP_TYPE_WHATS_THIS_MODE, HELP_TYPE_HELP_KEY,
➥ HELP_TYPE_WHATS_THIS_WIN]
{Get the context number for the current window.}
context_number = WinHelp_GetWindowContextNumber();
{Call the help engine, displaying the help for the window.}
result = WinHelp_InvokeHelp(help_path_and_file,
➥ HELP_CMD_CONTEXT, context_number);

INTEGRATION GUIDE 435


PA RT 8 AP P LI C A TI O N S E R V IC E S

in [HELP_TYPE_DIALOG_HELP]
{Process the help for modal dialogs.}
{Get the context number for the item chosen.}
context_number = WinHelp_GetFieldContextNumber();
{Call the help engine, displaying help for the modal dialog.}
result = WinHelp_InvokeHelp(help_path_and_file,
➥ HELP_CMD_CONTEXT, context_number);
in [HELP_TYPE_CONTENTS]
{Invoke the Contents topic.}
result = WinHelp_InvokeHelp(help_path_and_file,
➥ HELP_CMD_CONTENTS, 0);
in [HELP_TYPE_SEARCH]
{Invoke the search engine.}
result = WinHelp_Search(help_path_and_file, "");
else
{Invoke the Contents topic.}
result = WinHelp_InvokeHelp(help_path_and_file,
➥ HELP_CMD_CONTENTS, 0);
end case;

Registering the help processing procedure


You must specify which procedure script will be used for the help processing
procedure. Use the WinHelp_RegisterHelpProcedure() function from the WinHelp
function library to do this. For applications that integrate with Microsoft Dynamics
GP, you specify the help processing procedure in the Startup procedure script.

Be sure you use the WinHelp_RegisterHelpProcedure() function to specify the help


processing procedure. If you don’t, your application won’t be able to process help.

The following is part of the Startup procedure for the sample integrating
application:

l_result = WinHelp_RegisterHelpProcedure(script IG_Help_Processing);


if l_result <> 0 then
error "An error occurred. Unable to register help processing
➥ procedure.";
end if;

Help button
Most windows in Microsoft Dynamics GP contain a Help button that appears in the
lower-right or lower-left corner of the window. Clicking this button performs the
same action as choosing About This Window from the Help menu.

If you provide online help for a window, be sure the window has a visible Help
button. This provides a visual cue for the user, indicating that help is available. To
add a help button, complete the following procedure:

1. Add a Help button.


Add the global field named ‘WindowHelp’ to the window. Position the field in
the lower-left or lower-right corner, as appropriate.

Global field Control


WindowHelp

436 IN T E G R AT I O N G U ID E
C H A P T E R 3 9 O N L I N E H E L P

2. Set the following properties for the button.


Set the following Object properties for the field:

TabStop False
Tooltip Help About This Window (F1)

Set the following Visual properties for the field:

Appearance 3D Highlight
BackColor System - Button Face
Border True
Style Graphic Only

3. Attach a help button script.


Attach a change script to the help button similar to the following example. This
script will perform the same action as choosing About This Window from the
Help menu.
local boolean result;

result=Menu_Invoke(MENU_ACTION_HELPWINDOW);

Creating help source files


Once you’ve completed application development, you can create the source files for
your help file. The HTML Help compiler requires several types of files to create a
help file. The following table lists these files:

File Description
Help project file (.HHP) Contains information about how the help compiler generates the
help file. You may want to use the sample help project included in
the DevelopHelpSample.zip archive.
Contents file (.HHC) Contains the table of contents for the help file. This can be created
with the HTML Help Workshop, or with your help authoring
software.
Keyword file (.HHK) Contains the list of keywords for the help file. This can be created
with the HTML Help Workshop, or with your help authoring
software.
HTML content files (.HTM) Contains the help information, in HTML format. These are created
with your help authoring software.
Map file (.h) Contains a list of the context numbers and their corresponding help
alias entries. We recommend that you use the CHAMP tool included
with Dexterity to generate a map file for your integrating
application.
Alias file (.h) Contains a list of the values in the map file, and the corresponding
.htm file that contains the context-sensitive help information.
Cascading style sheet Describes the formatting that is applied to the .htm files displayed in
(.css) the compiled help file. We recommend that you use the GP.css style
sheet included in the DevelopHelpSample.zip archive.

Graphics files such as .GIFs are also typically part of a help file. You’ll create these graphics
files separately and reference them in the .htm files.

INTEGRATION GUIDE 437


PA RT 8 AP P LI C A TI O N S E R V IC E S

We recommend that you use CHAMP, the Context-sensitive Help Assistant and
Map Program, to create the map file for your integrating application. CHAMP is
included in the Samples directory that is installed with Dexterity. Refer to the
documentation included with CHAMP for more information about using this tool.

Help issues for integrating applications


The following sections describe issues you’ll need to consider before implementing
help.

Context-sensitivity
We recommend that you implement window-level context-sensitivity for your
integrating applications. Because of the large number of fields typically found in
Dexterity-based applications, field-level context-sensitivity quickly becomes
difficult to manage.

Alternate windows
Dexterity does not support context-sensitive help for a Microsoft Dynamics GP
global field you add to a Microsoft Dynamics GP window. We recommend that you
add a new local field to the Microsoft Dynamics GP window instead of adding a
Microsoft Dynamics GP global field.

Avoiding context ID conflicts


If you use Microsoft Dynamics GP fields on a third-party window, or add third-
party windows to a Microsoft Dynamics GP form, Dexterity may assign the same
context ID to a third-party field and a Microsoft Dynamics GP field in the same
window. This presents a problem, since the help system displays only a single help
topic for two different fields.

To avoid context ID conflicts in the situations listed above, set the UseUniqueHelp
property to True for all Microsoft Dynamics GP fields you use in your window.
Then be sure you set the UseUniqueHelp property to False for all of your fields.

438 IN T E G R AT I O N G U ID E
Chapter 40: Unified Communications
If either Microsoft Office Communicator or Microsoft Lync is running on the same
system as Microsoft Dynamics GP, the Microsoft Dynamics GP client can integrate
with some of the Unified Communications capabilities provided by Communicator
or Lync. Microsoft Dynamics GP can display presence information for specific
entities such as customers or vendors. Actions can be added to Communicator or
Lync to allow tasks to be performed within Microsoft Dynamics GP. Information
about integrating with Unified Communications is divided into the following
sections:

• Presence overview
• Adding presence support to a window
• Adding actions to Communicator or Lync

Presence overview
In Microsoft Dynamics GP, presence is supported for the following entities:

• Customer
• Vendor
• Employee
• Salesperson

Each of these entities can have a SIP (Session Initiation Protocol) address that is
used to allow multimedia connections over Internet Protocol. The SIP address is
specified in the Messenger Address field of the Internet Information window in
Microsoft Dynamics GP. When Microsoft Office Communicator or Microsoft Lync is
running on the same system an Microsoft Dynamics GP, the SIP address is used to
retrieve presence information for the entity.

Typically, presence information is displayed for fields in maintenance, inquiry, and


transaction entry forms. For example, the following illustration shows presence
information displayed for a salesperson in the Salesperson Maintenance window.

If your integration displays fields for which presence is supported, you can display
the presence indicator for those fields. You can also add presence support for your
own fields.

INTEGRATION GUIDE 439


PA RT 8 AP P LI C A TI O N S E R V IC E S

Adding presence support to a window


To add presence support to a window, you will add several predefined fields to the
window. Then you will add scripts to those fields.

Adding fields
To add the fields needed for presence support, complete the following steps:

1. Add the PresenceChangeEventTrigger field.


Add the global field named PresenceChangeEventTrigger as a hidden field on
the window. Set the following Object property for the field:

Editable False

Set the following Visual properties for the field:

BackColor Yellow
Visible False

2. Add Label_Presence fields.


Add an element of the global array field named Label_Presence_Button for each
field for which presence will be tracked. For example, if two fields in the
window will have presence tracked, add elements 1 and 2 of the Label_Presence
global field. Set the following Object property for each field:

Editable False

Set the following Visual properties for each field:

BackColor Yellow
Visible False

3. Add the PB_Presence_Button fields.


Add an element of the global array field named PB_Presence_Button for each
field for which presence will be tracked. For example, if two fields in the
window will have presence tracked, add elements 1 and 2 of the
PB_Presence_Button global field. Place the field to the left of the field for which
presence is being tracked. Set the following Object properties for each field:

SetChangeFlag False
TabStop False

Set the following Visual properties for each field:

Appearance 2D Border
Border False
Size-Height 18
Size-Width 18
Style TextOnly

440 IN T E G R AT I O N G U ID E
C H A P T E R 4 0 U N I F I E D C O M M U N I C A T I O N S

Attaching scripts
To add the scripts needed for presence support, complete the following steps:

1. Attach a change script to the PresenceChangeEventTrigger field.


This change script is used to reset the presence fields for the window. The script
handles the following cases:

• The field is set to -1 and the change script is run. In this case, all of the
presence triggers are unregistered.

• The field is set to the index of the presence indicator for a specific field and
the change script is run. In these cases, the presence trigger for only that
specific presence trigger is unregistered.

If the name of the form or window contains spaces, be sure to enclose the name in single
quotes. Otherwise, the presence fields cannot be accessed.

The following example shows this script for the Lead_Inquiry window in the
sample integrating application.

local string form_name;


local string window_name;

{Specify the technical name of the form and window that contains the
fields for which presence is being tracked.}
form_name = "IG_Lead_Inquiry";
window_name = "IG_Lead_Inquiry";

case PresenceChangeEventTrigger
in [-1]
{Unregister all of the presence triggers for the window}
call Unregister of form Dummy_Presence_Form, form_name,
➥ window_name, 1, Label_Presence[1], 'Salesperson ID',
➥ CO_INETADDRS_SALESPERSON, "", IG_PROD_ID;
in [1]
{Unregister a specific presence trigger for the window}
call Unregister of form Dummy_Presence_Form, form_name,
➥ window_name, 1, Label_Presence[1], 'Salesperson ID',
➥ CO_INETADDRS_SALESPERSON, "", IG_PROD_ID;
end case;

2. Attach a change script to each Label_Presence field.


This change script retrieves the SIP address associated with the entity, and
registers the presence field. The following example shows this script for the
Label_Presence field used for the Salesperson ID field in the Lead_Inquiry
window in the sample integrating application.

local string form_name;


local string window_name;

{Specify the technical name of the form and window that contains the
fields for which presence is being tracked.}
form_name = "IG_Lead_Inquiry";
window_name = "IG_Lead_Inquiry";

INTEGRATION GUIDE 441


PA RT 8 AP P LI C A TI O N S E R V IC E S

{Retrieve the SIP address for the salesperson and store it in the array
element}
Label_Presence[1] = GatherSIP(CO_INETADDRS_SALESPERSON, 'Salesperson ID',
➥ "");

{Register the presence trigger for the field}


call Register of form Dummy_Presence_Form, form_name, window_name, 1,
➥ Label_Presence[1], 'Salesperson ID', CO_INETADDRS_SALESPERSON, "",
➥ IG_PROD_ID;

3. Attach a change script to each PB_Presence field.


This change script performs the action the user chooses from the button drop
list. The following example shows this script for the presence indicator next to
the Salesperson ID field in the Lead Inquiry window in the sample integrating
application.

local string convo_title;

{Build the title to use for any conversation}


convo_title = 'Lead Name' + CH_SPACE + CH_DASH + CH_SPACE + 'Lead ID';

{Perform the action that was chosen from the button drop list}
call Activate of form Dummy_Presence_Form, "", "", 0, Label_Presence[1],
➥ convo_title, PB_Presence_Button[1], "", "", "", IG_PROD_ID;

4. Add presence support to the window pre script.


In the window pre script, you must register all of the presence fields for the
window. The following example shows the code that was added to the window
pre script for the Lead Inquiry window to register the presence fields.

{Clear and then register the presence fields for the window}
PresenceChangeEventTrigger = -1;
run script PresenceChangeEventTrigger;
run script Label_Presence[1];

5. Add presence support to the window post script.


In the window post script, you must unregister all of the presence fields for the
window. The following example shows the code that was added to the window
post script for the Lead Inquiry window to unregister the presence fields.

{Unregister the presence fields for the window}


PresenceChangeEventTrigger = -1;
run script PresenceChangeEventTrigger;

6. Add code to update presence when a different record is shown.


Each time a different record is shown, you must unregister the presence fields
and then reregister them so they can be updated based on the new data being
displayed. You will add code to do this in each place that can cause a new
record to be displayed. Common locations for this code are the change script for
the control field and the browse buttons for the window.

442 IN T E G R AT I O N G U ID E
C H A P T E R 4 0 U N I F I E D C O M M U N I C A T I O N S

The following example shows the portion of code added to the browse buttons
for the Lead Maintenance form in the sample integrating application to update
the presence when a new record is displayed.

{Update the presence status}


PresenceChangeEventTrigger = -1;
run script PresenceChangeEventTrigger;
run script Label_Presence[1];

7. Add code to update presence for individual fields (if required).


You may have presence indicators for fields that have their values set
individually, such as by using a lookup or typing a field value. If the field value
changes, you need to use the field change script to update the presence
indicator for the field.

The following example shows the code that was added to the change script for
the Salesperson ID field in the Lead Maintenance window of the sample
integrating application. This code updates the presence status for the new value
when the user changes the value of the Salesperson ID field.

{Update the presence status}


run script Label_Presence[1];

Adding actions to Communicator or Lync


The Microsoft Dynamics GP installer adds several actions to Communicator and
Lync that allow the user to perform actions in the Microsoft Dynamics GP client.
You can add your own actions to the Communicator or Lync client.

Defining an action
To add an action to Communicator or Lync, you must add a key containing several
values to the Windows Registry. To do this, complete the following steps:

1. Open the Windows Registry.


Using a tool like RegEdit, open the Windows Registry.

2. Create a new key.


In the registry, create a new key in the following location:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Communicator\Session
Manager\Apps\

3. Name the new key.


Supply the new key a with a GUID name similar to the other keys in this
location.

The name of the key is important. How this name sorts alphabetically with the other
GUID entries determines its position in the menus built by Communicator or Lync.

4. Define the values for the new key.


Add the following values to the new key:

ApplicationType A REG_DWORD value that specifies the protocol to use


for the action. For actions performed in Microsoft Dynamics GP, the Dynamics
GP Protocol handler is used, so this value is set to 1.

INTEGRATION GUIDE 443


PA RT 8 AP P LI C A TI O N S E R V IC E S

ExtensibleMenu A string value that specifies where the action will be


displayed in Communicator or Lync. Set this value to the following string:

MainWindowRightClick;ConversationWindowContextual

Name A string that specifies the name displayed for the action.

Path A string specifying the action to perform. Typically, this will be a call to
the Dynamics GP Protocol Handler. The following is an example of a call to the
protocol handler:

dgpp://UnifiedCommunications/Dynamics?ProductID=3333&ActionType=OPEN&
FunctionName=OpenNewLead&UserSIP=%user-id%

The call must begin with dgpp://UnifiedCommunications/Dynamics. The


query string (everything following the question mark) can contain whatever
name/value pairs are required so the action can be performed. For example,
you will want to pass a product ID and an indicator of the action to perform.
You can use the token %contact-id% to include the SIP address of the person
selected in Communicator. The token %user-id% can be used to include the SIP
address of the person performing the action.

SessionType A REG_DWORD value that should be set to 0 to indicate the


session will be local.

SmallIcon A string value that indicates the path of the icon to display. If the
icon can’t be found, a default icon is displayed. Two icons are included with
Microsoft Dynamics GP for the Unified Communication integration:

• NewDocument_16x16_72.png
• ViewRecord_16x16_72.png

These are found in this location for 32-bit systems:

C:\Program Files\Microsoft Dynamics\GP\Background\Images\

They are found in this location for 64-bit systems:

C:\Program Files (x86)\Microsoft Dynamics\GP\Background\Images\

Responding to the action


Typically, the Microsoft Dynamics GP Protocol Handler is used to perform an action
that is started from within Communicator or Lync. The code that performs the
action is contained in an add-in that is created with Visual Studio Tools. Refer to the
Visual Studio Tools Programmer’s Guide for general information about how to
create an add-in.

The Visual Studio Tools add-in that will respond to the action must reference the
Microsoft.Dynamics.GP.DrillBackWcfService assembly, found in the AddIns folder
of a Microsoft Dynamics GP installation.

In the Initialize() section of the add-in code, you will create a service instance. You
will also add an event handler to process static URI events. In the event handler,
you need to parse the query string that is passed in through the URL to determine
whether it is your action that needs to be processed. Special routines in the .NET
Framework can help you process the query string.

444 IN T E G R AT I O N G U ID E
C H A P T E R 4 0 U N I F I E D C O M M U N I C A T I O N S

The following C# code example is a Visual Studio Tools add-in that handles the
action for the sample integrating application. Note the following items in the code:

• The DrillBackService namespace is referenced, and used to create a service


instance.

• The static URI handler is created and implemented.

• In the event handler for the static URI, the query string from the URL is parsed
to retrieve the individual key values that were passed in.

• The key values are examined. If the product ID and operation match the
predefined values, then the operation to open the Lead Maintenance form is
run.

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.Dexterity.Bridge;
using Microsoft.Dexterity.Applications;
using Microsoft.Dynamics.GP.ServiceIntegration.DrillBackService;

namespace SampleGPHandler
{
public class GPAddIn : IDexterityAddIn
{
// Variable for the service instance
DynamicsGPDrillBack ServiceInstance;

public void Initialize()


{
// Get the service instance
ServiceInstance = DynamicsGPDrillBack.Instance;

// The static instance must be used for Unified Communications


ServiceInstance.ProcessStaticUri += new EventHandler
<UrlReceivedEventArgs>(ServiceInstance_ProcessStaticUri);
}

void ServiceInstance_ProcessStaticUri(object sender,


UrlReceivedEventArgs e)
{
string ProductId = "";
string ActionType = "";
string FunctionName = "";
string UserSIP = "";

// Process the query portion of the URL that was passed in


NameValueCollection KeyPairs =
HttpUtility.ParseQueryString(e.UriValue.Query);
foreach (string key in KeyPairs.Keys)
{
if (key == "ProductID")

INTEGRATION GUIDE 445


PA RT 8 AP P LI C A TI O N S E R V IC E S

{
ProductId=KeyPairs.GetValues(key).GetValue(0).ToString();
}
if (key == "ActionType")
{
ActionType=KeyPairs.GetValues(key).GetValue(0).ToString();
}
else if (key == "FunctionName")
{
FunctionName=KeyPairs.GetValues(key).GetValue(0)
.ToString();
}
else if (key == "UserSIP")
{
UserSIP = KeyPairs.GetValues(key).GetValue(0).ToString();
}
}

// If it is our product, then perform the action


if (ProductId == "3333")
{
if (FunctionName == "OpenNewLead")
{
// Open a new lead if one isn't already open
if (SampleIntegratingApp.Forms.IgLeadMaintenance.IsOpen ==
false)
{
SampleIntegratingApp.Forms.IgLeadMaintenance.Open();
}
}
}
}
}
}

446 IN T E G R AT I O N G U ID E
PART 9: PACKAGING YOUR APPLICATION
Part 9: Packaging Your Application
Once you’ve developed and tested your integrating application, you finish the
development process by packaging your application for delivery to customers. This
portion of the documentation explains this process. The following topics are
discussed:

• Chapter 41, “Building An Application,” explains the processes for extracting


your application, transferring alternate forms and reports, adding product
information, and compressing your dictionary.

• Chapter 42, “Making Installation Files,” explains the processes for writing
installation scripts, creating a chunk file, testing the installation process, and
delivering additional components.

• Chapter 43, “Updating an Application,” explains how to update your


application when an update of Microsoft Dynamics GP is released.

448 IN T E G R AT I O N G U ID E
Chapter 41: Building An Application
Once you’ve completed application development, you can prepare your application
for delivery to customers. Since you cannot ship your development dictionary, you
must prepare a separate dictionary containing all resources you created in your
development dictionary, and any Microsoft Dynamics GP forms or reports you’ve
customized (alternate forms and reports).

You will build this dictionary using Dexterity Utilities. The following checklist
outlines the process of building your dictionary:

✔ Step Description
1 Extract your application using the Extract utility.
2 Transfer alternate forms and reports using Transfer Dictionary Module utility.
3 Add product information using the Product Information utility.
4 Create installation files following the instructions in Chapter 42, “Making
Installation Files.”

Information about building your application is divided into the following sections:

• Extracting your application


• Transferring alternate forms and reports
• Adding product information
• Compressing your dictionary
• Completing the packaging process
• Using macros

Extracting your application


The Extract utility copies, or “extracts” new resources you’ve added to the
development dictionary (with resource IDs of 22,000 and greater), and places them
in a new dictionary. This process excludes any Microsoft Dynamics GP resources,
since Dexterity numbers these resources below 22,000. Although your dictionary
doesn’t contain any Microsoft Dynamics GP resources, it maintains references to
any main product resources you may have used.

The extraction process does not remove any resources from your development dictionary. It
simply copies new resources to the extracted dictionary.

The following illustration shows a development dictionary and the process for
building a third-party dictionary.

Development dictionary
Aged Trial Balance report
Customers report
Main product resources Customer Class Setup form
(resource IDs < 22,000) Customer Maintenance form
Cash Receipts Entry form
Core Resources
Extracted dictionary
Extract Utility
Lead Maintenance Lead Maintenance
Third-party resources
Lead Report Lead Report
(resource IDs >= 22,000)
Third-party Core Resources Third-party Core Resources

INTEGRATION GUIDE 449


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Use the following steps to extract your application from your development
dictionary.

1. Make a backup
Before you begin the extract process, be sure to make a backup of your
development dictionary and store it in a safe location. If errors occur during the
process of building your application dictionary, restore the backup and attempt
the process again.

2. Open the Extract utility in Dexterity Utilities.


Start Dexterity Utilities and open your development dictionary as a source
dictionary. Choose Extract from the Utilities menu. The Extract window, shown
in the following illustration, will display the name of your development
dictionary.

Click OK to start the dictionary extract process.

3. Name the extracted dictionary.


A file dialog will appear. This dialog allows you to specify the name of your
extracted application dictionary, and a location where the utility will create the
extracted dictionary.

If you use any Microsoft Dynamics GP resources in creating your application, you
should not edit your extracted dictionary using Dexterity. The extracted dictionary
contains references to resources in Microsoft Dynamics GP; Dexterity has no provisions
for handling these references, and you could corrupt your dictionary.

Transferring alternate forms and reports


Refer to Chapter 3, Before you deliver alternate forms and reports to customers, you must transfer
“Forms,” for additional them to your extracted dictionary using the Transfer Dictionary Module utility in
information about Dexterity Utilities. Once installed with an unmodified version of Microsoft
customizing forms and Dynamics GP, you can control access to alternate forms and reports using the
reports. security features in the accounting system.

The following illustration shows a development dictionary and the process for
transferring alternate forms and reports to a third-party dictionary.

Development dictionary
Aged Trial Balance report
Customers report
Alternate form
Customer Class Setup form
and report Transfer Dictionary
Customer Maintenance form
Module Utility
Extracted dictionary
Cash Receipts Entry form
Customers Report
Core Resources
Customer Maintenance form
Lead Maintenance Lead Maintenance
Lead Report Lead Report
Third-party Core Resources Third-party Core Resources

450 IN T E G R AT I O N G U ID E
C H A P T E R 4 1 B U I LD IN G A N A P PL IC A T IO N

Use the following steps to transfer alternate forms and reports to your extracted
dictionary.

Start Dexterity Utilities and open your development dictionary as a source


dictionary. Open your extracted dictionary as a destination dictionary.

1. Open the Transfer Dictionary Module utility.


Choose Transfer Dictionary Module from the Transfer menu. The Transfer
Dictionary Module window, shown in the following illustration, will appear.
The Source Dictionary Module list shows dictionary modules for the
development dictionary.

Select the forms or


reports you’ve customized
in this list and click
Transfer.

2. Choose alternate forms and reports you want to transfer.


In the Source Dictionary Modules list, locate the alternate form(s) or report(s)
you’ve customized. To display forms or reports from other series, choose the
appropriate series and dictionary module type from the drop-down lists. Once
you’ve located the form or report, select it and click Transfer. The form will
appear in the Destination Dictionary Modules list.

Repeat this process until all the alternate forms and reports you’re delivering
appear in the Destination Dictionary Module list. Click Close when you’ve
finished transferring form and report modules.

If you do not use the Auto-Chunk utility to package your application, be sure you use
the Update Series Resources utility to update resource lists in the extracted dictionary
for transferred alternate forms and reports. Chapter 42, “Making Installation Files,”
explains how to use the Auto-Chunk utility.

Adding product information


Before you can use your extracted application dictionary with Microsoft Dynamics
GP in a multidictionary environment, you must add product information to your
dictionary using the Product Information utility.
Refer to Chapter 42, Once you add product information to your dictionary, you can update the launch
“Making Installation file with the same product information, either by editing the launch file manually,
Files,” for more or by updating the launch file using a chunk dictionary. This gives the Microsoft
information about Dynamics GP runtime engine the information necessary to open your application in
updating the launch a multidictionary environment. The following illustration shows a launch file
file using a chunk configured so Microsoft Dynamics GP and the sample integrating application run in
dictionary. a multidictionary environment.

INTEGRATION GUIDE 451


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

The number of products 2


in the multidictionary 0
environment. Microsoft Dynamics GP
The product ID 3333
and name. Sample Integrating App.
The dictionary location ID. Windows
:C:Dynamics GP/Dynamics.dic
:C:Dynamics GP/Data/Forms.dic
:C:Dynamics GP/Data/Reports.dic
The locations of the :C:Dynamics GP/Develop.dic
application, forms and :C:Dynamics GP/Data/F3333.DIC
reports dictionaries. :C:Dynamics GP/Data/R3333.DIC

Use the following steps to add product information. Open your extracted dictionary
as an editable dictionary, then choose Product Information from the Utilities menu
to open the Product Information window.

Indicate the name of the


Microsoft Dynamics GP launch
file and the Dynamics.dic
dictionary ID in these fields.

1. Select a launch file.


Enter the name of the Microsoft Dynamics GP launch file in the Launch File
field. Usually, this name is “DYNAMICS.SET”. When installed with Microsoft
Dynamics GP, the chunk file adds product information to this launch file.

2. Enter a launch ID.


Accept the default launch ID of 0. This is the product ID for the main
application. Microsoft Dynamics GP has a product ID of 0 and each is the main
application in a multidictionary environment.

3. Enter a product name.


Enter the name of your application in the Product Name field as you want it to
appear when running with Microsoft Dynamics GP.

4. Enter a product ID.


Enter the product ID for your application in the Product ID field. Each product
must have a unique product ID assigned to avoid conflicts with other
integrating applications. Contact Microsoft to obtain a product ID for your
application.

452 IN T E G R AT I O N G U ID E
C H A P T E R 4 1 B U I LD IN G A N A P PL IC A T IO N

5. Enter the names of your forms and reports dictionaries.


Enter the name of the forms and reports dictionary for your application in the
Forms Dictionary and Reports Dictionary fields. You can enter an eight-
character name with a three-character extension. Use the .DIC extension. These
are the dictionary names used when the runtime engine creates your
application’s forms and reports dictionaries for the first time.

To avoid conflicts with forms and reports dictionaries from other integrating
applications, include your product ID in the name. For example, the forms dictionary
for the sample integrating application is F3333.DIC.

6. Enter the compatibility ID and compatibility message.


The Compatibility ID is a string that uniquely identifies the version of your
application. When you launch your application with the runtime engine, the
compatibility ID in the application dictionary is compared to the compatibility
IDs in the forms and reports dictionaries. If they match, items in the forms and
reports dictionaries can be accessed.

The compatibility message is the message that is displayed when the


compatibility IDs in the forms or reports dictionaries don’t match
the compatibility ID in the application dictionary. You should provide
information in this message describing how to update your forms and reports
dictionaries to make them compatible with the current version of your
application. For applications that integrate with Microsoft Dynamics GP, this
typically means performing a form and report update operation with GP
Utilities. Once you’ve finished entering product information, click OK.

Compressing your dictionary


If you build a There are two types of compression: total compression and removing unused blocks.
dictionary chunk using Total compression removes script source and all unused blocks from the dictionary.
the Auto-Chunk utility, Removing unused blocks removes only unused blocks from the dictionary, leaving
compressing your the script source intact. When distributing an application that integrates with
dictionary at this point Microsoft Dynamics GP, we recommend that you perform a total compression of
isn’t necessary. The your dictionary.
Auto-Chunk Utility
performs dictionary To compress your extracted dictionary, use the Compress utility in Dexterity
compression for you. Utilities.

Use the following steps to compress your extracted dictionary:

Start Dexterity Utilities and open your extracted dictionary as an editable


dictionary, then choose Compress from the Utilities menu.

1. Choose the Total Compression option.


Since this is a production release of your product, choose Total Compression as
the compression option. This will remove unused blocks as well as script
source.

INTEGRATION GUIDE 453


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

2. Begin the dictionary compression.


Click OK. The Compressed Dictionary Name file dialog box will appear,
allowing you to enter the name and location of the compressed dictionary. Once
you’ve created a compressed dictionary, be sure to use it with the remainder of
the packaging process.

Completing the packaging process


If you’re preparing an extracted application for delivery to Microsoft Dynamics GP
customers, or if you want to test the installation process for your application, be
sure to create an installation file following the guidelines in Chapter 42, “Making
Installation Files.” An installation file allows you to:

• Update the launch file with product information automatically.

• Execute installation scripts that can perform setup tasks during the installation.

• Update forms and reports dictionaries for your application.

If you’re simply testing your extracted application with an unmodified


Dynamics.dic dictionary in a multidictionary environment, you can edit the launch
file manually to include information about your application. Use Windows
Notepad to edit the launch file. The following illustration shows the modifications
necessary to launch the sample integrating application.

2
0
Microsoft Dynamics GP
3333
Sample Integrating App.
Windows
:C:Dynamics GP/Dynamics.dic
:C:Dynamics GP/Data/Forms.dic
:C:Dynamics GP/Data/Reports.dic
:C:Dynamics GP/Develop.dic
:C:Dynamics GP/Data/F3333.DIC
:C:Dynamics GP/Data/R3333.DIC

Once you’ve modified the launch file, you can move your application dictionary to
the location you specified in the launch file, and launch Microsoft Dynamics GP.

Using macros
Many steps are involved in building your application. You will find that you repeat
these steps several times as you develop your integration. We recommend that you
use the macro capability with Dexterity Utilities, and record a macro to automate
the building process. In addition to speeding the building process, a macro helps
ensure that you don’t skip a build step, or made an incorrect selection during the
process.

454 IN T E G R AT I O N G U ID E
Chapter 42: Making Installation Files
Once you’ve developed and tested your application in the development dictionary,
then built your application using Dexterity Utilities, finish the development process
by packaging your application for delivery to customers. Information about making
installation files is divided into the following sections:

• Writing installation scripts


• Building a chunk dictionary
• Using the Auto-Chunk utility
• Testing the installation process

Writing installation scripts


See Building a chunk An installation script is a procedure you write in the development dictionary that
dictionary on page 456 runs automatically when you install your application with Microsoft Dynamics GP.
for information about You will use an installation script can be used to perform certain setup tasks, such as
selecting an installa- setting default security for your integrating application.
tion script to use for a
chunk dictionary.

Installation Script

DEVELOP.CNK Dynamics Dictionary

You indicate the installation script for your application when building a chunk
dictionary for your extracted application dictionary, using either the Auto-Chunk or
Create Chunk Dictionary utilities. When the chunk dictionary installs, or
“unchunks” in the same location as the Microsoft Dynamics GP dictionary, it
automatically runs the installation script you’ve indicated.

Installation scripts are rarely used for integrations with recent versions of Microsoft
Dynamics GP.

You write an installation script just like an ordinary procedure. However, it’s
important to keep in mind when the installation script actually runs. The
installation script is run only one time when the chunk dictionary is installed. It is
never run again.

You cannot check values of any Microsoft Dynamics GP global variables using an
installation script. Microsoft Dynamics GP sets the values of global variables after your
installation script runs.

The installation script runs before any user has logged into the system. This is as
issue for SQL Server, because a user must be logged in before any table operations
can be performed. To avoid the SQL Login window being displayed during
installation, any operations that access tables must be delayed until the user has
logged into the system. Typically this is done using a procedure trigger for the
Add_Successful_Login_Record procedure in Microsoft Dynamics GP. The
following example shows the registration for this trigger.

l_result = Trigger_RegisterProcedure(script Add_Successful_Login_Record,


➥ TRIGGER_AFTER_ORIGINAL, script IG_Setup_SQL_Tables);

INTEGRATION GUIDE 455


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Building a chunk dictionary


To deliver your extracted application dictionary, first convert your application into a
chunk dictionary using Dexterity Utilities. When you install your application with
Microsoft Dynamics GP, a chunk dictionary is “unchunked” and becomes a regular
application dictionary. As it unchunks, the chunk dictionary performs two
necessary functions:

• It automatically updates the launch file with product information you applied
to the extracted dictionary. Without a chunk dictionary, the user must edit the
launch file manually to add product information.

• It allows you to attach an installation script, which you can use to complete any
setup or installation tasks. Refer to Writing installation scripts on page 455 for
more information.

Refer to Chapter 7, There are two methods of creating a chunk dictionary. The simplest and
“Dictionary Utilities,” recommended method is to create a single chunk dictionary using the Auto-Chunk
of the Dexterity utility. The section Using the Auto-Chunk utility on page 456 explains how to use this
Utilities manual for utility.
information about
using the Create Chunk The second method of creating a dictionary chunk uses the Create Chunk
Dictionary utility. Dictionary utility. The main advantage of this utility is that you can break up your
application into several smaller chunk dictionaries that will be merged into one
application dictionary during installation. This is especially useful if your
installation program doesn’t support file segmenting.

Using the Auto-Chunk utility


To use the Auto-Chunk utility to create a single dictionary chunk for your
application dictionary, complete the following steps.

Start Dexterity Utilities and open your extracted dictionary as an editable


dictionary. If you haven’t extracted your application yet, be sure to do so following
the processes described in Chapter 41, “Building An Application.”

1. Name the chunk.


Choose Auto-Chunk from the Utilities menu on the toolbar. The Auto-Chunk
window will appear. Click the Chunk Dictionary lookup button; a dialog box
will appear prompting you to name the dictionary chunk you’re creating. Name
the chunk and click OK.

Due to a historical limitation imposed by early versions of Windows, the name of the
chunk dictionary must not exceed 13 characters, including the .cnk extension. If the
name exceeds 13 characters, the chunk cannot be accessed by the runtime engine and
will not be unchunked.

2. Specify chunk options.


To complete the process of creating a chunk, use the Auto-Chunk window,
shown in the following illustration.

456 IN T E G R AT I O N G U ID E
C H A P T E R 4 2 M A K I N G I N S TA L L A T I O N F I L E S

Dictionary Enter the name of the dictionary created once the installation is
complete. For the sample integrating application, this is DEVELOP.DIC. Do not
enter the name of the Dynamics.dic dictionary.

Module This selection indicates which module the Major Version, Minor
Version and Build Number information is associated with. (These are the fields
below the Module field.) The setting in the Module field is used when the
version numbers and build number are retrieved from the dictionary.

Refer to the Runtime_GetModuleInfo() function in the Function Library


Reference manual for information about retrieving version and build numbers.

Major Version/Minor Version Enter the major and minor version numbers
for your application. For instance, if your application is version 1.3, enter a 1 for
the major number and a 3 for the minor number. If you’d like, you can use the
same version number scheme used by Microsoft Dynamics GP. You can retrieve
these numbers from your application dictionary and display them in your
application’s About box.

The values you choose for the major version and minor version are significant.
If a Microsoft Dynamics GP installation contains a dictionary for a previous
version of your product, the dictionary chunk you are creating will unchunk
only if the major version and minor version numbers in the chunk match those
in the existing dictionary. If the version numbers don’t match, an error
indicating the issue will be written to the InstallErrors.txt file in the Microsoft
Dynamics GP installation folder. The dictionary chunk won’t be deleted.

Build Number Enter the build of the current version of the dictionary. You
can retrieve this build number and display it in your application’s About box.

If you have multiple dictionary chunks with the same major version and minor
version values, the build number is used to determine the order in which the
dictionary chunks are unchunked. The chunks with lower build number values
are unchunked first.

If an installation contains a dictionary for which the major and minor version
numbers match those of the dictionary chunk, the build number will be
examined. If the build number of the chunk is the same or greater than the build
number of the dictionary, the chunk will be unchunked. If the build number of
the chunk is lower, it will not be unchunked, and a message indicating the issue
will be written to the InstallErrors.txt file in the Microsoft Dynamics GP
installation folder. The dictionary chunk will be deleted.

INTEGRATION GUIDE 457


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Refer to the previous Starting/Ending Script These fields specify which installation scripts
section, Writing (procedures) run when the chunk dictionary unchunks. Installation scripts are
installation scripts, for procedures you write in the development dictionary that perform setup tasks
more information when your application installs with Microsoft Dynamics GP. To specify a
about installation starting or ending script, mark the corresponding check box and click the
scripts. lookup button for the starting or ending script. A list of the procedures in your
extracted application dictionary will appear. Choose the installation script.

The installation scripts run only after the chunk dictionary unchunks. The
starting script runs first, then the ending script runs. If you have a single main
installation script (similar to the IG_Install_Main installation script for the
sample integrating application), simply indicate the main installation script as
the starting script, and don’t indicate an ending script.

Compression Choose to remove either unused blocks from the dictionary, or


to perform a total compression, which removes unused blocks and all script
source. Typically, you should perform a total compression when delivering
integrating applications.

3. Create the chunk.


Click OK to begin the chunking process. Once the Auto-Chunk utility creates
the chunk dictionary, the Auto-Chunk window will close.

4. Make a backup.
Make a backup of the chunk dictionary. At this point, you should test the chunk
dictionary following the instructions in Testing the installation process on
page 458.

Testing the installation process


Once you’ve created a chunk dictionary, test the installation process. Be sure to
complete the installation using an unmodified Microsoft Dynamics GP system
that’s set up the same as the one your customers use. To complete the installation
process, perform the following steps:

1. Make a backup of tables that will be updated.


Make a backup of all tables you’re updating during installation, as well as the
launch file (DYNAMICS.SET). To test the installation multiple times, you’ll
need to restore any tables updated during the installation, as well as the launch
file, with backups you make here.

2. Install the chunk.


Place a copy of the chunk dictionary in the same location as the Dynamics.dic
dictionary and launch the accounting system. A dialog box appears asking
whether you’d like to include new code. Click Yes. The runtime engine will
“unchunk,” then synchronize your application dictionary. Any installation
scripts will then run. When the installation is complete, the login window will
appear.

3. Check installation items.


Log into the sample company. If you used an installation script, examine
whether the script was run correctly. If the installation wrote records to multiple
companies or for multiple users, be sure those records appear properly for each
company and user.

458 IN T E G R AT I O N G U ID E
C H A P T E R 4 2 M A K I N G I N S TA L L A T I O N F I L E S

4. Make any necessary changes.


If your application doesn’t install properly, check the following:

• Be sure your application dictionary has product information before you cre-
ate chunk dictionaries.

• Be sure the names of the dictionary chunks don’t exceed 13 characters


(including the .cnk extension).

• Verify that the version numbers and build number you applied to the dic-
tionary chunk are correct. They must follow the rules described in Using the
Auto-Chunk utility on page 456. Check the InstallErrors.txt file in the
Microsoft Dynamics GP installation folder for any errors reported during
the unchunking process.

• If you’re using installation scripts, be sure each works in your development


dictionary using test mode.

• Before installing, be sure the launch file contains the correct information for
Microsoft Dynamics GP to launch without your integrating product.

• If you’re using multiple dictionary chunks, be sure the Dictionary name


you’ve specified is exactly the same for each chunk, and the dictionary
name is not DYNAMICS.DIC. Also, be sure the sequence numbers are cor-
rect.

• Be sure each chunk dictionary contains the [Core] System Core Tables and
the [Core] System Install resources.

• If you receive permission errors, be sure the dictionary chunk file isn’t
locked. Also verify that another instance Microsoft Dynamics GP isn’t
already running, accessing the dictionary being updated.

After installation, a single application dictionary will have replaced the chunk
dictionary or dictionaries. The chunk also will have updated the launch file with the
correct location of the integrating dictionary.

INTEGRATION GUIDE 459


460 IN T E G R AT I O N G U ID E
Chapter 43: Updating an Application
When an update of Microsoft Dynamics GP is released, you’ll need to deliver an
updated version of your application to customers who receive the update. This
process is necessary to deliver changes made to your application, and to ensure that
your application integrates properly with the new version of Microsoft Dynamics
GP. The following checklist outlines the steps involved in the update process:

✔ Step Description
1 Use the detailed upgrade procedure to transfer third-party resources to the new
version of the Dynamics.dic dictionary.
2 Review Microsoft Dynamics GP changes and make any necessary changes in
your application.
3 Redo any customizations made for alternate forms and reports.
4 Test your application with the new version of Microsoft Dynamics GP.
5 Build an update chunk dictionary that you can deliver to customers.

Information about updating an application is divided into the following sections:

• Transferring third-party resources


• Common update problems
• Reviewing Microsoft Dynamics GP changes
• Converting data
• Alternate forms and reports
• Testing your application
• Building an update chunk dictionary
• Updating forms and reports dictionaries

Transferring third-party resources


If you are using Source Beginning with Release 6, the Microsoft Dynamics GP development organization
Code Control to began using the source code control support in Dexterity to manage application
manage your development. Because of this change to source code control, you can no longer use
application the Developer Update routine in Dexterity Utilies to upgrade your application.
development, refer to Instead, you must use the following procedure to upgrade your application.
Chapter 55, “Source
Code Control for This procedure requires using the source code control capabilities in Dexterity. Refer
Integrating to Part 9, Source Code Control, in Volume 1 of the Dexterity Programmer’s Guide
Applications,” in for information about using source code control. You can find the same information
Volume 1 of the in the Dexterity online help.
Dexterity
Programmer’s Guide As an example of this upgrade procedure, the sample integrating application
for information about included with Dexterity will be converted to work with a new release of Microsoft
updating your Dynamics GP.
application.
1. Install the new Microsoft Dynamics GP release.
Be sure Microsoft Dynamics GP is working properly before you attempt to
upgrade your integrating application to work with it.

2. Install the Dexterity Source Code Control Server.


If you are planning to implement source code control to manage your Dexterity
application development, install the source code control provider you plan to
use, such as Microsoft’s Visual SourceSafe. Refer to Chapter 51, “Setting up
Source Code Control,” in Volume 1 of the Dexterity Programmer’s Guide for
information about setting up source code control.

INTEGRATION GUIDE 461


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

If you aren’t planning to use source code control in your application


development, you will need to use the Generic provider included with
Dexterity to perform the upgrade process. This procedure assumes that you will
be using the generic provider. The same steps can be used if you have chosen
another provider such as Visual SourceSafe.

To install the Source Code Control Server, locate the SETUP.EXE file in the
DSCCS folder included with the Dexterity installation. Run the setup. During
the installation, the control panel for the Dexterity Source Code Control Server
will be displayed. Select the provider type you are using.

• If you have chosen Visual SourceSafe as the provider, specify the location of
the SRCSAFE.INI. This tells the Dexterity Source Code Control Server
where the source code control provider is located.

• If you have chosen the Generic provider, specify the Root directory. This is
the location that will store the contents of your dictionary when it is
checked into source code control. Typically, this is a directory on the same
machine that is running the Dexterity Source Code Control Server.

Continuing the example, the Dexterity Source Code Control Server was
installed, and the Generic provider was selected. The “SCC” directory was
created, and will be used as the root directory.

3. Create a project for your integrating application.


To create a project for your integrating application, do one of the following:

• If you are using Visual SourceSafe, use the administrative tools to create a
project. You will also need to create a user and set access rights for the
project.

• If you are using the Generic provider, create a directory inside of the root
directory you specified in the previous step. This directory will store the
contents of your integrating application.

Continuing the example, a directory named “Sample” was created inside the
SCC directory.

4. Locate your current development dictionary.


The development dictionary is the Dynamics.dic dictionary that contains the
resources for your integrating application.

For this procedure, we recommend that you use a copy of your development dictionary.

5. Open the development dictionary with Dexterity.


Using Dexterity, open the copy of your development dictionary.

462 IN T E G R AT I O N G U ID E
C H A P T E R 4 3 U P DA T IN G A N A P PL IC A T IO N

6. Set up source code control options.


Choose Options from the Edit menu in Dexterity. Click the Source Control tab
and specify the options necessary to access the source code control repository.
These include the following:

Repository Name This is the hostname or IP address of the machine that


contains the repository and is running the Dexterity Source Code Control
Server. If you are running Dexterity and the source code control system on a
single machine, you can use the IP address 127.0.0.1 or the hostname localhost
to indicate the current machine.

User Name Enter the user name you were assigned when the source code
control provider was set up. If you are using the Generic provider, you don’t
need to supply a user name.

Password Enter the password you were assigned when the source code
control provider was set up. If you are using the Generic provider, you don’t
need to supply a password.

Project Name Enter the name of the project you want to use in the
repository. You can click the lookup button to view a list of projects available in
the repository.

Temp File Location Many temporary files are created as resources are
checked into and out of the repository. Specify the location where you want
these temporary files placed. The location you choose should have at least twice
as much disk space available as the size of the dictionary you will be storing in
the repository.

Original Dictionary For resources to be properly checked into the


repository, you must specify the location of an unmodified original dictionary
for version of Microsoft Dynamics GP you are upgrading from.

The settings used for the example are shown in the following illustration. Since
the Generic provider is being used, a user name and password are not needed.

Be sure you have marked all of the options at the bottom of the window.

To be sure you have set the source code control options correctly, click the
Validate Connection button. A dialog will be displayed, indicating whether a
connection could be established with the source code control provider.

INTEGRATION GUIDE 463


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

7. “Touch” alternate forms and reports.


If your integrating application has alternate forms and reports, you must
“touch” them with Dexterity so they can be put into the new state. This allows
them to be checked into the source code control repository. To “touch” an
alternate form or report, open the form or report definition and click OK.

8. Check resources into the repository.


In the Explorer menu, point to Source Control and then choose Check In. After a
few moments, the Check in To Repository window will be displayed.

Click Insert All to check in all of the source files for your integrating application.
Supply a check in comment. The content of the comment isn’t critical, but is
required to check in files to the repository. Typically, the comment will indicate
this is the initial check in operation.

Click Check In to perform the check in operation. A progress dialog will be


displayed as resources are checked into the repository. When the process has
finished, click Close to close the Check in To Repository window.

9. Update the Index file.


The Index file contains a list of the resources and their associated resource IDs.
It’s used to ensure that resources keep the same resource IDs. To update the
Index file, point to Source Control in the Explorer menu and choose Update
Index File. Click Yes in the dialog that is displayed.

We recommend that you make a backup of your repository at this point.

10. Create a new development dictionary.


Make a copy of the Dynamics.dic dictionary for the new release. This dictionary
will become your new development dictionary. Open this new dictionary with
Dexterity.

11. Specify the location of an original dictionary for the new release.
Now that you are working with dictionary for the new release, you must
specify the location of an unmodified original dictionary for the new release of
Microsoft Dynamics GP.

Open the Options window in Dexterity and display the Source Control options.
Use the Original Dictionary lookup button to specify the location of an
unmodified Dynamics.dic dictionary for the new release.

12. Perform an update operation.


The update operation will retrieve all of your third-party resources from the
source code control repository and add them to the new development
dictionary.

To perform an update operation, point to Source Control in the Explorer menu


and choose Update. The Update From Repository window will be displayed.
Mark the following options in this window:

• Update All
• Run SCC Error Report
• Run Compile Error Report - Detailed
• Use Index File

464 IN T E G R AT I O N G U ID E
C H A P T E R 4 3 U P DA T IN G A N A P PL IC A T IO N

The window should look like the following illustration.

Click OK to perform the update operation. Dialogs will be displayed, asking


you where you want the error reports printed. We recommend that you print
the reports.

Next, the Resources to Update window will be displayed. Be sure all of the
items are marked, and click OK. As the update operation is performed, a
progress dialog will be displayed.

The update operation can take several minutes.

13. Check the error reports.


The error reports will indicate problems that exist in the new development
dictionary, such as fields that are no longer available. The following section,
Common update problems, describes common problems you may encounter. Use
the information provided to help you resolve them.

14. Continue updating your application.


Use the updated version of the development dictionary that now contains your
application’s resources to perform the remainder of the update tasks for your
application. Before you use Dexterity to make changes, make a backup of the
updated development dictionary.

Common update problems


The following is a list of common problems that can occur during the update
process, and how to resolve them. The issues discussed are:

• Deleted strings
• String collisions
• Deleted resources
• Resource name conflicts

Deleted strings
If your application references strings that are no longer part of the Dynamics.dic
dictionary, Dexterity will automatically add new string resources to the dictionary.
No developer intervention is required.

String collisions
If your application contains strings that now part of the Dynamics.dic dictionary, a
warning will be logged during the update operation. Dexterity will automatically
use the string resource in the Dynamics.dic dictionary. No developer intervention is
required.

INTEGRATION GUIDE 465


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Deleted resources
Your application may be referencing resources that no longer exist in the
Dynamics.dic dictionary. For example, a field you reference may no longer be
included in the dictionary. To deal with resources that have been deleted, you will
need to either use a different resource or create your own version of the resource.
Then you will have to open each resource (such as forms or reports) that use the
resource you created and replace the [Not Found] instances with an instance of the
new resource.

If you have chosen to use a new resource that can be referred to directly in scripts,
you will need to use the Search and Replace capability in Dexterity to replace all
occurrences of the previous resource name with the new resource name. Be sure to
compile all scripts after the search and replace operation.

Resource name conflicts


If your integrating application contains resources that have the same name as
resources that are now part of the Dynamics.dic dictionary, the update operation
will not be able to finish until those conflicts are resolved. How you resolve the
name conflict depends on whether you want to reference your own resource or use
the new resource in the Dynamics.dic dictionary.

Using your own resource


To continue using your own version of the resource, do the following:

1. Switch back to the previous version of your application.


In Dexterity, open the development dictionary for the previous version of your
application. This is the same dictionary you used in step 5 of the previous
procedure.

2. Check out the resources that need to be changed.


Check out the source files that contain the resources whose names need to be
changed to avoid the naming conflicts.

3. Change the names of the conflicting resources.


You must change the names of the resources to unique names that don’t conflict
with resources in the new version of Microsoft Dynamics GP.

There are special considerations to keep in mind when changing the names of resources
in dictionaries that are stored under source code control. Refer to Renaming resources
on page 462 of Volume 1 of the Dexterity Programmer’s Guide for complete information
about renaming resources.

4. Check the source files back into source code control.


Check in all of the source files that were changed when you eliminated the
naming conflict.

5. Open the actual development dictionary.


With Dexterity, open the actual development dictionary for the new release of
Microsoft Dynamics GP.

466 IN T E G R AT I O N G U ID E
C H A P T E R 4 3 U P DA T IN G A N A P PL IC A T IO N

6. Perform an update operation.


An update operation will add all the resources from the source code control
repository to the development dictionary. Be sure the following options are
marked in the Update From Repository window:

• Update All
• Run SCC Error Report
• Run Compile Error Report - Detailed
• Use Index File

7. Check the error reports.


After this procedure, you should no longer receive errors for the name conflicts.
The renamed resources from the earlier version of your dictionary will be used.

To use the Dynamics.dic resource


If you have verified that the new resource included in the Dynamics.dic dictionary
is acceptable, and you want to use it instead of your resource, do the following:

1. Remove the resource from the Index File.


The Index File (INDEX.TXT) is located in the Admin folder in the source code
control repository. You will need to manually check out this file from the
repository, open it with a text editor and remove the entry for the resource that
has the name conflict. Check the Index File back into the repository.

2. Create a “throw away” development dictionary.


Create a new development dictionary by making a copy of an unmodified
Microsoft Dynamics GP dictionary from the new release. This “throw away”
development dictionary will be used for this procedure, then discarded.

3. Perform an update operation for the “throw away” dictionary.


Open the “throw away” development dictionary and perform an update
operation. To perform an update operation, point to Source Control in the
Explorer menu and choose Update. The Update From Repository window will
be displayed. Mark the following options in this window:

• Update All
• Run SCC Error Report
• Run Compile Error Report - Detailed
• Use Index File

Click OK to perform the update operation. Dialogs will be displayed, asking


you where you want the error reports printed. We recommend that you print
the reports.

Next, the Resources to Update window will be displayed. Be sure all of the
items are marked, and click OK. As the update operation is performed, a
progress dialog will be displayed.

Because the resource with the name conflict wasn’t included in the Index File,
you shouldn’t receive any errors when performing the update operation.

4. Lock the source file containing the resource that caused the name
conflict.
In Dexterity, lock the source file containing the resource that caused the name
conflict. For instance, if a field resource caused the name conflict, lock the
source file that contains all of the fields.

INTEGRATION GUIDE 467


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

5. Check in the source file containing the resource that caused the
name conflict.
In Dexterity, check in the source file that you locked in the previous step. This
creates a revision of the source file that will not contain the resource that caused
the conflict.

6. Open the actual development dictionary.


With Dexterity, open the actual development dictionary for the new release of
Microsoft Dynamics GP.

7. Perform an update operation.


An update operation will add all the resources from the source code control
repository to the development dictionary. Be sure the following options are
marked in the Update From Repository window:

• Update All
• Run SCC Error Report
• Run Compile Error Report - Detailed
• Use Index File

8. Check the error reports.


After this procedure, you should no longer receive errors for the name conflicts.
The new resources in the Dynamics.dic dictionary will be used.

Reviewing Microsoft Dynamics GP changes


Once all your application’s resources are in the updated version of the development
dictionary, use Dexterity to begin the process of changing your application to
function with the updated version. Depending on the number and type of Microsoft
Dynamics GP resources you reference in your application, the impact of changes
will vary. The following table shows the typical changes you may need to address.

Resource Impact of changes


Data Types Data types may change to account for a larger storage size, or a different
control type (such as changing an integer to a long integer). If you use a
Microsoft Dynamics GP field in your tables, and the data type for that field
changes, you may need to convert customer data in that table. See
Converting data on page 469 for additional information.
Fields New Microsoft Dynamics GP fields may have the same names as fields in
your application. When testing your application, this will result in illegal
address errors. If this is the case, rename your application’s fields where
appropriate, and change scripts that reference those fields.
Procedures Microsoft Dynamics GP procedures may change in functionality, or in the
number, order and type or parameters used in the procedure. If parameters
change, you won’t be able to compile the calling script in your application.

468 IN T E G R AT I O N G U ID E
C H A P T E R 4 3 U P DA T IN G A N A P PL IC A T IO N

Converting data
Refer to Chapter 60, If you change any of your application’s tables in the process of updating your
“Updating an application, data from the previous version of your application will likely be
Application,” in Volume incompatible. This requires that you convert data at the customer site to the new
1 of the Dexterity table definition for the updated version of your application. Changes that make
Programmer’s Guide existing data incompatible include:
for more information
• Adding or deleting fields from a table definition
about writing a table
• Changing the storage size of a table field
conversion procedure.
• Adding or deleting table keys
• Changing table keys

In addition, if your table uses Microsoft Dynamics GP fields and the storage size of
one of the fields changes, you’ll need to convert the data for that table.

Alternate forms and reports


In addition to updating your application’s resources, be sure to examine any
alternate forms that were updated in your application. Source Code Control will
attempt to make the appropriate modification to the new version of each form
you’ve customized, but you should verify the changes that were made.

If you have any alternate reports in your application, you will need to remake those
modifications. This is necessary because the new version of the report you
customized may include new resource or changes to the layout.

Do not transfer alternate forms or reports from your previous development dictionary to
the updated version of your development dictionary. This will replace the original form or
report in the Dynamics.dic dictionary and invariably result in application errors.

Testing your application


Be sure to test your application using both test mode and a multidictionary
environment. When testing your application in a multidictionary environment, do
not install your application with your development dictionary. This can produce
unreliable results since you’re not using the same dictionary your customers are.
Once you complete testing for your application, you can deliver changes to
customers using an update chunk dictionary.

Building an update chunk dictionary


Once you’ve updated your application to the latest version of Microsoft Dynamics
GP, use Dexterity Utilities to build the new version of your application and deliver
it using an update dictionary chunk. An update dictionary chunk can perform the
following:

• Replace updated forms and reports for your application


• Replace alternate forms and reports
• Update your application’s form and report dictionaries
• Run any installation scripts for converting data, or adding records to Microsoft
Dynamics GP tables

INTEGRATION GUIDE 469


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Once your updated application is ready for packaging, complete the following
steps:

1. Build a new application dictionary.


Refer to Chapter 41, Start Dexterity Utilities. Using the new version of your development dictionary,
“Building An build your updated application dictionary like you normally would. This
Application,” for more includes extracting the dictionary, transferring alternate forms and reports,
information about adding product information, and compressing the extracted dictionary.
building the However, do not build a chunk dictionary yet.
application dictionary.
2. Build an “input” file for report update (optional).
If you have made database changes that affect reports, such as removing fields
from tables, you may want to create an input file that will be used when the
report update process is run. The input file contains information about how
reports should be updated to accommodate database changes you have made.
Contact Dexterity technical support for information about creating this input
file.

3. Create the chunk dictionary.


Although you can create a chunk dictionary that contains only the resources
that changed, we recommend that you deliver your entire application dictionary using
a chunk dictionary. This method has a distinct advantage, since you can deliver
the same dictionary chunk to existing customers and to new customers.

Refer to Chapter 60, “Updating an Application,” in Volume 1 of the Dexterity


Programmer’s Guide for information about creating an update chunk that
contains only new and changed resources.

To create a chunk that contains all your application’s resources, use the same
procedure you used when packaging your application using the Auto-Chunk
utility. Refer to Building a chunk dictionary on page 456 for information about
using the Auto-Chunk utility.

4. Test the update chunk.


Move a copy of the chunk dictionary to the same location as an unmodified
installation of the latest Microsoft Dynamics GP system. When you launch the
application, a message will appear asking whether you want to include new
code; click Yes. Once the chunk dictionary “unchunks,” the login window will
appear. Log into the sample company and check to verify that your application
installed properly.

Updating forms and reports dictionaries


If customers use the Modifier to modify your application’s forms, or the Report
Writer to modify your application’s reports, you need to ensure that the forms and
reports dictionaries for your application are updated propery. Otherwise, your
application may not operate correctly.

Forms dictionary
During the unchunking process, resources in the forms dictionary are updated to
make them compatible with the application dictionary. If the user has made any
modifications to forms, as many of those changes as possible will be preserved.

470 IN T E G R AT I O N G U ID E
C H A P T E R 4 3 U P DA T IN G A N A P PL IC A T IO N

Reports dictionary
Updating the reports dictionary is a two-step process. During the unchunking
process, resources in the reports dictionary are updated to make them compatible
with the application dictionary. The second part of the updating process must be
performed by executing the Dict_UpdateReportsDictionary() function. This
portion of the report update uses an “input” file that describes how to handle
database changes that affect reports. You can also run this portion of the update
without using an input file. This is beneficial, because the second portion of the
report update performs some “cleanup” operations on the reports dictionary.

We recommend that you call the Dict_UpdateReportsDictionary() function from


your install script. Doing so allows the entire update process to be performed
immediately after unchunking, making it just a single step for the user installing the
update.

INTEGRATION GUIDE 471


472 IN T E G R AT I O N G U ID E
PART 10: WINDOWS INSTALLER
Part 10: Windows Installer
Windows Installer Services is used to deploy the Microsoft Dynamics GP
application. You can use Windows Installer to deploy your Microsoft Dynamics GP
integration. This portion of the documentation explains how to use Windows
Installer Services to create an installer for your integration. The following topics are
discussed:

• Chapter 44, “Windows Installer Overview,” describes what is provided with


Windows Installer Services. It also introduces WiX, the toolset used to create the
installer for Microsoft Dynamics GP.

• Chapter 45, “Installer Template,” explains how to use the WiX installer template
to create an installer for your integration.

• Chapter 46, “Patches,” describes how to create a patch to update an integrating


application.

474 IN T E G R AT I O N G U ID E
Chapter 44: Windows Installer Overview
When distributing an integration to your customers, consider creating an installer
with Windows Installer Services. Provided with Windows, this set of services makes
installing and maintaining applications much easier. Information about Windows
Installer is divided into the following sections:

• Windows Installer Services


• WiX
• GUIDs

Windows Installer Services


Windows Installer Services are used to install the Microsoft Dynamics GP
application. In addition to being the standard installation tool for Microsoft
applications, using the Windows Installer provides the following benefits:

• Automatic checks for prerequisites to ensure software compatibility


• Standard user interface for the installer
• Remove, repair, and upgrade capabilities
• Updates through software patches

We suggest that you use the Windows Installer to create an installer for your
Microsoft Dynamics GP integration. Users will have a consistent experience
installing your integration, as well as the other benefits of the Windows Installer.

Several products are available for creating an installer based on Windows Installer
Services. They include:

• Windows Installer SDK - Included with the Windows Platform SDK


• Visual Studio®
• Commercial installer development tools
• Shared-source tools

Any of these products could be used to create an installer for your integrating
application. For Microsoft Dynamics GP, a shared-source toolset named WiX is used
to create the installer. A sample WiX template is included with this documentation.
It provides an example of how to install a basic integration.

To begin working with Windows Installer Services, we recommend that you install
the Windows Installer SDK. This is included in the Windows Platform SDK, and
can be downloaded from the Microsoft Developer Network (MSDN®) web site. Go
to msdn.microsoft.com and search for “Platform SDK”.

If you have limited experience creating installers, the quickest path to a successful
installer will be to use the WiX template provided with this documentation. This
template is described in detail in Chapter 45, “Installer Template.”

INTEGRATION GUIDE 475


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

WiX
WiX (Windows Installer XML) is a toolset that is used to create installers based on
Windows Installer Services. XML source files are used to specify the characteristics
of the installer being created. WiX provides a large feature set and can be used to
create sophisticated installation routines.

The sample installer templates were written for WiX release 3. They were tested with build
3.0.5419.0 of WiX.

WiX is available under Microsoft’s Shared Source Licensing Program. You can learn
more about this program at the following site:

http://www.microsoft.com/resources/sharedsource/default.mspx

WiX is still in active development, with new features being added. Quality of the
WiX toolset has reached a level that production installers can be created with it. You
can download the latest version of the WiX toolset from this location:

http://sourceforge.net/projects/wix

After installing the WiX toolset, you should add the folder that contains the WiX
binary files to the PATH environment variable on your system. This allows the WiX
tools be accessed easily from the command prompt.

GUIDs
Globally-unique IDs (GUIDs) are used throughout the process of creating installer
or patched. You will need to generate GUIDs as you create your installer. The
GUIDGen tool, included with the Platform SDK, is a good choice. You can also use
SQL Server to generate GUIDs.

476 IN T E G R AT I O N G U ID E
Chapter 45: Installer Template
A WiX installer template is included with the samples for Dexterity. You can use this
template to create an installer for your integration. Information about using this
template is provided in the following sections:

• Installer template overview


• Creating an installer
• Adding multiple-instance support

Installer template overview


The WiX installer template can be found in the Samples folder installed with
Dexterity. Look inside the Installer folder for the template files. The template
provided can be used to create an installer that does the following:

• Displays a license screen


• Displays an entry in Add/Remove Programs, along with a support link
• Installs components for the integration, such as .CNK and .CHM files
• Removes components and settings
• Provides repair capability

You can use this template to install your integration. Since it uses the standard WiX
toolset, you can enhance your installer with any other capabilities provided by WiX.

The Microsoft Dynamics GP installer allows up to 50 additional instances of


Microsoft Dynamics GP to be installed on a single workstation. Special code was
written to support this scenario. Ideally, your integration should support being
installed into any specific Microsoft Dynamics GP instance. The WiX installer
template described here provides this capability.

The following are the basic steps needed to create an installer using the WiX
template provided:

1. Complete the components to be installed.


All of the dictionary chunks, help files, and any other files required for your
integration should be complete.

2. Update the license agreement.


A license agreement template is provided by the installer. It should be updated
to display the license terms for your integration.

3. Modify the WiX project file.


Use a text editor to modify the WiX project (.wxs) used for your installer. You
will perform actions such as adding the components to the installation.

4. Edit the WiX localization file.


Use a text editor to modify the WiX localization (.wxl) used for your installer.
The localization file contains the text that will appear in the installer.

5. Update the CustomActions script file.


You must modify the CustomActions.vbs script file to include the upgrade code
for your integration, as well as the integrating application’s dictionary name,
forms dictionary name, and reports dictionary name. These values are
necessary so earlier versions of the add-in can be upgraded.

INTEGRATION GUIDE 477


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

6. Build the installer.


Using tools from the WiX toolset, you will create the Windows Installer file.

7. Use the transform tool to add multiple-instance support.


The tool modifies your installer to support multiple Microsoft Dynamics GP
instances.

8. Modify Setup.ini to indicate your installer.


The Setup.msi file must be used to launch your installer. The Setup.ini file must
specify the name of the MSI file you created for your installer.

9. Ship the finished installer.


Include all of the components of the installer.

Creating an installer
To create an installer using the WiX template, complete the following steps. As an
example, the steps needed to create the installer for the sample integrating
application are described.

1. Create a working folder.


The steps for creating the installer will be performed in the working folder. For
this example, the folder is named “Sample Installer” and is located at the root
level.

2. Copy the template items to the working folder.


The following items from the Installer sample must be copied to the working
folder:

• Graphics folder – Graphics and icons for the installer


• Include folder – Script code and source files used for the installer
• Template.wxs – The WiX template project
• Template.wxl – Text strings used for the installer
• Data_SetFile.wxi – An include file that specifies launch file settings
• Transform folder – The tool to support multiple Microsoft Dynamics GP
instances
• Setup.msi – The launcher to be shipped with the installer
• Setup.ini – A configuration file for Setup.msi
• LicenseAgreement.rtf – The license agreement displayed by the installer

3. Rename the template files.


Rename the Template.wxs file to match the completed installer name. For this
example, the file was renamed to Develop.wxs, which means that Develop.msi
will be the final installer filename.

Rename the Template.wxl file to match the new name for the template project.
For this example, the file was rename to Develop.wxl to match the name chosen
for the project file.

4. Copy the files to install into the working folder.


Copy all of the files you want to install into the working folder. These files
typically include:

• Dictionary chunks (.cnk)


• Help files (.chm)

478 IN T E G R AT I O N G U ID E
C H A P T E R 4 5 IN S TA LL E R T E M P LA TE

5. Edit the project file for the installer.


Using a text editor, open the project file (.wxs file) for the installer project. You
will make changes throughout this file. Areas to edit are indicated by comments
in the file. Specify the following:

Product ID This value is a GUID that uniquely identifies a major version of a


product. It is also called the Product Code. This value must be changed for each
major release of your product. For instance, version 8.0 and version 9.0 of a
product would have different product IDs. Any international editions of a
product must also have different product IDs.

Upgrade code This value is a GUID that identifies the product. This value
remains constant throughout the life of the product. The same value must be
used in every version of the product that is released.

Upgrade information This information specifies what previous versions of


a product this installer can upgrade. The upgrade code must be added to this
section. Also, supply the version number values that specify the maximum
(newest) version of your product that this installer can upgrade. Typically, this
will be a value large enough to include all previous versions of your product.
For example, to upgrade all versions prior to 10, use Maximum='9.9.9'.

Version A string that indicates the major, minor, build, and revision numbers
for the release. The major, minor, and build numbers are significant for
comparing versions. Be sure to use them consistently for releases of your
product. For example, version 9.0 build 1 revision 0 of a product would have
the following version string: '9.0.1.0'

Cabinet file name This string specifies the name of the cabinet (.cab) file
that will be used for the installer. Use a value that corresponds to the installer
you’re creating. For example, the cabinet file for the sample installer is
“Develop.cab”.

Component entries The component entries specify the items to be included


in the installer. Each item installed for your integration will have a separate
component in this section. Each component must be identified with a GUID
that remains constant over the life of your product to allow the Windows
Installer to properly handle updates. The following are the component entries
for the components installed by the sample integration.
<Component Id='Develop.cnk' Guid='EC747C55-814D-4fb8-8DB1-70BF67D5AFEC'
DiskId='1'>
<File Id='Develop.cnk' ShortName='Develop.cnk' Name='Develop.cnk'
Source='$(sys.CURRENTDIR)\Develop.cnk'/>
<IniFile Id='GPDICVER_INI' Name='GPDicVer.ini' Directory='INSTALLDIR'
Action='addLine' Section='General' Key='Prod3333' Value='1'/>
</Component>

<Component Id='Develop.chm' Guid='8CA10247-7A9C-48e7-9E2C-58B74E36109D'


DiskId='1'>
<File Id='Develop.chm' ShortName='Develop.chm' Name='Develop.chm'
Source='$(sys.CURRENTDIR)\Develop.chm'/>
</Component>

Notice that for the Develop.cnk component, a value is specified to be written to


the GPDictVer.ini file. This value specified should include the product ID and
install information slot number you specified when you build the dictionary
chunk with Dexterity Utilities.

INTEGRATION GUIDE 479


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Feature components This section specifies which components are included


with each feature defined by the installer. The template installer has only one
feature defined, so all components will be included in this section. The
component IDs listed here must match those you specified in the previous step.
The following are the two components included for the sample integration.
Notice that the component IDs match those defined in the previous section.

<ComponentRef Id='Develop.cnk'/>
<ComponentRef Id='Develop.chm'/>

6. Edit the localization file for the installer.


Using a text editor, open the localization file (.wxl file) for the installer project.
You will make changes throughout this file. Areas to edit are indicated by
comments in the file that state EDIT THESE.

7. Edit the launch file information.


Using a text editor, open the Data_SetFile.wxi file. This file contains information
about what will be written to and removed from the Microsoft Dynamics GP
launch file. Edit the following items:

Product ID This should be the integer product ID you use for your
integrating application.

Feature By default, this will be “Template”. If you changed the feature name
in the .wxs project file, you must change this setting to match the name you
chose.

Product information The last group of entries in this file specifies the
product information for the integrating application. These entries must match
the information that you specified in the Product Information window in
Dexterity Utilities when you created your dictionary chunk. For instance, the
following entries are used for the sample integrating application’s installer.

<Data Column="PRODID">3333</Data>
<Data Column="NAME">Sample Integrating App.</Data>
<Data Column="APPDIC">Develop.dic</Data>
<Data Column="FRMDIC">F3333.dic</Data>
<Data Column="RPTDIC">R3333.dic</Data>

8. Edit the CustomActions script file.


Using a text editor, open the CustomActions.vbs script file that is located in the
Include folder. At the beginning of this file you will see four constants that must
be updated. Edit the following items:

InstallToUpgrade For this value, specify the Upgrade Code for your
integration, with no dashes, prepended with the letters “UC”.

ApplicationDictionary This value specifies the name of the dictionary


from the previous version of the integration. The dictionary must be deleted or
moved during the update process, or the dictionary chunk for the new version
will not unchunk properly.

The template installer moves the previous version of the dictionary to the “Data” folder
and renames it to include the “Prev_” prefix. The dictionary can then be used when
upgrading the forms and reports dictionaries.

480 IN T E G R AT I O N G U ID E
C H A P T E R 4 5 IN S TA LL E R T E M P LA TE

FormsDictionary This value specifies the name of the forms dictionary for
the integration.

ReportsDictionary This value specifies the name of the reports dictionary


for the integration.

9. Compile the project.


Open a command prompt. Set the current folder to the working folder where
you are building the installer. Use the following syntax with the candle
command to compile the installer project:

candle filename.wxs

Replace filename with the name of your installer project file. The command
should process, create a .wixobj object file, and not display any errors. If errors
are displayed, correct them and compile again.

10. Link the project.


The linking process creates the .msi installer file and incorporates the
localization information. Use the following syntax with the light command to
link the installer project:

light filename.wixobj -loc locfile.wxl

Replace filename with the name of your installer project file. Replace locfile with
the name of the localization file used for your project. Again, no errors should
be reported.

11. Update the Setup.ini file.


This .ini file provides information to the Setup.msi, indicating the product name
and the .msi file to be launched. For example, the following setting are used for
the sample integrating application:

[Setup]
PROD_NAME=Sample Integrating Application
PROD_SHORT_NAME=Sample Integrating Application
INSTALL=Develop.msi

12. Update the license agreement.


The LicenseAgreement.rtf file will be displayed in the installer. The user must
agree to the license terms displayed for the installer to continue. Update this file
to include the license terms for your integration.

13. Assemble the components for the installer.


The following components are needed for the completed installer:

• Your completed .msi file


• Setup.msi
• Setup.ini
• LicenseAgreement.rtf

It’s important that you use the version of the Setup.msi file that matches the
version of Microsoft Dynamics GP your integrating application works with. For
example, if you are integrating with version 11.0 of Microsoft Dynamics GP, the
version information for Setup.msi you use should indicate this. To see the
version that Setup.msi works with, position the pointer over the Setup.msi icon
and display the tooltip. The version will be indicated in the comment.

INTEGRATION GUIDE 481


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

14. Test the completed installer.


The basic installer is complete, and can be tested in a Microsoft Dynamics GP
installation. Start the installer by double-clicking the Setup.msi file.

Launch the installer by running Setup.msi, not the installer file you created. Launching
your .msi file directly will cause an error.

Adding multiple-instance support


To allow your integration to work with multiple instances of Microsoft Dynamics
GP on a single workstation, you must perform an additional procedure for your
completed installer. This procedure applies 50 additional transforms to the installer,
corresponding to each additional instance of Microsoft Dynamics GP that can be
installed. To add multiple instance support, complete the following steps:

1. Copy the completed installer file.


Make a copy of your completed installer (.msi) file and place it in the Transform
folder where you created the installer.

2. Edit the Transform.xml file to add GUID instances.


Using a text editor, open the Transform.xml file in the Transform folder. This file
contains 50 GUIDs, one for each installed instance of your product. You must
supply a set of 50 new GUIDs for this file, replacing the text “NEW GUID” with
a GUID you have generated. The following example from the sample
integration’s Transform.xml file shows the format required for the GUIDs:

<INST01>{7FE7E638-52F5-437f-BE57-A64F0BE549A8}</INST01>
<INST02>{462D0913-E2F2-4869-A29C-844BEFD8D30D}</INST02>

The set of 50 GUIDs must be changed each time you change the product code for your
application.

3. Create a temporary folder.


In the Transform folder, create a temporary folder named “Temp”. This folder
will contain the code blocks that will be merged into your .msi installer file.

4. Generate and apply the transforms.


Use the following syntax with the GenerateTransforms.exe application to
generate and apply the transforms to your installer:

GenerateTransforms.exe filename.msi "Temp\\"

482 IN T E G R AT I O N G U ID E
C H A P T E R 4 5 IN S TA LL E R T E M P LA TE

Replace filename with the name of the installer file you created. You will see the
processing occur as each transform is applied to the installer file. The completed
.msi file will be somewhat larger after all of the transforms have been added.

5. Test the completed installer.


Be sure you have at least two instances of Microsoft Dynamics GP on your
system. Run the installer for your integration. You will be asked which instance
of Microsoft Dynamics GP you want to install the integration into.

INTEGRATION GUIDE 483


484 IN T E G R AT I O N G U ID E
Chapter 46: Patches
When using Windows Installer Services, patch files (files with a .msp extension) are
used to update installed applications. Information about using patches is divided
into the following sections:

• Patch overview
• Creating a patch

Patch overview
If you use the Windows Installer to install your integrating application, you must
use patches created with Windows Installer to apply updates for your integration.
Patches are typically used for small changes, like code corrections. They’re typically
not used for large changes like table structure changes. Patches are easily applied by
the user or by the automatic update process in Microsoft Dynamics GP.

Patch files have the additional advantage of being included in the “repair”
operations that can be performed by Windows Installer. A repair operation will
automatically re-apply any patches that have been installed for your integration,
ensuring that the most current version is being used after a repair.

This is why when you use Windows Installer for your integration, you shouldn’t manually
update an installation with dictionary chunk (.cnk) files. The repair process won’t include
any of the updates you applied manually.

When you create patch, you will begin by creating a full build of your updated
integrating application. Be sure that you’re incrementing only the build number for
the updated version. The major and minor version numbers should remain
unchanged. New installations of your integration will use the full installer for the
updated version of your integration. Existing installations of your integration will
use the install patch to move to the updated version of your integration.

A WiX template project for a patch is included in the Installer folder within the
Samples folder of the Dexterity install. The following are the basic steps needed to
create an installer patch using the WiX template provided:

1. Complete the installer for the updated version of your integration.


This is a complete installer for your integration, created using the procedure
described in Creating an installer on page 478. The build number for this
updated version must have been increased.

2. Locate the “baseline” installer for your integration.


The “baseline” installer for your integration is the complete installer you
created for the initial version of the integration. The patch will contain the
differences between the “baseline” installer and the updated installer. In effect,
this makes the patch cumulative, including any of the updates in previous
patches.

3. Extract the baseline and updated installers.


This process expands the installer files into their individual components so the
two versions can be compared. This tells the installer which components need
to be included.

INTEGRATION GUIDE 485


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

4. Modify the WiX project file.


A separate WiX project file is used when creating a patch. You will use a text
editor to modify the template patching project included with Dexterity,
specifying characteristics for the patch you’re creating.

5. Build the source for the patch.


Using tools from the WiX toolset, you will create the Windows Installer .pcp file
that contains the information needed to create the patch.

6. Create the patch file.


Using the MsiMsp.exe application included in the Windows Installer SDK, you
will create the patch for your integration.

Creating a patch
To create a patch using the WiX template, complete the following steps. As an
example, the steps needed to create a patch for the sample integrating application
are described.

1. Create a working folder.


The steps for creating the patch will be performed in the working folder. For
this example, the folder is named “Sample Patch” and is located at the root
level.

2. Copy the two installers to the working folder.


These are the complete working baseline installer, and the updated installer. For
this example, these are Develop.msi and Develop SP1.msi.

3. Create folders for the two installers.


Create a folder for the “baseline” installation, and another folder for the
updated installer. The files from each installer will be placed in these folders.
For this example, the folders are named “Base Version” and “New Version”.

486 IN T E G R AT I O N G U ID E
C H A P T E R 4 6 P A TC HE S

4. Extract the two installers.


Open a command prompt. Set the current folder to the working folder where
you are building the patch. Use the following syntax with the msiexec
command to extract the contents of each installer file:

msiexec /a file.msi /qn TARGETDIR=path ADMIN_PATCH_CREATION=1


/l*v logfile.log

Replace file with the name of the MSI file you’re extracting. Replace path with
the path to the folder where you want the extracted files to be placed. Replace
logfile with the name of the log that will contain status information about the
process.

For example, the following two commands are used to extract the baseline and
updated installers for the sample integration:

msiexec /a "Develop.msi" /qn TARGETDIR="C:\Sample Patch\Base Version"


ADMIN_PATCH_CREATION=1 /l*v BaseVersion.log

msiexec /a "Develop SP1.msi" /qn TARGETDIR="C:\Sample Patch\New


Version" ADMIN_PATCH_CREATION=1 /l*v NewVersion.log

After the extraction, the log files will have been created and the folders will
have the contents of the two installers.

5. Copy the Patch.wxs template.


Copy the Patch.wxs template into the working folder from the Installer folder in
the Samples folder for Dexterity.

6. Modify the Patch.wxs template.


Using a text editor, modify the Patchwxs template. You will make changes
throughout this file. Specify the following:

Patch ID This value is a GUID that uniquely identifies the patch.

Output path This string specifies the name given to the patch file, as well as
the location it will be placed.

Patch information These strings specify the comments, description, and


manufacturer for the patch.

Patch metadata These strings specify the description, display name,


manufacturer, and so on for the patch.

UpgradeImage This element specifies the locations of the two installers that
will be compared to create the patch. For the UpgradeImage src attribute,
specify the installer file in the “New Version” folder. For the TargetImage src
attribute, specify the installer file in the “Base Version” folder. For example, the
following is the UpgradeImage element for the sample patch:

<UpgradeImage Id="SP1U" src="C:\Sample Patch\New Version\Develop


SP1.msi">
<TargetImage Id="SP1T" src="C:\Sample Patch\Base Version\Develop.msi"
Order="1" Validation="0x00000920"></TargetImage>
</UpgradeImage>

INTEGRATION GUIDE 487


PA RT 9 P A C K A G I N G Y O U R A P P L I C A TI O N

Target product codes These GUID values identify the individual instances
of your integration installed on a Microsoft Dynamics GP system. The first
TargetProductCode must be set to the Product Id GUID specified at the
beginning of the original installation’s .wxs file. The remaining 50 GUIDs must
be set to the 50 GUIDs used in the Transform.xml file used for multiple-instance
support.

7. Compile the project.


Open a command prompt. Set the current folder to the working folder where
you are building the patch. Use the following syntax with the candle command
to compile the project:

candle filename.wxs

Replace filename with the name of your patch project file. The command should
process, create a .wixobj object file, and not display any errors. If errors are
displayed, correct them and compile again.

8. Link the project and create the .pcp file.


The linking process creates the .pcp file that will be used to make the patch. Use
the following syntax with the light command to link the patch project:

light filename.wixobj

Replace filename with the name of your patch project file. Again, no errors
should be reported.

9. Create the patch (.msp) file.


Locate the MsiMsp.exe application, which is part of the Windows Installer SDK
included with the Win32 Platform SDK. Typically, this file will be found in
C:\Program Files\Microsoft SDK\Samples\sysmgmt\msi\Patching\ folder.

You may want to consider adding the location of this file to the PATH environment
variable.

Execute the following command to create the .msp file:

MsiMsp.exe -s PCPfile.pcp -p patch.msp -l logfile.log

Replace PCPfile with the name of the .pcp file you created in the previous step.
Replace patch with the name you want to use for the patch file. Replace logfile
with the name of the log to which results will be written.

488 IN T E G R AT I O N G U ID E
C H A P T E R 4 6 P A TC HE S

For example, the following command is used to create the patch for the sample
integration:

MsiMsp.exe -s Patch.pcp -p "Develop Patch SP1.msp" -l "SP1Patch.log"

You will receive a warning indicating the versions of the two installers do not
match. That’s OK for this patch, so click Yes to proceed.

The patch file will be created.

10. Test the completed patch.


The patch is complete, and can be tested in a Microsoft Dynamics GP
installation. When you install the patch, it will verify that a version of your
integration exists that is valid to upgrade. If one exists, the patch will be applied
and appear in Add/Remove Programs. This is shown in the following
illustration:

When you launch Microsoft Dynamics GP, the updated code will be merged in.

INTEGRATION GUIDE 489


490 IN T E G R AT I O N G U ID E
PART 11: SCRIPT REFERENCE
Part 11: Script Reference
This portion of the documentation contains detailed descriptions of several
procedures and functions defined in the Dynamics.dic dictionary that you will use
while developing your integration. The procedures and functions are divided into
the following categories:

• Area Page scripts


• Command scripts
• Home page scripts
• List scripts
• Menu scripts
• Report scripts
• Security scripts
• Setup Checklist scripts
• Shortcut scripts
• SmartList scripts
• SQL scripts
• Toolbar scripts
• Unified Communications scripts

492 IN T E G R AT I O N G U ID E
Area Page scripts
The following scripts are used when defining a new Area Page for an integrating
application:

• AddCategory
• AddCommand
• AddContentArea
• AddItems
• Create
• Display

INTEGRATION GUIDE 493


A R E A P A G E S C R I P T S A D D C A T E G O R Y

AddCategory

Description The AddCategory procedure of the syAreaPageXML form adds a category to the
current content area of the Area Page. It also adds the commands from the specified
command list to the category.

Syntax AddCategory of form syAreaPageXML, XML_state, command_list, display_name,


expanded

Parameters • XML_state – A composite parameter of the type AreaPageXMLState that is used to


maintain state information for the Area Page.

• command_list – The command list that contains the commands to be added to the
category.

• display_name – A string parameter that specifies the title displayed for the category.

• expanded – A boolean that specifies whether the category is expanded. The value
true specifies that it is, while false specifies that it is not.

Comments The following illustration shows a category that is added to a content area for an
Area Page for Microsoft Dynamics GP.

This is a category, with


the items from the
command list displayed.

Examples The following example adds the Inventory category to the current content area of
the Area Page being defined.

local AreaPageXMLState XMLState;

{Hide the customize link for the page}


call Command_HideAndDisable, command CustomizeHomePage of form
➥ Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";
if not empty(XMLState:XMLDoc) then
call AddContentArea of form syAreaPageXML, XMLState, getmsg(451)
{Reports}, IMAGE_REPORTS of form syAreaPageXML, true, 1;

call AddCategory of form syAreaPageXML, XMLState, command


CL_Inventory_Reports of form Command_Inventory, "Inventory", true;
end if;

call Display of form syAreaPageXML, XMLState;

494 IN T E G R AT I O N G U ID E
A R E A P A G E S C R I P T S A D D C O M M A N D

AddCommand

Description The AddCommand method defined for the syAreaPageXML form adds a single
command to the current content area.

Syntax AddCommand of form syAreaPageXML, XML_state, command

Parameters • XML_state – A composite parameter of the type AreaPageXMLState that is used to


maintain state information for the Area Page.

• command – The command to be added to the content area.

Examples The following example adds individual commands to the various content areas for
an the Area Page in the sample integrating application.

local AreaPageXMLState XMLState;

call Command_HideAndDisable, command CustomizeHomePage of form


Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";

{Add items if needed}


if not empty(XMLState:XMLDoc) then
{Cards}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(9823) {Cards}, IMAGE_CARDS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Lead_Maintenance of form Command_IG_Sample;

{Reports}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(451) {Reports}, IMAGE_REPORTS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Reports
➥ of form Command_IG_Sample;

{Inquiry}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(4426) {Inquiry}, IMAGE_INQUIRY of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Inquiry
➥ of form Command_IG_Sample;

{Setup}
call AddContentArea of form syAreaPageXML, XMLState, getmsg(860) {Setup},
➥ IMAGE_SETUP of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Contact_History_Setup of form Command_IG_Sample;
end if;

{Display the Area Page}


call Display of form syAreaPageXML, XMLState;

INTEGRATION GUIDE 495


A R E A P A G E S C R I P T S A D D C O N T E N T A R E A

AddContentArea

Description The AddContentArea method defined for the syAreaPageXML form adds a top-
level content area to the Area Page.

Syntax AddContentArea of form syAreaPageXML, XML_state, display_name, image,


expanded, column

Parameters • XML_state – A composite parameter of the type AreaPageXMLState that is used to


maintain state information for the Area Page.

• display_name – A string parameter that specifies the title displayed for the content
area. Consider using one of the getmsg() function and one of the following message
values to retrieve the string to display for the standard content areas:

Content area Message number


Cards 9823
Inquiry 4426
Reports 451
Routines 11456
Setup 860
Transactions 1232
Utilities 4080

• image – A string parameter that specifies the relative path to the image to be
displayed for the content area. The path is relative to the Background folder found
in the Microsoft Dynamics GP installation. Use one of the following constants
defined for the syAreaPageXML form to specify the image for the standard content
areas:

Content area Constant


Cards IMAGE_CARDS
Inquiry IMAGE_INQUIRY
Reports IMAGE_REPORTS
Routines IMAGE_ROUTINES
Setup IMAGE_SETUP
Transactions IMAGE_TRANSACTIONS
Utilities IMAGE_UTILITIES

• expanded – A boolean that specifies whether the content area is expanded. The value
true specifies that it is, while false specifies that it is not.

• column – An integer that specifies the column the content area is located in. Indicate
column 1 or column 2.

496 IN T E G R AT I O N G U ID E
A R E A P A G E S C R I P T S A D D C O N T E N T A R E A

Comments The following illustration shows the Cards content area that was added to an Area
Page for Microsoft Dynamics GP. It contains one item.

This is the content area.

Examples The following example adds the Cards content area to the Area Page being defined.
The content area is added to column 1.

local AreaPageXMLState XMLState;

{Hide the customize link for the page}


call Command_HideAndDisable, command CustomizeHomePage of form
➥ Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";

{Add items if needed}


if not empty(XMLState:XMLDoc) then

call AddContentArea of form syAreaPageXML, XMLState,


➥ getmsg(9823) {Cards}, IMAGE_CARDS of form syAreaPageXML, true, 1;

end if;

call Display of form syAreaPageXML, XMLState;

INTEGRATION GUIDE 497


A R E A P A G E S C R I P T S A D D I T E M S

AddItems
Description The AddItems method defined for the syAreaPageXML form adds the items
defined by a command list to the current content area. Unlike the AddCategory
procedure, the items are not part of a collapsible category.

Syntax AddItems of form syAreaPageXML, XML_state, command_list

Parameters • XML_state – A composite parameter of the type AreaPageXMLState that is used to


maintain state information for the Area Page.

• command_list – The command list that contains the commands to be added to the
content area.

Examples The following example adds the items from the CL_Purchasing_Reports command
list to the content area for the Area Page being defined.

local AreaPageXMLState XMLState;

call Command_HideAndDisable, command CustomizeHomePage of form


Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";

{Add items if needed}


if not empty(XMLState:XMLDoc) then

call AddContentArea of form syAreaPageXML, XMLState,


➥ getmsg(451) {Reports}, IMAGE_REPORTS of form syAreaPageXML, true, 1;

call AddItems of form syAreaPageXML, XMLState, command


➥ CL_Purchasing_Reports of form Command_Purchasing;

end if;

call Display of form syAreaPageXML, XMLState;

498 IN T E G R AT I O N G U ID E
A R E A P A G E S C R I P T S C R E A T E

Create

Description The Create procedure defined for the syAreaPageXML form creates a new Area
Page.

Syntax Create of form syAreaPageXML, XML_state, display_name

Parameters • XML_state – A composite parameter of the type AreaPageXMLState that is used to


maintain state information for the Area Page.

• display_name – A string parameter that specifies the title displayed at the top of the
Area Page.

Examples The following example creates and displays an Area Page for the sample integrating
application.

local AreaPageXMLState XMLState;

call Command_HideAndDisable, command CustomizeHomePage of form


Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";

{Add items if needed}


if not empty(XMLState:XMLDoc) then
{Cards}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(9823) {Cards}, IMAGE_CARDS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Lead_Maintenance of form Command_IG_Sample;

{Reports}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(451) {Reports}, IMAGE_REPORTS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Reports
➥ of form Command_IG_Sample;

{Inquiry}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(4426) {Inquiry}, IMAGE_INQUIRY of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Inquiry
➥ of form Command_IG_Sample;

{Setup}
call AddContentArea of form syAreaPageXML, XMLState, getmsg(860) {Setup},
➥ IMAGE_SETUP of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Contact_History_Setup of form Command_IG_Sample;
end if;

{Display the Area Page}


call Display of form syAreaPageXML, XMLState;

INTEGRATION GUIDE 499


A R E A P A G E S C R I P T S D I S P L A Y

Display

Description The Display procedure defined for the syAreaPageXML form displays an Area
Page.

Syntax Display of form syAreaPageXML, XML_state

Parameters • XML_state – A composite parameter of the type AreaPageXMLState that is used to


maintain state information for the Area Page. This specifies the content to display
for the Area Page.

Examples The following example creates and displays an Area Page for the sample integrating
application.

local AreaPageXMLState XMLState;

call Command_HideAndDisable, command CustomizeHomePage of form


Command_System;

{Add items to the Area page}


call Create of form syAreaPageXML, XMLState, "Sample";

{Add items if needed}


if not empty(XMLState:XMLDoc) then
{Cards}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(9823) {Cards}, IMAGE_CARDS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Lead_Maintenance of form Command_IG_Sample;

{Reports}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(451) {Reports}, IMAGE_REPORTS of form syAreaPageXML, true, 1;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Reports
➥ of form Command_IG_Sample;

{Inquiry}
call AddContentArea of form syAreaPageXML, XMLState,
➥ getmsg(4426) {Inquiry}, IMAGE_INQUIRY of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command IG_Lead_Inquiry
➥ of form Command_IG_Sample;

{Setup}
call AddContentArea of form syAreaPageXML, XMLState, getmsg(860) {Setup},
➥ IMAGE_SETUP of form syAreaPageXML, true, 2;
call AddCommand of form syAreaPageXML, XMLState, command
➥ IG_Contact_History_Setup of form Command_IG_Sample;
end if;

{Display the Area Page}


call Display of form syAreaPageXML, XMLState;

500 IN T E G R AT I O N G U ID E
Command scripts
The following scripts are used when working with commands for an integrating
application:

• Command_HideAndDisable
• Command_ShowAndEnable

INTEGRATION GUIDE 501


C O M M A N D S C R I P T S C O M M A N D _ H I D E A N D D I S A B L E

Command_HideAndDisable

Description The Command_HideAndDisable procedure is used to hide and disable a


command. This is the preferred method of hiding and disabling a command for an
integration.

Syntax Command_HideAndDisable, command

Parameters • command – The command to be hidden and disabled.

Comments By using a common procedure for hiding and disabling commands, Microsoft
Dynamics GP can control what action is performed for the command. For example,
Microsoft Dynamics GP can choose to display the commands, but leave them in the
disabled state so they cannot be used. This can be useful so that all commands can
be seen.

Use the Command_HideAndDisable procedure after you have checked any


security settings for your integration, typically in the form pre script of your
integration’s command form. If access should not be granted to the commands in
your integration, use this procedure to hide and disable them.

Examples The following example is the form pre script for a command form. It checks the
security access for the integration. If access should not be granted, it disables the
commands for the integration.

local boolean security_access;

{Use the appropriate routine to check security access}


security_access = CheckIntegrationSecurity();

if security_access = false then


call Command_HideAndDisable, command CMD_Inquiry1;
call Command_HideAndDisable, command CMD_Maintenance1;
call Command_HideAndDisable, command CMD_List1;
end if;

502 IN T E G R AT I O N G U ID E
C O M M A N D S C R I P T S C O M M A N D _ S H O W A N D E N A B L E

Command_ShowAndEnable

Description The Command_ShowAndEnable procedure is used to show and enable a


command. This is the preferred method of showing and enabling a command for an
integration.

Syntax Command_ShowAndEnable, command

Parameters • command – The command to be shown and enabled.

Comments By using a common procedure for showing and enabling commands, Microsoft
Dynamics GP can control what action is performed for the command. For example,
Microsoft Dynamics GP can choose to display the commands, but leave them in the
disabled state so they cannot be used. This can be useful so that all commands can
be seen.

Use the Command_ShowAndEnable procedure after you have checked any


security settings for your integration, typically where you allow registration
information to be entered. If access should be granted to the commands in your
integration, use this procedure to show and enable them.

Examples The following example checks the security access for the integration. If access
should be granted, it shows and enables the commands for the integration.

local boolean security_access;


local string user_entry;

if getstring ("Please enter registration key", false, user_entry) then


{Use the appropriate routine to check security access}
security_access = CheckRegistrationKey(user_entry);

if security_access = true then


call Command_ShowAndEnable, command CMD_Inquiry1;
call Command_ShowAndEnable, command CMD_Maintenance1;
call Command_ShowAndEnable, command CMD_List1;
end if;
end if;

INTEGRATION GUIDE 503


504 IN T E G R AT I O N G U ID E
Home page scripts
The following scripts are used when an integrating application defines or adds
items to Home Pages:

• AddMetric
• AddMyReport()
• AddNew
• AddQuickLink
• AddSection
• AddSubSection
• Create()
• Commit()
• Destroy
• Exists()
• Get()
• Release
• SetIndex
• SetUserRole

INTEGRATION GUIDE 505


H O M E P A G E S C R I P T S A D D M E T R I C

AddMetric

Description The AddMetric procedure of the form syHomePageMetric form adds a metric item
to the template Home Page for a user.

Syntax AddMetric, user_ID, dict_ID, metric_ID

Parameters • user_ID – A string specifying the ID of the current user for which the metric is being
added.

• dict_ID – The ID of the dictionary that contains the definition of the metric.

• metric_ID – An integer that specifies the ID of the metric being added. Typically a
constant is used for the metric ID.

Comments This procedure simply adds the metric to the Home Page template. Other scripts
must be added to your dictionary to process the metric.

Examples The following example trigger processing procedure uses the AddMetric procedure
to add a metric to the Home Page template for the Operations Manager role. The
constant METRIC_TOP5LEADS was defined to identify the metric.

in integer iIndustry;
in integer iUserRole;

local string sUserID;

sUserID = 'User ID' of globals;

{Add a Metric for the Operations Manager}


if iUserRole = ROLE_OPSMGR then
call AddMetric of form syHomePageMetric,
sUserID,
IG_PROD_ID,
METRIC_TOP5LEADS;
end if;

506 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S A D D M Y R E P O R T ()

AddMyReport()

Description The AddMyReport() function of the syMyReportsObj form adds a report item to
the My Reports section of the template Home Page for a user.

Syntax AddMyReport(report_data {,sequence_number})

Parameters • report_data – A composite of type syReportData that specifies characteristics of the


report item to be added to the Home Page. Refer to syReportData on page 324 for a
description of this composite.

• sequence_number – An optional returned long integer that contains the sequence


number assigned to the report item.

Return value An integer indicating whether the report item was added. The constant value OKAY
indicates it was, while any other value indicates it was not.

Comments When you add a report using this function, it will also be included in the Report List
displayed for the user.

Examples The following example trigger processing procedure uses the AddMyReport()
function to add a simple report item to the Home Page template for a role. Notice
how the items in the syReportData composite are filled in to indicate which report is
being added.

in integer iUserRole;

local syReportData RptData;

{Add a simple report for all roles}


RptData:'Report Type' = REPORTTYPE_SIMPLE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = IG_PROD_ID;
RptData:'Report Series ID' = 1;
RptData:'Report ID' = ReptID_LeadsSimple;
RptData:'Report Option Name' = "Leads";
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);
RptData:'User ID' = 'User ID' of globals;
RptData:'My Report Name' = "Leads";

AddMyReport(RptData) of form syMyReportsObj;

INTEGRATION GUIDE 507


H O M E P A G E S C R I P T S A D D N E W

AddNew

Description The AddNew procedure of the syHomePage form starts the process of adding a
Home Page for a user.

Syntax AddNew, HomePageState, UserID, Display, Refresh, UserRole

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

• UserID – A string that specifies the user for which the new Home Page is being
created.

• Display – A boolean that specifies whether the Home Page will be displayed by
default for the user. The value true indicates the page will be displayed, while false
indicates it will not.

• Refresh – A boolean that specifies whether the Home Page will be automatically
refreshed at the standard one-hour interval. The value true indicates the page will
be refreshed, while false indicates it will not.

• UserRole – An integer that specifies the role for which the Home Page is being
created. This typically corresponds to the constant value created for the new role.

Examples Refer to the example for Create().

508 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S A D D Q U I C K L I N K

AddQuickLink

Description The AddQuickLink procedure of the syHomePageQuickLinks form adds a Quick


Link to the template Home Page for a user.

Syntax AddQuickLink, UserID, TypeID, CmdID, CmdFormID, CmdDictID, DisplayName,


TargetString1, TargetString2, TargetString3, TargetLong1, TargetLong2, TargetLong3,
TargetLong4, TargetLong5

Parameters • UserID – A string specifying the ID of the current user for which the Quick Link is
being added.

• TypeID – An integer specifying the type of link being added. The value corresponds
to one of the following constants that are defined as part of the syHomePageMain
form:

Constant Description
QL_COMMAND A standard command action
QL_EXTERNAL A link to an external action
QL_WEBPAGE A link to a web page

• CmdID – For command links, the resource ID of the command to use for the link.
For the other types of links, specify 0.

• CmdFormID – For command links, the resource ID of the command form that
contains the definition of the command used for the link. For the other types of
links, specify 0.

• CmdDictID – For command links, the ID of the dictionary that contains the
command you are using for the link. For the other types of links, specify 0.

• DisplayName – A string specifying the name to display for the Quick Link.

• TargetString1 – A target string for the Shortcut Bar. Specify the empty string.

• TargetString2 – A target string for the Shortcut Bar. Specify the empty string.

• TargetString3 – A target string for the Shortcut Bar. Specify the empty string.

• TargetLong1 – A target long integer for the Shortcut Bar. Specify the value 0.

• TargetLong2 – A target long integer for the Shortcut Bar. Specify the value 0.

• TargetLong3 – A target long integer for the Shortcut Bar. Specify the value 0.

• TargetLong4 – A target long integer for the Shortcut Bar. Specify the value 0.

• TargetLong5 – A target long integer for the Shortcut Bar. Specify the value 0.

INTEGRATION GUIDE 509


H O M E P A G E S C R I P T S A D D Q U I C K L I N K

Examples The following example shows the AddQuickLink procedure being used to add a
command link to a Home Page template.
local string sUserID;

sUserID = 'User ID' of globals;

call AddQuickLink of form syHomePageQuickLinks,


sUserID,
QL_COMMAND of form syHomePageMain,
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
resourceid(form Command_IG_Sample),
IG_PROD_ID,
Window_GetMainWindowTitle(IG_PROD_ID, technicalname(form
➥ IG_Lead_Maintenance)),
"","","",0,0,0,0,0;

The following example shows the AddQuickLink procedure being used to add an
external link to a Home Page template.

local string sUserID;

sUserID = 'User ID' of globals;

call AddQuickLink of form syHomePageQuickLinks,


sUserID,
QL_EXTERNAL of form syHomePageMain,
0,
0,
0,
"Notepad",
"c:\Windows\Notepad.exe",
"","",0,0,0,0,0;

The following example shows the AddQuickLink procedure being used to add a
web page link to a Home Page template.

local string sUserID;

sUserID = 'User ID' of globals;

call AddQuickLink of form syHomePageQuickLinks,


sUserID,
QL_WEBPAGE of form syHomePageMain,
0,
0,
0,
"Microsoft",
"http://www.microsoft.com",
"","",0,0,0,0,0;

510 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S A D D S E C T I O N

AddSection

Description The AddSection procedure of the syHomePageLayout form adds a section to the
Home Page being created for a user.

Syntax AddSection, UserID, SectionID, DictionaryID, ColumnNumber, Visible

Parameters • UserID – A string that specifies the user for which the new Home Page is being
created.

• SectionID – A constant defined for the syHomePageMain form that specifies which
section is being added to the Home Page. The value corresponds to one of the
following constants:

Constant Description
METRICS The Metrics section of the Home Page
MYREPORTS The My Reports section of the Home Page
OUTLOOK The Outlook section of the Home Page
QUICKLINKS The Quick Links section of the Home Page
TODO The To Do section of the Home Page

• DictionaryID – An integer specifying the dictionary ID of the application hosting the


Home Page. In all cases, use the constant DYNAMICS.

• ColumnNumber – An integer specifying the column into which the section will be
placed. Use the value 1 or 2 for the column number.

• Visible – A boolean specifying whether the section will be displayed. The value true
indicates the section will be displayed, while the value false indicates the section
will be hidden.

Comments You must define all sections for the Home Page. If you don’t want a section to be
shown, use the Visible parameter to set its state to hidden.

Examples Refer to the example for Create().

INTEGRATION GUIDE 511


H O M E P A G E S C R I P T S A D D S U B S E C T I O N

AddSubSection

Description The AddSubSection procedure of the syHomePageSubSection form adds a


subsection to the specified section of the Home Page being created for a user.

Syntax AddSubSection, UserID, SectionID, SubSectionID, DictionaryID, Visible, UserDefined

Parameters • UserID – A string that specifies the user for which the new Home Page is being
created.

• SectionID – A constant defined for the syHomePageMain form that specifies to


which section the sub-section is being added to for the Home Page. The value
corresponds to one of the following constants:

Constant Description
METRICS The Metrics section of the Home Page
MYREPORTS The My Reports section of the Home Page
OUTLOOK The Outlook section of the Home Page
QUICKLINKS The Quick Links section of the Home Page
TODO The To Do section of the Home Page

• SubSectionID – A constant defined for the syHomePageMain form that specifies the
sub-section being added. The value corresponds to one of the following constants:

Section Constant Description


Outlook CALENDAR_SUBSECTION The Outlook Calendar
INBOX_SUBSECTION The Outlook Inbox
To Do REMINDERS_SUBSECTION The Dynamics GP Reminders
TASKS_SUBSECTION The Dynamics GP Tasks

• DictionaryID – An integer specifying the dictionary ID of the application hosting the


Home Page. In all cases, use the constant DYNAMICS.

• Visible – A boolean specifying whether the sub-section will be displayed. The value
true indicates the sub-section will be displayed, while the value false indicates the
sub-section will be hidden.

• UserDefined – A string parameter that isn’t currently used. Use the empty string ("")
for this parameter.

Comments You must define all sub-sections for the Home Page. If you don’t want a sub-section
to be shown, use the Visible parameter to set its state to hidden.

Examples Refer to the example for Create().

512 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S C R E A T E ()

Create()

Description The Create() function of the syHomePage form populates the state object for a
Home Page.

Syntax Create( HomePageState, table HomePageTable)

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

• table HomePageTable – The syHomePage table, which stores information about the
Home Page for each user in Microsoft Dynamics GP.

Return value An integer indicating the status of the operation. The value corresponding to the
constant OKAY indicates the operation completed successfully. Any other value
indicates the operation failed.

Examples The following example is the IG_HomePage_BuildHomePage procedure for the


sample integrating application. This procedure creates a new Home Page for the
current user when they have chosen the “Lead Generation” role. The ID for this role
is passed into the procedure.

The procedure uses the Create() function to create the state object for the Home
Page. The Exists() function is used to determine whether the user already has a
Home Page defined. If one hasn’t been defined, the AddNew procedure is used to
create one. If a Home Page already exists for the user, the SetIndex procedure, Get()
function, and SetUserRole procedure are used to retrieve the existing entry. The
AddSection and AddSubSection procedures are called to define the Home Page
content. Quick Links and Metrics are added. Finally, the Release and Destroy
procedures dispose of the Home Page object.

in integer iIndustry;
in integer iUserRole;

local syHomePageState HomePageState;


local long nStatus;
local string sUserID;

if iUserRole = ROLE_LEADGENERATOR then

sUserID = 'User ID' of globals;

nStatus = Create(HomePageState, table syHomePage) of form syHomePage;


if nStatus <> OKAY then
abort script;
end if;

{Add the main record}


if not Exists(sUserID) of form syHomePage then
call AddNew of form syHomePage, HomePageState, sUserID, true, true,
➥ iUserRole;
nStatus = Commit(HomePageState) of form syHomePage;
else
call SetIndex of form syHomePage, HomePageState, sUserID;
nStatus = Get(HomePageState,CHG + EQUAL) of form syHomePage;

INTEGRATION GUIDE 513


H O M E P A G E S C R I P T S C R E A T E ( )

if nStatus = OKAY then


call SetUserRole of form syHomePage, HomePageState, iUserRole;
nStatus = Commit(HomePageState) of form syHomePage;
end if;
end if;

{Setup the Layout records}


call AddSection of form syHomePageLayout, sUserID, TODO of form
➥ syHomePageMain, DYNAMICS, 1, true;
call AddSubSection of form syHomePageSubSection, sUserID,TODO of form
➥ syHomePageMain, REMINDERS_SUBSECTION of form syHomePageMain, DYNAMICS,
➥ true, "";
call AddSubSection of form syHomePageSubSection, sUserID,TODO of form
➥ syHomePageMain, TASKS_SUBSECTION of form syHomePageMain, DYNAMICS,
➥ true, "";

call AddSection of form syHomePageLayout, sUserID, MYREPORTS of form


➥ syHomePageMain, DYNAMICS, 1, true;

call AddSection of form syHomePageLayout, sUserID, QUICKLINKS of form


➥ syHomePageMain, DYNAMICS, 2, true;
call AddSection of form syHomePageLayout, sUserID, METRICS of form
➥ syHomePageMain, DYNAMICS, 2, true;

call AddSection of form syHomePageLayout, sUserID, OUTLOOK of form


➥ syHomePageMain, DYNAMICS, 1, false;
call AddSubSection of form syHomePageSubSection, sUserID,OUTLOOK of form
➥ syHomePageMain, INBOX_SUBSECTION of form syHomePageMain, DYNAMICS,
➥ false, "";
call AddSubSection of form syHomePageSubSection, sUserID,OUTLOOK of form
➥ syHomePageMain, CALENDAR_SUBSECTION of form syHomePageMain, DYNAMICS,
➥ false, str(2);

{Add the QuickLinks}


call AddQuickLink of form syHomePageQuickLinks,
sUserID,
QL_COMMAND of form syHomePageMain,
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
resourceid(form Command_IG_Sample),
IG_PROD_ID,
Window_GetMainWindowTitle(IG_PROD_ID, technicalname(form
➥ IG_Lead_Maintenance)),
"";

{Add Metrics}
call AddMetric of form syHomePageMetric,
sUserID,
IG_PROD_ID,
METRIC_TOP5LEADS;

{Perform any cleanup necessary}


call Release of form syHomePage, HomePageState;
call Destroy of form syHomePage, HomePageState;

end if;

514 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S C O M M I T ()

Commit()

Description The Commit() function of the syHomePage form commits the settings for the Home
Page.

Syntax Commit( HomePageState)

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

Return value An integer indicating the status of the operation. The value corresponds to one of
the following constants:

Constant Error type


OKAY No Error
DUPLICATE Another user has created the page

Examples Refer to the example for Create().

INTEGRATION GUIDE 515


H O M E P A G E S C R I P T S D E S T R O Y

Destroy

Description The Destroy procedure of the syHomePage form disposes of the state object for the
Home Page.

Syntax Destroy, HomePageState

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

Examples Refer to the example for Create().

516 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S E X I S T S ()

Exists()

Description The Exists() function of the syHomePage form indicates whether a Home Page has
been created for the specified user in Microsoft Dynamics GP.

Syntax Exists( UserID)

Parameters • UserID – A string that specifies the user for which the Home Page creation state is
being determined.

Return value A boolean. The value true indicates a Home Page exists for the user, while the value
false indicates one does not.

Examples Refer to the example for Create().

INTEGRATION GUIDE 517


H O M E P A G E S C R I P T S G E T ()

Get()

Description The Get() function of the syHomePage form retrieves the settings for the specified
item from the Home Page table.

Syntax Get( HomePageState, Operation)

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

• Operation – An integer that specifies the operation to perform. The value


corresponds to one of the following constant expressions:

Constant expression Description


GET + EQUAL Read the specific item from the table specified by the
HomePageState composite.
GET + FIRST Read the first item from the table specified by the
HomePageState composite.
GET + LAST Read the last item from the table specified by the
HomePageState composite.
GET + PREV Read the previous item from the table specified by the
HomePageState composite.
GET + NEXT Read the next item from the table specified by the
HomePageState composite.
CHG + EQUAL Read and lock the specific item from the table specified by the
HomePageState composite.
CHG + FIRST Read and lock the first item from the table specified by the
HomePageState composite.
CHG + LAST Read and lock the last item from the table specified by the
HomePageState composite.
CHG + PREV Read and lock the previous item from the table specified by
the HomePageState composite.
CHG + NEXT Read and lock the next item from the table specified by the
HomePageState composite.
ADDNEW + EQUAL Create the specific item in the table specified by the
HomePageState composite.

Return value An integer indicating the result of the operation. The value corresponds to one of
the following constants:

Constant Error type


OKAY No Error
LOCKED Locked Record
EOF End of File
DUPLICATE Duplicate Record
MISSING Missing
RECORDCHANGED Changed Record

Examples Refer to the example for Create().

518 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S R E L E A S E

Release

Description The Release procedure of the syHomePage form releases the record in the table for
the current Home Page.

Syntax Release, HomePageState

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

Examples Refer to the example for Create().

INTEGRATION GUIDE 519


H O M E P A G E S C R I P T S S E T I N D E X

SetIndex

Description The SetIndex procedure of the syHomePage form sets the key value for the
specified user so the Home Page for that user can be retrieved.

Syntax SetIndex, HomePageState, UserID

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

• UserID – A string that specifies the user for which the Home Page information is
being retrieved.

Examples Refer to the example for Create().

520 IN T E G R AT I O N G U ID E
H O M E P A G E S C R I P T S S E T U S E R R O L E

SetUserRole

Description The SetUserRole procedure of the syHomePage form sets the user role for the the
Home Page.

Syntax SetUserRole, HomePageState, UserRole

Parameters • HomePageState – A composite parameter of the type syHomePageState that is used


to maintain state information for the Home Page.

• UserRole – An integer that specifies the role for the Home Page. This typically
corresponds to the constant value created for each role.

Examples Refer to the example for Create().

INTEGRATION GUIDE 521


522 IN T E G R AT I O N G U ID E
List scripts
The following scripts are used when working with lists for an integrating
application:

• ActionStatus_LogActionComplete()
• ActionStatus_LogError()
• AddCommand()
• AddGroup()
• AddReport()
• BuildDictSpecificID()
• Columns_AddToken()
• Columns_AutoGenTokensForEnumField()
• ConfirmAction()
• CreateDefaultColumn()
• CreateDefaultCustomViewRecord()
• CreateDefaultFactBox()
• CreateDefaultViewRecord() -- Options
• CreateDefaultViewRecord() -- View
• DeleteForListView() -- Options
• DeleteForListView() -- Columns
• DeleteForListView() -- Business Analyzer Reports
• DisassembleDictSpecificID
• Exists()
• ExistsAsAction()
• ExistsAsGroup()
• FactBoxParameter_Add
• FindCommandInCmdList()
• GetListID()
• GetMarkedRecordCount()
• GetMarkedRecordsTableIndex()
• GetMarkedRecordsTableRef()
• GetViewID()
• InfoValue_ClearState()
• InfoValue_IsStateSet()
• InfoValue_SetState()
• List_FormatBoolean()
• List_FormatCurrency()
• List_FormatDate()
• List_FormatInteger()
• List_FormatPhone()
• List_FormatQuantity()
• List_FormatString()
• List_FormatTime()
• List_GetIDsForCoreCommand
• List_MultiSelectActionCompleteEvent
• List_Open
• List_RegisterAction()
• List_RegisterGroup()
• List_SetFactBoxParameter
• RegisterListNavigationCommand()
• XMLDoc_AddColumn
• XMLDoc_AddHeaderField
• XMLDoc_AddLineItem
• XMLDoc_AddLineItemValue
• XMLDoc_Create

INTEGRATION GUIDE 523


L I S T S C R I P T S

• XMLDoc_Save

524 IN T E G R AT I O N G U ID E
L I S T S C R I P T S A C T I O N S T A T U S _ L O G A C T I O N C O M P L E T E ()

ActionStatus_LogActionComplete()
Description The ActionStatus_LogActionComplete() function of the form syListObj is used to
indicate that all status information has been logged for a list action.

Syntax ActionStatus_LogActionComplete(action_status_ID, success_count, failure_count)

Parameters • action_status_ID – This is the ActionStatusID component from the list_object


composite that manages state information for the list.

• success_count – A long integer specifying the total number of list items that were
processed successfully.

• failure_count – A long integer specifying the total number of list items that had an
error logged for them as they were processed.

Return value A long integer containing the number of errors that were logged.

Comments The action processing code must keep track of the number of list items that were
processed successfully and that were processed but had an error logged.

Examples Refer to the example for ActionStatus_LogError().

INTEGRATION GUIDE 525


L I S T S C R I P T S A C T I O N S T A T U S _ L O G E R R O R ( )

ActionStatus_LogError()
Description The ActionStatus_LogError() function of the form syListObj is used to log a specific
error for a list action.

Syntax ActionStatus_LogError(action_status_ID, sequence_number, error_text, error_value,


reference_field, user_defined_data)

Parameters • action_status_ID – This is the ActionStatusID component from the list_object


composite that manages state information for the list.

• sequence_number – This is the 'Error Sequence Number' component from the


list_object composite that manages state information for the list.

• error_text – A string that specifies the text of the error being logged.

• error_value – A long integer that specifies the numeric representation of the error
being logged. Often, this is a value from the err() function.

• reference_field – This is a reference to the field that identifies the list item for which
the error is being logged. Typically, it refers to a field in the main table used for the
list.

• user_defined_data – A composite field of type ListStatusLineUserDefData that is used


to store additional user-defined data associated with the error that occurred. This
information can later be used by the ActOnActionError procedure for the list to
perform additional actions for the list item that encountered the error.

Return value A long integer containing the sequence for the logged error.

Examples The following is the DeleteLeads procedure for the Leads card list defined in the
sample integrating application. This procedure is run when the Delete action is
performed for the list. If an error occurs during the delete process, the
ActionStatus_LogError() function is used to log the error details. Once the action
processing is complete, the ActionStatus_LogActionComplete() function is called
to complete the process. Since the Delete action can be performed on multiple list
items at once, the List_MultiSelectActionCompleteEvent procedure is called to
indicate that a multi-select action has finished.

inout ListObjState list_object;

local ListStatusLineUserDefData UserDefData;


local long ErrorsLogged;
local long Sequence;
local integer SuccessCount;
local integer FailureCount;

{Clear the status counts}


SuccessCount = 0;
FailureCount = 0;

{Use the table reference from the list object to find which Leads are selected
in the list.}
get first table(list_object:TableRef1) by number list_object:Index;

526 IN T E G R AT I O N G U ID E
L I S T S C R I P T S A C T I O N S T A T U S _ L O G E R R O R ()

while err() = OKAY do


{Attempt to delete the selected Lead}
'Lead ID' of table IG_Leads_MSTR = 'Lead ID' of
➥ table(list_object:TableRef1);
change table IG_Leads_MSTR;
if err() = OKAY then
{Item could be locked, so delete it}
remove table IG_Leads_MSTR;
if err() = OKAY then
increment SuccessCount;
else
increment FailureCount;

{Log the details of the error}


UserDefData:'User Defined Text01' = 'Lead ID' of
➥ table(list_object:TableRef1);
Sequence = ActionStatus_LogError(list_object:ActionStatusID,
list_object:'Error Sequence Number',
"Lead could not be deleted",
err(),
'Lead ID' of table(list_object:TableRef1),
UserDefData) of form syListObj;

increment list_object:'Error Sequence Number';


end if;
else
{Item could not be found or passively locked}
increment FailureCount;

{Log the details of the error}


UserDefData:'User Defined Text01' = 'Lead ID' of
➥ table(list_object:TableRef1);
Sequence = ActionStatus_LogError(list_object:ActionStatusID,
list_object:'Error Sequence Number',
"Lead could not be found or was already deleted",
err(),
'Lead ID' of table(list_object:TableRef1),
UserDefData) of form syListObj;

increment list_object:'Error Sequence Number';


end if;

{Get the next Lead to delete}


get next table(list_object:TableRef1) by number list_object:Index;

end while;

{Log the success and failure results}


ErrorsLogged = ActionStatus_LogActionComplete(list_object:ActionStatusID,
➥ SuccessCount, FailureCount) of form syListObj;

{Indicate that the mutli-select list action is complete}


call List_MultiSelectActionCompleteEvent of form syListObj, list_object;

INTEGRATION GUIDE 527


L I S T S C R I P T S A D D C O M M A N D ( )

AddCommand()
Description The AddCommand() function defined in the syListViewCmdBarObj form is used to
add a command to a group in the Action Pane for a list.

Syntax AddCommand(product_ID, list_ID, view_ID, ParentDictID, ParentFormID,


ParentCmdID, sequence, CmdDictID, CmdFormID, CmdID, priority, size, caption, visible
{, clone})

Parameters • product_ID – The ID of the dictionary that contains the list for which you are adding
a command.

• list_ID – An integer specifying the ID of the list for which you are adding a
command.

• view_ID – An integer specifying the view for which the command is being added.
Use the constant LIST_PRIMARYVIEWID to indicate the primary view for the list.

• ParentDictID – The ID of the dictionary that contains the command list (group in the
Action Pane) to which the new command will be added. Use the constant
DYNAMICS to specify that you are adding items to a command list that is defined
in the Microsoft Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list (group in the Action Pane) to which you are adding a command.

• ParentCmdID – The resource ID of the command list (group in the Action Pane) to
which you are adding a command.

• sequence – An integer variable that can be used to specify the sequence of the item in
the command list. The value 0 specifies the command will be added to the end of
the list. The actual position of the command will be returned after the command is
added.

• CmdDictID – The ID of the dictionary that contains the command you are adding.

• CmdFormID – The resource ID of the command form that contains the definition of
the command you are adding.

• CmdID – The resource ID of the command you are adding.

• priority – An integer that specifies the preferred initial location of the button for the
command. The value corresponds to one of the following constants:

528 IN T E G R AT I O N G U ID E
L I S T S C R I P T S A D D C O M M A N D ()

Constant Example
LISTACTIONPRIORITY_PRIMARY

LISTACTIONPRIORITY_SECONDARY

LISTACTIONPRIORITY_OVERFLOW

• size – An integer that specifies the initial size of the button displayed in the Action
Pane for the command. The value corresponds to one of the following constants:

Constant Example
LISTACTIONBTNSIZE_SMALL

LISTACTIONBTNSIZE_LARGE

• caption – A string specifying the caption to display for the command when it is
displayed in the Action Pane. Set this parameter to the empty string ("").

• visible – A boolean specifying whether the command will initially be visible in the
Action Pane. The value true indicates it will be visible, while the value false
indicates it will not.

• clone – An optional boolean indicating whether the command should be duplicated


for all existing lists of the specified type.

Return value An integer indicating whether the command was added to the Action Pane. The
value corresponds to one of the following constants:

Constant Description
OKAY The command was successfully added.
DUPLICATE The command was not added because it already exists.

Comments A command displayed in the Action Pane must always be part of a group.

INTEGRATION GUIDE 529


L I S T S C R I P T S A D D C O M M A N D ( )

Commands added to the Action Pane must be registered using the


List_RegisterAction() function. If you don’t register the commands, they will
appear in the Action Pane, but may not be accessible.

Examples The following example is the IG_AddCustomerActions trigger processing


procedure from the sample integrating application. This procedure adds two
commands to the Customer card list Action Pane. The ExistsAsAction() function is
used to verify that the commands haven’t already been added. Notice that after the
commands have been added, the List_RegisterAction() function registers them.
inout ListObjState list_object;

local integer seq;


local integer nStatus;
local boolean exists;

{Is this the Customers list?}


if list_object:ListID = LISTID_CUSTOMERS then

{Does the Contact History command exist for the list? If not, add it.}
exists = ExistsAsAction(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History of form Command_IG_Sample),
DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID) of form syListViewCmdBarObj;

if exists = false then

{Find the Remove Hold command}


seq = FindCommandInCmdList(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ModifyGroup of form ListObj_Customers),
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command Remove_Hold of form ListObj_Customers)) of form
➥ syListViewCmdBarObj;

{If the command was found, add the Contact History command}
if seq <> 0 then
seq = seq + 1;
nStatus = AddCommand(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ModifyGroup of form ListObj_Customers),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History of form
➥ Command_IG_Sample),
LISTACTIONPRIORITY_SECONDARY,
LISTACTIONBTNSIZE_SMALL,

530 IN T E G R AT I O N G U ID E
L I S T S C R I P T S A D D C O M M A N D ()

""{caption},
true{visible}) of form syListViewCmdBarObj;
end if;
end if;

{Does the Update Contact Date command exist for the list? If not, add it.}
exists = ExistsAsAction(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Update_Contact_Date of form Command_IG_Sample),
DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID) of form syListViewCmdBarObj;

if exists = false then

{Find the Print Statements command}


seq = FindCommandInCmdList(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ActionsGroup of form ListObj_Customers),
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command Print_Statements of form ListObj_Customers)) of
➥ form syListViewCmdBarObj;

{If the command was found, add the Update Contact Date command}
if seq <> 0 then
seq = seq + 1;
nStatus = AddCommand(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ActionsGroup of form ListObj_Customers),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Update_Contact_Date of form
➥ Command_IG_Sample),
LISTACTIONPRIORITY_SECONDARY,
LISTACTIONBTNSIZE_SMALL,
""{caption},
true{visible}) of form syListViewCmdBarObj;
end if;
end if;

{Register the Contact History action}


List_RegisterAction(list_object, command IG_Contact_History of form
➥ Command_IG_Sample, LISTCMDTYPE_SINGLESELECT,
➥ ACTION_CONTACT_HISTORY_ENCODED) of form syListObj;

{Register the Update Contact Date action}


List_RegisterAction(list_object, command IG_Update_Contact_Date of form
➥ Command_IG_Sample, LISTCMDTYPE_MULTISELECT,

INTEGRATION GUIDE 531


L I S T S C R I P T S A D D C O M M A N D ( )

➥ ACTION_UPDATE_CONTACT_DATE_ENCODED) of form syListObj;

end if;

532 IN T E G R AT I O N G U ID E
L I S T S C R I P T S A D D G R O U P ()

AddGroup()
Description The AddGroup() function defined in the syListViewCmdBarObj form is used to
add an additional group (command list) to the Action Pane for a list.

Syntax AddGroup(product_ID, list_ID, view_ID, sequence, CmdDictID, CmdFormID, CmdID,


caption, visible {, clone})

Parameters • product_ID – The ID of the dictionary that contains the list for which you are adding
a group.

• list_ID – An integer specifying the ID of the list for which you are adding a group.

• view_ID – An integer specifying the view for which the group is being added. Use
the constant LIST_PRIMARYVIEWID to indicate the primary view for the list.

• sequence – An integer variable that can be used to specify the sequence of the group
in the Action Pane. The value 0 specifies the group will be added to the end of the
Action Pane. The actual position of the group will be returned after the group is
added.

• CmdDictID – The ID of the dictionary that contains the group (command list) you
are adding.

• CmdFormID – The resource ID of the command form that contains the definition of
the group (command list) you are adding.

• CmdID – The resource ID of the group (command list) you are adding.

• caption – A string specifying the caption to display for the group when it is
displayed in the Action Pane. Set this parameter to the empty string ("").

• visible – A boolean specifying whether the group will initially be visible in the
Action Pane. The value true indicates it will be visible, while the value false
indicates it will not.

• clone – An optional boolean indicating whether the group should be duplicated for
all existing lists of the specified type.

Return value An integer indicating whether the group was added to the Action Pane. The value
corresponds to one of the following constants:

Constant Description
OKAY The group was successfully added.
DUPLICATE The group was not added because it already exists.

INTEGRATION GUIDE 533


L I S T S C R I P T S A D D G R O U P ( )

Examples The following is a portion of the CreateListRibbonData procedure for the Leads
card list defined in the sample integrating application. This procedure defines the
groups and actions that appear in the Action Pane for the Leads list. This example
adds the Actions group to the Action Pane.

in ListDictID nListDictID;
in ListID nListID;

local CmdDictID nCmdDictID;


local CmdFormID nCmdFormID;
local CmdID nCmdID;
local integer nStatus;
local CmdSequence nGroupSeq;

nGroupSeq = 0;

{ Actions group }
increment nGroupSeq;
nCmdDictID = IG_PROD_ID;
nCmdFormID = resourceid(form ListObj_Leads);
nCmdID = resourceid(command CL_ActionsGroup);
nStatus = AddGroup(nListDictID, nListID, LIST_PRIMARYVIEWID, nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
true{visible}) of form syListViewCmdBarObj;

534 IN T E G R AT I O N G U ID E
L I S T S C R I P T S A D D R E P O R T ()

AddReport()

Description The AddReport() function defined in the syReportList form is used to add a report
to the Report List.

Syntax AddReport(report_data)

Parameters • report_data – A composite of type syReportData that specifies characteristics of the


report to add to the Report List.

Return value An integer indicating whether the report was added to the list. The value
corresponds to one of the following constants:

Constant Description
OKAY The report was added successfully
DUPLICATE The report already exists

Examples The following is a portion of the IG_ReportList_AddReports procedure in the


sample integrating application. It determines whether reports should be added for
the current Report List series. If they should, it fills in the syReportData composite
and uses the AddReport() function to add a simple report to the list.

in ListObjState list_object;
in 'Report Series DictID' nSeriesDictID;
in 'Report Series ID' nSeriesID;

local integer status;


local syReportData RptData;

{Add items for the IG Reports series}


if (nSeriesID = REPORTS_ALL of form syReportList) or
➥ ((nSeriesDictID = IG_PROD_ID) and (nSeriesID = 1)) then

{Simple Report}
clear field RptData;
RptData:'Report Type' = REPORTTYPE_SIMPLE;
RptData:'Product ID' = IG_PROD_ID;
RptData:'Report Series DictID' = IG_PROD_ID;
RptData:'Report Series ID' = 1;
RptData:'Report ID' = 1;
RptData:'Report Option Name' = "Leads";
RptData:'DictID' = IG_PROD_ID;
RptData:'Resid' = resourceid(report IG_Leads);

status = AddReport(RptData) of form syReportList;

end if;

INTEGRATION GUIDE 535


L I S T S C R I P T S B U I L D D I C T S P E C I F I C I D( )

BuildDictSpecificID()

Description The BuildDictSpecificID() function encodes an integer identifier for an action and
a product ID into a single action ID.

Syntax BuildDictSpecificID(product_ID, action)

Parameters • product_ID – An integer that specifies the ID of the product that defines the action.

• action – An integer value associated with the action.

Return value A long integer containing the encoded action ID.

Examples The following example creates an action ID for an action in the sample integrating
application. The action is identified by the constant value
ACTION_CONTACT_HISTORY. The product ID is identified by the constant
IG_PROD_ID.

local long ID;

ID = BuildDictSpecificID(IG_PROD_ID, ACTION_CONTACT_HISTORY);

536 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C O L U M N S _ A D D T O K E N ()

Columns_AddToken()
Description The Columns_AddToken() function in syListObj form defines the filtering tokens
to use for a specific column in a list. This function is used when the values to use for
the tokens can’t be automatically determined, such as for a radio group.

Syntax Columns_AddToken(list_object, column_ID, token_name, token_ID {, search_condition}


{, qualifier})

Parameters • list_object – The list object composite that manages the state information for the list.
This will have been passed into the procedure that creates the filtering tokens for list
columns.

• column_ID – A long integer specifying the column for which the filtering token is
being added. This will have been passed into the procedure that creates the filtering
tokens for list columns.

• token_name – A string specifying the name that will be displayed for the token. This
name will also be used in the SQL expression that is generated for the filter token.

• token_ID – A long integer specifying the unique ID of the filter token.

• search_condition – An optional string specifying the SQL search condition to use for
this specific token. If supplied, this search condition will be used in a WHERE
clause to retrict the list items displayed to those that meet the specified criteria. The
token_name and qualifier parameters will not be used for the restriction. The search
condition string must be enclosed by parentheses. The general form of the SQL
restriction clause is:

WHERE fieldname LIKE search_condition

The fieldname is automatically supplied based on the column.

• qualifier – An optional integer that specifies how the % wildcard will be included in
the SQL expression for the token. The value corresponds to one of the following
constants:

Constant Description
QUALIFY_NONE The % wildcard will not be included in the SQL expression.The SQL
expression will have the form:
WHERE fieldname LIKE 'token_name'
QUALIFY_PREFIX The % wildcard will be added to the beginning of the SQL expression,
before the token_name parameter. The SQL expression will have the
form:
WHERE fieldname LIKE '%token_name'
QUALIFY_SUFFIX The % wildcard will be added to the end of the SQL expression, after the
token_name parameter. The SQL expression will have the form:
WHERE fieldname LIKE 'token_name%'
QUALIFY_FULL The % wildcard will be added to both the beginning and the end of the
SQL expression, surrounding the token_name parameter. The SQL
expression will have the form:
WHERE fieldname LIKE '%token_name%'

Return value A long integer containing the internal ID for the token.

INTEGRATION GUIDE 537


L I S T S C R I P T S C O L U M N S _ A D D T O K E N ( )

Comments In most cases, the Columns_AutoGenTokensForEnumField() can be used to create


the filtering tokens for fields that can’t have their filtering tokens determined
automatically.

Examples The following example is the GetColumnTokens procedure for a list. It shows how
tokens would be added for a list column based on a the Typical Balance radio
group. In this example, a search_condition expression is used to select the specific
balance type. The physical name for the Typical Balance radio group is TPCLBLNC.
The value 0 indicates a debit balance. The value 1 indicates a credit balance.

in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

local long internal_ID;

if nFieldID = resourceid(field 'Typical Balance') then


{Debit}
internal_ID = Columns_AddToken(list_object,
nColumnID,
"Debit", {Token name}
1, {Unique ID for this token}
"(TPCLBLNC = '0')") of form syListObj;

{Credit}
internal_ID = Columns_AddToken(list_object,
nColumnID,
"Credit", {Token name}
2, {Unique ID for this token}
"(TPCLBLNC = '1')") of form syListObj;
end if;

The following example is the GetColumnTokens procedure for a list. It shows how
tokens would be added for a list column based on the Document Type Name field,
which is a string value stored in the table. The value can be “Work”, “Open”, or
“History”. The token_name and qualifier parameters are used to define the selection
criteria for each token. The physical name for this field is DOCTYNAM.

in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

local long internal_ID;

if nFieldID = resourceid(field 'Document Type Name') then


{Work}
internal_ID = Columns_AddToken(list_object,
nColumnID,

538 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C O L U M N S _ A D D T O K E N ()

"Work", {Token name}


1, {Unique ID for this token}
"", {No expression}
QUALIFY_SUFFIX) of form syListObj;

{Open}
internal_ID = Columns_AddToken(list_object,
nColumnID,
"Open", {Token name}
2, {Unique ID for this token}
"", {No expression}
QUALIFY_SUFFIX) of form syListObj;

{History}
internal_ID = Columns_AddToken(list_object,
nColumnID,
"History", {Token name}
3, {Unique ID for this token}
"", {No expression}
QUALIFY_SUFFIX) of form syListObj;

end if;

The three restriction expressions that will be generated for the tokens are:

(DOCTYNAM like 'Work%')

(DOCTYNAM like 'Open%')

(DOCTYNAM like 'History%')

INTEGRATION GUIDE 539


L I S T S C R I P T S C O L U M N S _ A U T O G E N T O K E N S F O R E N U M F I E L D ( )

Columns_AutoGenTokensForEnumField()
Description The Columns_AutoGenTokensForEnumField() function in syListObj form creates
the filtering tokens to use for a specific list column that is based on a drop-down list,
button drop list, list box, combo box, or visual switch datatype.

Syntax Columns_AutoGenTokensForEnumField(list_object, field, column_ID)

Parameters • list_object – The list object composite that manages the state information for the list.
This will have been passed into the procedure that creates the filtering tokens for list
columns.

• field – A window field instance of the drop-down list, button drop list, list box,
combo box, or visual switch for which tokens are being generated. When the
Columns_AutoGenTokensForEnumField() is run, the window the field is placed
on must already be open.

• column_ID – A long integer specifying the column ID of the list column for which
tokens are being generated. This will have been passed into the procedure that
creates the filtering tokens for list columns.

Return value A boolean. The value true indicates that tokens were successfully generated for the
field, while false indicates they were not.

Examples The following is the GetColumnTokens procedure for the Leads card list defined in
the sample integrating application. This procedure creates the filter tokens for the
Lead Business Category column, which is based on a drop-down list field.

in ListObjState list_object;
in ColFieldID nFieldID;
in ColArrayIndex nArrayIndex;
in long nColumnID;

local boolean status;

if nFieldID = resourceid(field 'Lead Business Category') then


{Can use the auto-generated tokens}
status = Columns_AutoGenTokensForEnumField(list_object,
➥ 'Lead Business Category' of window State, nColumnID) of form syListObj;
end if;

540 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C O N F I R M A C T I O N ()

ConfirmAction()
Description The ConfirmAction() function of the form ListObj_DropDialogs is used to display a
confirmation dialog for the user before an action is applied to the marked list items.
If the user confirms the action, the action will be performed.

Syntax ConfirmAction(list_type, action_ID, track_messages, action_name, button_prompt)

Parameters • list_type – An integer that specifies the type of list for which the action is being
performed. The value corresponds to one of the following constants:

Constant Description
LISTTYPE_CARD A card list
LISTTYPE_TRX A transaction list
LISTTYPE_REPORT A report list

• action_ID – A long integer specifying the ID of the action to be performed if the


action is confirmed by the user. If integrating with an existing Microsoft Dynamics
GP list, this must be an encoded ID.

• track_messages – A boolean specifying whether status messages will be tracked and


displayed by the message bar for the list. The value true indicates status messages
will be tracked, while false indicates they will not.

• action_name – A string specifying the name of the action being performed. This
name will be used in the status messages for the action.

• button_prompt – A string specifying the text displayed in the button for the drop-
dialog.

Return value An integer specifying the drop-dialog status. The value OKAY is returned if all
properties of the drop-dialog could be set properly. Any other value indicates an
error occurred.

Comments The following illustration shows the drop-dialog displayed by the ConfirmAction()
function.

To cancel the confirmation dialog, press the ESC key.

INTEGRATION GUIDE 541


L I S T S C R I P T S C O N F I R M A C T I O N ()

Examples The following example is the command script for the DeleteLead command used
for the Leads list in the sample integrating application. The script calls the
ConfirmAction() function to verify that the delete action should be performed for
the items marked in the list.

local integer tag;

{Get the tag for the "Delete" command}


tag = Command_GetTag(command DeleteLead of form ListObj_Leads);

{Confirm the action before processing}


ConfirmAction(LISTTYPE_CARD,
ACTION_DELETELEAD,
true, {Track status}
Command_GetStringProperty(tag, COMMAND_PROP_CLEAN_DISPLAY_NAME),
getmsg(7690) {Delete}) of form ListObj_DropDialogs;

542 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C R E A T E D E F A U L T C O L U M N ()

CreateDefaultColumn()

Description The CreateDefaultColumn() function defined in the syListViewColObj form is used


to define the columns for a list.

Syntax CreateDefaultColumn(product_ID, list_ID, sequence, field_ID, sort_order, visible,


width, array_index, format_field_dict_ID, format_field_ID, filter_token_ID, sort_sequence)

Parameters • product_ID – The ID of the dictionary that contains the list for which you are
creating a column.

• list_ID – An integer specifying the ID of the list for which you are creating a column.

• sequence – An integer specifying the default position of the column in the list. The
value 1 specifies the first column.

• field_ID – The resource ID of the field to be used for the new column.

• sort_order – An integer specifying how the content of the column will be sorted. The
value corresponds to one of the following constants:

Constant Description
COLSORTORDER_DESCENDING Sort the column in descending order
COLSORTORDER_ASCENDING Sort the column in ascending order
COLSORTORDER_NONE Do not sort the column

• visible – A boolean that indicates whether the column will be displayed by default.
The value true indicates the column will be displayed, while false indicates it will
not.

• width – An integer specifying the default width for the column in pixels.

• array_index – An integer specifying the array index of the field to be used for the
column. Specify the value 0 if the field is not an array.

• format_field_dict_ID – The ID of the dictonary that contains the format field used to
format the content of the column. Specify the value 0 if no format field is being
used.

• format_field_ID – The resource ID of the format field used to format the content of
the column. Specify the value 0 if no format field is being used.

• filter_token_ID – A long integer specifying the filter token to be applied to the


column. If you haven’t defined filter tokens for the column, or don’t want a specific
filter token applied to the column, specify the value 0.

• sort_sequence – This is an optional parameter that is not used.

Return value An integer indicating whether the column was added. The value corresponds to one
of the following constants:

Constant Description
OKAY The column was added successfully
DUPLICATE The column already exists for the list

INTEGRATION GUIDE 543


L I S T S C R I P T S C R E A T E D E F A U L T C O L U M N ( )

Examples The following example is part of the CreateListColumnsData procedure for the
Leads list in the sample integrating application. It uses the CreateDefaultColumn()
function to add the MarkedToProcess column to the list.

in ListDictID nListDictID;
in ListID nListID;

local integer nStatus;


local integer nSeq;
local integer nRet;

{Delete any existing column information for the list}


nRet = DeleteForListView(nListDictID, nListID, LIST_PRIMARYVIEWID) of form
➥ syListViewColObj;
nSeq = 1;

nStatus = CreateDefaultColumn(
nListDictID,
nListID,
nSeq,
resourceid(field 'Marked To Process'){field id},
COLSORTORDER_NONE {sort order},
true {visible},
25 {width},
0, {array index}
0, 0, { no format field }
0, {token ID}
0 {sort sequence}) of form syListViewColObj;

544 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C R E A T E D E F A U L T C U S T O M V I E W R E C O R D ()

CreateDefaultCustomViewRecord()
Description The CreateDefaultCustomViewRecord() function defined in the syListViewObj
form is used to create a custom view for a list.

Syntax CreateDefaultCustomViewRecord(list_dict_ID, list_ID, name, local_ID, view_ID)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the ID of the list for which a custom view is being
created.

• name – A string specifying the name to display for the new custom view.

• local_ID – A long integer that will be saved with the custom view. This value can be
used to identify the view if the view record needs to be retrieved at a future time.

• view_ID – A returned long integer containing the ID value that Microsoft Dynamics
GP assigned to the custom view. This value will be used in the functions that
defined the characteristics of the custom view.

Return value An integer indicating whether the default view information was created. The
constant OKAY indicates the information was created. Any other value indicates an
error occurred.

Examples Refer to the example for Exists().

INTEGRATION GUIDE 545


L I S T S C R I P T S C R E A T E D E F A U L T F A C T B O X ( )

CreateDefaultFactBox()
Description The CreateDefaultFactBox() function defined in the syListViewFactBoxReportsObj
form is used to add an SSRS report to the default set of reports for a Business
Analyzer displayed for a list.

Syntax CreateDefaultFactBox(list_dict_ID, list_ID, sequence, relative_URL, report_name,


view_ID)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the ID of the list for which a Business Analyzer is
being created.

• sequence – An integer that is used to specify the sequence of the report in the list. The
value 1 indicates the first item in the list.

• relative_URL – A string specifying the relative URL of the report on the Report
Server to be displayed. The URL has the following form:

%Company%/series/Charts and KPIs/

The %Company% placeholder will be replaced automatically by Microsoft


Dynamics GP. In place of series you will substitute the name of the series under
which the SSRS report has been stored.

• report_name – A string specifying the name of the report to add.

• view_ID – An integer specifying the list view for which Business Analyzer report
information is being added. Use the constant LIST_PRIMARYVIEWID to indicate
the primary view for the list.

Return value An integer indicating whether the default Business Analyzer information was
created. The constant OKAY indicates the information was created. Any other value
indicates an error occurred.

Comments The SSRS reports that are to be available for a Business Analyzer must be located in
the /company/series/Charts and KPIs/ location on the Report Server. Otherwise,
the reports will not be found by the Business Analyzer.

Examples The following example is the CreateListFactBoxData procedure for the Leads list in
the sample integrating application. It adds two reports that will be available by
default in the Business Analzyer for the Leads list.

in ListDictID nListDictID;
in ListID nListID;

local integer nStatus;


local 'Sequence Number' nSeq;
local integer nRet;

{ Remove all reports for the default list. }


nRet = DeleteForListView(nListDictID, nListID, LIST_PRIMARYVIEWID) of form
syListViewFactBoxReportsObj;

546 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C R E A T E D E F A U L T F A C T B O X ()

{ Add the default set of SSRS reports for the list. }


nSeq = 0;

increment nSeq;
nStatus = CreateDefaultFactBox(
nListDictID,
nListID,
nSeq,
"%Company%/Sales/Charts And KPIs/",
"Lead Potential Revenue",
LIST_PRIMARYVIEWID) of form syListViewFactBoxReportsObj;

increment nSeq;
nStatus = CreateDefaultFactBox(
nListDictID,
nListID,
nSeq,
"%Company%/Sales/Charts And KPIs/",
"Leads Per Salesperson",
LIST_PRIMARYVIEWID) of form syListViewFactBoxReportsObj;

INTEGRATION GUIDE 547


L I S T S C R I P T S C R E A T E D E F A U L T V I E W R E C O R D ( ) - - O P T I O N S

CreateDefaultViewRecord() -- Options
Description The CreateDefaultViewRecord() function defined in the syListViewOptionsObj
form is used to create the default view option information for a list.

Syntax CreateDefaultViewRecord(list_dict_ID, list_ID {, list_option}{, date_restriction)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the unique ID assigned to the list.

• list_option – An optional long integer that allows specifying which records are
displayed in the list. The default value is indicated by the constant
LISTOPTION_ALLRECORDS, which specifies that all records are displayed.

• date_restriction – An optional long integer that allows specifying the date range of
the records displayed in the list. The default value is indicated by the constant
DATERESTRICT_NONE, which indicates that no date restriction is applied.

Return value An integer indicating whether the default view option information was created. The
constant OKAY indicates the information was created. Any other value indicates an
error occurred.

Examples The following is the CreateListOptionsData procedure for the Leads list. It uses the
CreateDefaultViewRecord() function to create new default view option
information for the primary view of the Leads list. The list has the ID value 1.

local integer nStatus;

{Remove all records for this list.}


nStatus = DeleteForListView(IG_PROD_ID, 1, LIST_PRIMARYVIEWID) of form
➥ syListViewOptionsObj;

{Add the default options record for the list.}


nStatus = CreateDefaultViewRecord(IG_PROD_ID, 1, LISTOPTION_ALLRECORDS,
➥ DATERESTRICT_NONE) of form syListViewOptionsObj;

548 IN T E G R AT I O N G U ID E
L I S T S C R I P T S C R E A T E D E F A U L T V I E W R E C O R D ( ) -- V I E W

CreateDefaultViewRecord() -- View
Description The CreateDefaultViewRecord() function defined in the syListViewObj form is
used to create the default view information for a list.

Syntax CreateDefaultViewRecord(list_dict_ID, list_ID)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the unique ID assigned to the list.

Return value An integer indicating whether the default view information was created. The
constant OKAY indicates the information was created. Any other value indicates an
error occurred.

Examples Refer to the example for Exists().

INTEGRATION GUIDE 549


L I S T S C R I P T S D E L E T E F O R L I S T V I E W ( ) -- O P T I O N S

DeleteForListView() -- Options
Description The DeleteForListView() function defined in the syListViewOptionsObj form is
used to delete any existing view information that has been saved for a specific list.

Syntax DeleteForListView(list_dict_ID, list_ID, view_ID)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the unique ID assigned to the list.

• view_ID – An integer specifying the view for which view information is being
deleted. Use the constant LIST_PRIMARYVIEWID to indicate the primary view for
the list.

Return value An integer indicating whether the view information was deleted. The constant
OKAY indicates the information was deleted. Any other value indicates an error
occurred.

Examples The following is the CreateListOptionsData procedure for the Leads list. It uses the
DeleteForListView() function to remove any existing view information for the
primary view of the Leads list. The list has the ID value 1.

local integer nStatus;

{Remove all records for this list.}


nStatus = DeleteForListView(IG_PROD_ID, 1, LIST_PRIMARYVIEWID) of form
➥ syListViewOptionsObj;

{Add the default options record for the list.}


nStatus = CreateDefaultViewRecord(IG_PROD_ID, 1, LISTOPTION_ALLRECORDS,
➥ DATERESTRICT_NONE) of form syListViewOptionsObj;

550 IN T E G R AT I O N G U ID E
L I S T S C R I P T S D E L E T E F O R L I S T V I E W ( ) - - C O L U M N S

DeleteForListView() -- Columns

Description The DeleteForListView() function defined in the syListViewColObj form deletes


the column definition information for the specific list view.

Syntax DeleteForListView(list_dict_ID, list_ID, view_ID)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the unique ID assigned to the list.

• view_ID – An integer specifying the view for which column definition information
is being deleted. Use the constant LIST_PRIMARYVIEWID to indicate the primary
view for the list.

Return value An integer indicating whether the column definitions were deleted. The constant
OKAY indicates they were deleted. Any other value indicates an error occurred.

Examples The following example is a portion of the CreateListColumnsData procedure for the
Leads list in the sample integrating application. This portion of the script uses the
DeleteForListView() function to remove any existing column information for the
list before new columns are defined.

in ListDictID nListDictID;
in ListID nListID;

local integer nRet;

{Delete any existing column information for the list}


nRet = DeleteForListView(nListDictID, nListID, LIST_PRIMARYVIEWID) of form
➥ syListViewColObj;

INTEGRATION GUIDE 551


L I S T S C R I P T S D E L E T E F O R L I S T V I E W ( ) -- B U S I N E S S A N A L Y Z E R R E P O R T S

DeleteForListView() -- Business Analyzer Reports


Description The DeleteForListView() function defined in the syListViewFactBoxReportsObj
form deletes the SSRS report information used by the Business Analzyer for the
specific list view.

Syntax DeleteForListView(list_dict_ID, list_ID, view_ID)

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the unique ID assigned to the list.

• view_ID – An integer specifying the view for which SSRS report information is
being deleted. Use the constant LIST_PRIMARYVIEWID to indicate the primary
view for the list.

Return value An integer indicating whether the SSRS report information was deleted. The
constant OKAY indicates it was. Any other value indicates an error occurred.

Examples Refer to the example for CreateDefaultFactBox().

552 IN T E G R AT I O N G U ID E
L I S T S C R I P T S D I S A S S E M B L E D I C T S P E C I F I C I D

DisassembleDictSpecificID

Description The DisassembleDictSpecificID procedure takes an action ID and extracts the


product ID and the integer that represents the action.

Syntax DisassembleDictSpecificID, action_ID, product_ID, action

Parameters • action_ID – A long integer containing an action ID.

• product_ID – A returned integer containing the product ID extracted from the


supplied action ID.

• action – A returned integer containing the action extracted from the supplied action
ID.

Examples The following example is the trigger processing procedure that runs when the user
chooses an action from the Customers list. It uses the DisassembleDictSpecificID
procedure to extract the product ID and action from the action ID.
inout ListObjState list_object;
in long action_id;

local integer dict_id;


local integer action;

{Is this the default action? If it is, do not process it.}


if action_id <> DEFAULT_ACTION then
{Disassemble the action that was passed into the script}
call DisassembleDictSpecificID, action_id, dict_id, action;
{Process the action}
if dict_id = IG_PROD_ID then
{It is our action to process}
case action
in[1]
{Execute the action to open the selected customer}
call ExecuteAction of form ListObj_Customers,
➥ list_object, DEFAULT_ACTION;
{Open the Contact History window}
call IG_Trigger_Open_Contact_History;
end case;
end if;
end if;

INTEGRATION GUIDE 553


L I S T S C R I P T S E X I S T S ( )

Exists()
Description The Exists() function in the syListViewObj form verifies whether a specific view for
a list has been defined.

Syntax Exists(product_ID, list_ID, view_ID)

Parameters • product_ID – The ID of the dictionary that contains the list for which the view is
being queried.

• list_ID – An integer specifying the ID of the list for which a view is being queried.

• view_ID – An integer specifying the view being queried. Use the constant
LIST_PRIMARYVIEWID to indicate the primary view for the list.

Return value A boolean. The value true indicates the view has been defined for the list, while
false indicates it has not.

Comments Use this function when creating custom views to determine whether views for the
specific list have already been created.

Examples The following example is a trigger processing procedure from the sample
integrating application. It creates a custom view for the Leads list in the sample
integration. It uses the Exists() function to determine whether the primary view for
the Leads list has been created. If it has not, it uses the CreateDefaultViewRecord()
-- View and the CreateDefaultCustomViewRecord() functions to create the custom
view. This custom view defines new filter criteria for the list.

local integer nStatus;


local long viewID;
local syListViewFiltersState syListViewFilters;
local FilterCriteria sFilterCriteria;

{Does the primary view exist for the list?}


if Exists(IG_PROD_ID, LISTID_LEADS, LIST_PRIMARYVIEWID) of form
➥ syListViewObj = false then
{Create the primary view record}
nStatus = CreateDefaultViewRecord(IG_PROD_ID, LISTID_LEADS) of form
➥ syListViewObj;

{Create the custom view record for the 'High Revenue' view}
nStatus = CreateDefaultCustomViewRecord(IG_PROD_ID, LISTID_LEADS,
➥ "High Revenue", 1, viewID) of form syListViewObj;

if nStatus = OKAY then


{Add the information about the custom view.}
{Define the filter criteria for the custom view}
sFilterCriteria = "<criteria><or><and><eval property="+
➥ QUOTE + "PotentialRevenue" + QUOTE + " operator=" + QUOTE +
➥ "is greater than and includes" + QUOTE + " value1=" + QUOTE +
➥ "50000" + QUOTE + " value2=" + QUOTE + QUOTE +
➥ " /></and></or></criteria>";

nStatus = Create(syListViewFilters, table syListViewFilters,


➥ IG_PROD_ID, LISTID_LEADS, viewID, MODE_CHG) of form
➥ syListViewFiltersObj;

554 IN T E G R AT I O N G U ID E
L I S T S C R I P T S E X I S T S ()

if nStatus = OKAY then


call SetFilterCriteria of form syListViewFiltersObj,
syListViewFilters,
sFilterCriteria;

nStatus = Commit(syListViewFilters) of form syListViewFiltersObj;


call Destroy of form syListViewFiltersObj, syListViewFilters;
end if;
end if;
end if;

INTEGRATION GUIDE 555


L I S T S C R I P T S E X I S T S A S A C T I O N ( )

ExistsAsAction()
Description The ExistsAsAction() function in the syListViewCmdBarObj form verifies whether
a specific command exists as an action for the Action Pane of a list.

Syntax ExistsAsAction(ParentDictID, ParentFormID, ParentCmdID, product_ID, list_ID,


view_ID)

Parameters • ParentDictID – The ID of the dictionary that contains the command that is being
queried. Use the constant DYNAMICS to specify that you querying a command that
is defined in the Microsoft Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command that is being queried.

• ParentCmdID – The resource ID of the command that is being queried.

• product_ID – The ID of the dictionary that contains the list for which a command is
being queried.

• list_ID – An integer specifying the ID of the list for which a command is being
queried.

• view_ID – An integer specifying the view for which the command is being queried.
Use the constant LIST_PRIMARYVIEWID to indicate the primary view for the list.

Return value A boolean. The value true indicates the command exists as an action for the list,
while false indicates it does not.

Examples Refer to the example for AddCommand().

556 IN T E G R AT I O N G U ID E
L I S T S C R I P T S E X I S T S A S G R O U P ()

ExistsAsGroup()
Description The ExistsAsGroup() function in the syListViewCmdBarObj form verifies whether
a specific command list exists as a group for the Action Pane of a list.

Syntax ExistsAsGroup(product_ID, list_ID, view_ID, ParentDictID, ParentFormID,


ParentCmdID)

Parameters • product_ID – The ID of the dictionary that contains the list for which a command list
is being queried.

• list_ID – An integer specifying the ID of the list for which a command list is being
queried.

• view_ID – An integer specifying the view for which the command list is being
queried. Use the constant LIST_PRIMARYVIEWID to indicate the primary view for
the list.

• ParentDictID – The ID of the dictionary that contains the command list that is being
queried. Use the constant DYNAMICS to specify that you querying a command list
that is defined in the Microsoft Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that is being queried.

• ParentCmdID – The resource ID of the command list that is being queried.

Return value A boolean. The value true indicates the command list exists as a group for the list,
while false indicates it does not.

Examples The following example examines whether the Actions group exists for the Action
Pane defined for the Leads card list defined in the sample integrating application.

local boolean exists;

exists = ExistsAsGroup(IG_PROD_ID,
1, {Leads card list}
LIST_PRIMARYVIEWID,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_ActionsGroup));

INTEGRATION GUIDE 557


L I S T S C R I P T S F A C T B O X P A R A M E T E R _ A D D

FactBoxParameter_Add
Description The FactBoxParameter_Add procedure in the syListObj form adds a value to the list
of values to be used for a parameter of a SQL Server Reporting Services report that
is displayed in a Business Analyzer for a list.

Syntax FactBoxParameter_Add of form syListObj, list_object, parameter, value


{, multiple_marked} {, param_overflow}

Parameters • list_object – The list object composite that manages the state information for the list.
This will have been passed into the procedure that is creating the parameter for use
by the report.

• parameter – A text field that contains the set of values for the parameter. A parameter
can contain one or more values.

• value – A string specifying the value to add to the list of values for the parameter.

• multiple_marked – An optional boolean indicating whether the parameter will


contain multiple values. This will have been passed into the procedure that is
creating the parameter for use by the report.

• param_overflow – An optional boolean that is returned from the procedure. The


value true indicates that the overall lengthof the parameter has exceeded the
maximum. When this occurs, no additional values should be added to the
parameter.

Examples The following example is the LoadFactBoxParameters procedure for the Leads list
in the sample integrating application. It uses the FactBoxParameter_Add procedure
to build the set of Lead ID values to pass as a parameter to the reports displayed in
the Business Analyzer for the list. If only one row is selected, the parameter will
contain just one value. If multiple rows are marked in the list, the Lead ID of each
marked row will be added to the parameter. The List_SetFactBoxParameter
procedure makes the parameter value available to the report.

inout ListObjState list_object;


inout reference tableRef;
in boolean fMultipleMarked;

local text LeadParam;


local integer nStatus;
local boolean fParamTooLong;

if fMultipleMarked then

{ Look through the list of marked leads, and add each one. }
get first table(tableRef);
nStatus = err();
while nStatus <> EOF do
call FactBoxParameter_Add of form syListObj, list_object, LeadParam,
➥ 'Lead ID' of table(tableRef), fMultipleMarked, fParamTooLong;
if fParamTooLong then
exit while;
end if;

get next table(tableRef);

558 IN T E G R AT I O N G U ID E
L I S T S C R I P T S F A C T B O X P A R A M E T E R _ A D D

nStatus = err();
end while;
else
{ Add only the selected lead. }
call FactBoxParameter_Add of form syListObj, list_object, LeadParam,
➥ 'Lead ID' of table(tableRef);
end if;

{ Set the parameter that will be available for each report. }


call List_SetFactBoxParameter of form syListObj, list_object,
➥ physicalname('Lead ID' of table IG_Leads_List_TEMP), LeadParam;

INTEGRATION GUIDE 559


L I S T S C R I P T S F I N D C O M M A N D I N C M D L I S T ()

FindCommandInCmdList()

Description The FindCommandInCmdList() function defined in the syListViewCmdBarObj


form in Microsoft Dynamics GP is used to find the location of a command or
command list that is used for the Action Pane in a list.

Syntax FindCommandInCmdList(product_ID, list_ID, view_ID, ParentDictID,


ParentFormID, ParentCmdID, CmdDictID, CmdFormID, CmdID)

Parameters • product_ID – The ID of the dictionary that contains the list for which a command list
is being queried.

• list_ID – An integer specifying the ID of the list for which a command in the Action
Pane is being queried.

• view_ID – An integer specifying the view for which the command list is being
queried. Use the constant LIST_PRIMARYVIEWID to indicate the primary view for
the list.

• ParentDictID – The ID of the dictionary that contains the command list that is being
examined. Use the constant DYNAMICS to specify the Microsoft Dynamics GP
main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that is being examined.

• ParentCmdID – The resource ID of the command list that is being examined.

• CmdDictID – The ID of the dictionary that contains the command whose location is
being examined.

• CmdFormID – The resource ID of the command form that contains the definition of
the command whose location is being examined.

• CmdID – The resource ID of the command whose location is being examined.

Return value An integer that specifies the location (sequence number) of the specified command.
The value 0 indicates the item was not found in the command list.

Examples The following example uses the FindCommandInCmdList() function to retrieve the
location of the Remove Hold command that appears in the Action Pane for the
Customers list in Microsoft Dynamics GP.
local integer Seq;

{Find the Remove Hold command}


seq = FindCommandInCmdList(DYNAMICS,
LISTID_CUSTOMERS,
LIST_PRIMARYVIEWID,
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command CL_ModifyGroup of form ListObj_Customers),
DYNAMICS,
resourceid(form ListObj_Customers),
resourceid(command Remove_Hold of form ListObj_Customers)) of form
➥ syListViewCmdBarObj;

560 IN T E G R AT I O N G U ID E
L I S T S C R I P T S G E T L I S T ID ()

GetListID()
Description The GetListID() function in the syListObj form retrieves the ID of the list currently
being displayed.

Syntax GetListID(list_object)

Parameters • list_object – The list object composite that manages the state information for the list.

Return value A long integer containing the list ID.

Examples The following example retrieves the list ID for the current list.

inout ListObjState list_object;

local long list_ID;

list_ID = GetListID(list_object) of form syListObj;

INTEGRATION GUIDE 561


L I S T S C R I P T S G E T M A R K E D R E C O R D C O U N T ()

GetMarkedRecordCount()
Description The GetMarkedRecordCount() function in the syListObj form retrieves the number
of rows marked for the list.

Syntax GetMarkedRecordCount(list_object)

Parameters • list_object – The list object composite that manages the state information for the list.

Return value An integer containing the number of rows marked.

Examples The following example retrieves the number rows marked for the current list.

inout ListObjState list_object;

local integer RowCount;

RowCount = GetMarkedRecordCount(list_object) of form syListObj;

562 IN T E G R AT I O N G U ID E
L I S T S C R I P T S G E T M A R K E D R E C O R D S T A B L E I N D E X ()

GetMarkedRecordsTableIndex()
Description The GetMarkedRecordsTableIndex() function in the syListObj form retrieves the
number of the index used for the temporary table that contains the rows marked for
the list.

Syntax GetMarkedRecordsTableIndex(list_object)

Parameters • list_object – The list object composite that manages the state information for the list.

Return value An integer containing the index number.

Examples The following example retrieves the reference to the temporary table that contains
the marked rows for the current list. It also retrieves the number of the index used
for the temporary table that contains the marked rows.

inout ListObjState list_object;

local reference ListTableReference;


local integer ListTableIndex;

ListTableReference = GetMarkedRecordsTableRef(list_object) of form syListObj;


ListTableIndex = GetMarkedRecordsTableIndex(list_object) of form syListObj;

INTEGRATION GUIDE 563


L I S T S C R I P T S G E T M A R K E D R E C O R D S T A B L E R E F ( )

GetMarkedRecordsTableRef()
Description The GetMarkedRecordsTableRef() function in the syListObj form retrieves the
reference to the temporary table that contains the rows marked for the list.

Syntax GetMarkedRecordsTableRef(list_object)

Parameters • list_object – The list object composite that manages the state information for the list.

Return value A reference to the temporary table that contains the rows marked for the list.

Examples The following example retrieves the reference to the temporary table that contains
the marked rows for the current list. It also retrieves the number of the index used
for the temporary table that contains the marked rows.

inout ListObjState list_object;

local reference ListTableReference;


local integer ListTableIndex;

ListTableReference = GetMarkedRecordsTableRef(list_object) of form syListObj;


ListTableIndex = GetMarkedRecordsTableIndex(list_object) of form syListObj;

564 IN T E G R AT I O N G U ID E
L I S T S C R I P T S G E T V I E W ID ()

GetViewID()
Description The GetViewID() function in the syListObj form retrieves the ID of the view for the
list currently being displayed.

Syntax GetViewID(list_object)

Parameters • list_object – The list object composite that manages the state information for the list.

Return value A long integer containing the view ID.

Examples The following example retrieves the view ID for the current list.

inout ListObjState list_object;

local long view_ID;

view_ID = GetViewID(list_object) of form syListObj;

INTEGRATION GUIDE 565


L I S T S C R I P T S I N F O V A L U E _ C L E A R S T A T E ( )

InfoValue_ClearState()
Description The InfoValue_ClearState() function defined in the syListObj form is used to clear
a specific state value of the InfoValue column for a list. The InfoValue is a bitmask
field, with several states that are set and retrieved independently.

Syntax InfoValue_ClearState(InfoValue, state)

Parameters • InfoValue – The InfoValue column for the list.

• state – The state which will be cleared for the Information Icon displayed for the list
item. The value is an integer that corresponds to one of the following constants:

Constant Icon Priority Description


INFOVALUE_ERROR Highest The item has an error.

INFOVALUE_WORKFLOWPRESENT The item is part of a workflow.

INFOVALUE_ONHOLD The item is on hold.

INFOVALUE_INACTIVE The item is inactive.

INFOVALUE_VOID The item has been voided.

INFOVALUE_NOTEATTACHED A record-level note is attached to the


item.

INFOVALUE_CUSTOM1 A general-purpose icon indicating an


action should be performed for the
item.
INFOVALUE_CUSTOM2 Lowest A general-purpose icon indicating
additional information is available
for the item.

Return value A boolean. The value true indicates the specific state value had already been
cleared. The value false indicates the specific state value was previously set, but is
now cleared.

Examples The following example clears the Error state for a variable used to set the
Information Icon for a list.

local boolean already_cleared;

already_cleared = InfoValue_ClearState(InfoValue, INFOVALUE_ERROR);

566 IN T E G R AT I O N G U ID E
L I S T S C R I P T S I N F O V A L U E _ I S S T A T E S E T ()

InfoValue_IsStateSet()
Description The InfoValue_IsStateSet() function defined in the syListObj form is used to verify
whether a specific state value of the InfoValue column for a list is set. The InfoValue
is a bitmask field, with several states that are set and retrieved independently.

Syntax InfoValue_IsStateSet(InfoValue, state)

Parameters • InfoValue – The InfoValue column for the list.

• state – The state which will be examined for the Information Icon displayed for the
list item. The value is an integer that corresponds to one of the following constants:

Constant Icon Priority Description


INFOVALUE_ERROR Highest The item has an error.

INFOVALUE_WORKFLOWPRESENT The item is part of a workflow.

INFOVALUE_ONHOLD The item is on hold.

INFOVALUE_INACTIVE The item is inactive.

INFOVALUE_VOID The item has been voided.

INFOVALUE_NOTEATTACHED A record-level note is attached to the


item.

INFOVALUE_CUSTOM1 A general-purpose icon indicating an


action should be performed for the
item.
INFOVALUE_CUSTOM2 Lowest A general-purpose icon indicating
additional information is available
for the item.

Return value A boolean. The value true indicates the state is set, while the value false indicates it
is not.

Examples The following example examines the Note Attached state for the Information Icon
for a list.

local boolean note_attached;

note_attached = InfoValue_IsStateSet(InfoValue, INFOVALUE_NOTEATTACHED);

INTEGRATION GUIDE 567


L I S T S C R I P T S I N F O V A L U E _ S E T S T A T E ( )

InfoValue_SetState()
Description The InfoValue_SetState() function defined in the syListObj form is used to set the
value of the InfoValue column for a list. The InfoValue is a bitmask field, with
several states that are set and retrieved independently.

Syntax InfoValue_SetState(InfoValue, state)

Parameters • InfoValue – The InfoValue column for the list.

• state – The state which will be set and displayed by the Information Icon for the list
item. The value is an integer that corresponds to one of the following constants:

Constant Icon Priority Description


INFOVALUE_ERROR Highest The item has an error.

INFOVALUE_WORKFLOWPRESENT The item is part of a workflow.

INFOVALUE_ONHOLD The item is on hold.

INFOVALUE_INACTIVE The item is inactive.

INFOVALUE_VOID The item has been voided.

INFOVALUE_NOTEATTACHED A record-level note is attached to the


item.

INFOVALUE_CUSTOM1 A general-purpose icon indicating an


action should be performed for the
item.
INFOVALUE_CUSTOM2 Lowest A general-purpose icon indicating
additional information is available
for the item.

Return value A boolean indicating the state had previously been set. The value true indicates the
state had already been set, while the value false indicates it had not.

Comments While the InfoValue column can keep track of all the individual states, the
Information Icon in the list will display the icon for only the highest-priority state
that has been set.

Examples The following example sets two integer variables to states that are used to set the
InfoValue column for the Leads card list in the sample integrating application.

local integer InfoValueInactive;


local integer InfoValueNote;

{Define the values to which the InfoValue column must be set for rows that
meet the criteria}
InfoValue_SetState(InfoValueInactive, INFOVALUE_CUSTOM1) of form syListObj;
InfoValue_SetState(InfoValueNote, INFOVALUE_NOTEATTACHED) of form syListObj;

568 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ F O R M A T B O O L E A N ()

List_FormatBoolean()
Description The List_FormatBoolean() function defined in the syListObj form is used to format
boolean values for list data displayed in the Information Pane, included in a report,
or exported to Microsoft Excel.

Syntax List_FormatString(boolean_value, use)

Parameters • boolean_value – The boolean value being formatted.

• use – An integer indicating where the formatted boolean is to be used. Based on the
intended use, the boolean will be formatted appropriately. The value corresponds to
one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A string containing the formatted boolean value. The value true will be returned as
“Yes”. The value false will be returned as “No”.

Examples The following example formats a boolean value for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatBoolean(Active, LIST_FORMATFOR_PREVPANE) of form


➥ syListObj;

INTEGRATION GUIDE 569


L I S T S C R I P T S L I S T _ F O R M A T C U R R E N C Y ( )

List_FormatCurrency()
Description The List_FormatCurrency() function defined in the syListObj form is used to format
currency values for list data displayed in the Information Pane, included in a report,
or exported to Microsoft Excel.

Syntax List_FormatCurrency(currency_value, currency_index, use {, currency_symbol})

Parameters • currency_value – The currency value being formatted.

• currency_index – A integer specifying the currency index to use for formatting. If the
currency index isn’t known, the number of decimal places can also be specified by
this parameter.

• use – An integer indicating where the formatted currency is to be used. Based on the
intended use, the currency will be formatted appropriately. The value corresponds
to one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

• currency_symbol – An optional boolean parameter. The value true indicates the


currency symbol should be shown, while the value false indicates it should not.

Return value A string containing the formatted currency value.

Examples The following example formats a currency value for use in the Information Pane.
The value will have two decimal places and display the currency symbol.

local string formatted_value;

formatted_value = List_FormatCurrency('Potential Revenue', 2,


LIST_FORMATFOR_PREVPANE, true) of form syListObj;

570 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ F O R M A T D A T E ()

List_FormatDate()
Description The List_FormatDate() function defined in the syListObj form is used to format
date values for list data displayed in the Information Pane, included in a report, or
exported to Microsoft Excel.

Syntax List_FormatDate(date_value, use)

Parameters • date_value – The date value being formatted.

• use – An integer indicating where the formatted date is to be used. Based on the
intended use, the date will be formatted appropriately. The value corresponds to
one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A string containing the formatted date value.

Examples The following example formats a date value for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatDate('Qualified Date', LIST_FORMATFOR_PREVPANE)


➥ of form syListObj;

INTEGRATION GUIDE 571


L I S T S C R I P T S L I S T _ F O R M A T I N T E G E R ()

List_FormatInteger()
Description The List_FormatInteger() function defined in the syListObj form is used to format
integer or long integer values for list data displayed in the Information Pane,
included in a report, or exported to Microsoft Excel.

Syntax List_FormatInteger(integer_value, use)

Parameters • integer_value – The integer or long integer value being formatted.

• use – An integer indicating where the formatted integer or long integer is to be used.
Based on the intended use, the value will be formatted appropriately. The value
corresponds to one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A string containing the formatted integer or long integer value.

Examples The following example formats an integer value for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatInteger(Total, LIST_FORMATFOR_PREVPANE) of form


➥ syListObj;

572 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ F O R M A T P H O N E ()

List_FormatPhone()
Description The List_FormatPhone() function defined in the syListObj form is used to format
phone number values for list data displayed in the Information Pane, included in a
report, or exported to Microsoft Excel.

Syntax List_FormatPhone(phone_value, use)

Parameters • phone_value – The phone number value being formatted.

• use – An integer indicating where the formatted phone number is to be used. Based
on the intended use, the phone number will be formatted appropriately. The value
corresponds to one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A string containing the formatted phone number value.

Examples The following example formats a phone number for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatPhone(Fax, LIST_FORMATFOR_PREVPANE) of form


➥ syListObj;

INTEGRATION GUIDE 573


L I S T S C R I P T S L I S T _ F O R M A T Q U A N T I T Y ( )

List_FormatQuantity()
Description The List_FormatQuantity() function defined in the syListObj form is used to format
quantity values for list data displayed in the Information Pane, included in a report,
or exported to Microsoft Excel.

Syntax List_FormatQuantity(quantity_value, decimal_places, use)

Parameters • quantity_value – The quantity value being formatted.

• decimal_places – The 'Decimal Places QTYS' field (a drop-down list) specifying the
number of decimal places to use for the quantity.

• use – An integer indicating where the formatted quanitity value is to be used. Based
on the intended use, the quantity value will be formatted appropriately. The value
corresponds to one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A string containing the formatted quantity value.

Examples The following example formats a quantity value for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatBoolean('QTY Available', 'Decimal Places QTYS',


➥ LIST_FORMATFOR_PREVPANE) of form syListObj;

574 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ F O R M A T S T R I N G ()

List_FormatString()
Description The List_FormatString() function defined in the syListObj form is used to format
string values for list data displayed in the Information Pane, included in a report, or
exported to Microsoft Excel.

Syntax List_FormatString(string_value, use)

Parameters • string_value – The string value being formatted.

• use – An integer indicating where the formatted string is to be used. Based on the
intended use, the string will be formatted appropriately. The value corresponds to
one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A formatted string value.

Examples The following example formats a string value for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatString(City, LIST_FORMATFOR_PREVPANE) of form


➥ syListObj;

INTEGRATION GUIDE 575


L I S T S C R I P T S L I S T _ F O R M A T T I M E ( )

List_FormatTime()
Description The List_FormatTime() function defined in the syListObj form is used to format
time values for list data displayed in the Information Pane, included in a report, or
exported to Microsoft Excel.

Syntax List_FormatTime(time_value, use)

Parameters • time_value – The time value being formatted.

• use – An integer indicating where the formatted time value is to be used. Based on
the intended use, the time will be formatted appropriately. The value corresponds
to one of the following constants:

Constant Description
LIST_FORMATFOR_EXCEL The value is being formatted for exporting to Excel.
LIST_FORMATFOR_PREVPANE The value is being formatted for display in the Information
Pane.
LIST_FORMATFOR_REPORT The value is being formatted for display in the report
generated from the list content.

Return value A string containing the formatted time value.

Examples The following example formats a time value for use in the Information Pane.

local string formatted_value;

formatted_value = List_FormatTime('Start Time', LIST_FORMATFOR_PREVPANE)


➥ of form syListObj;

576 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ G E T ID S F O R C O R E C O M M A N D

List_GetIDsForCoreCommand
Description The List_GetIDsForCoreCommand procedure defined in the
syListViewCmdBarObj form is used to retrieve the ID values for predefined
commands and groups that can be displayed in the Action Pane for a list.

Syntax List_GetIDsForCoreCommand of form syListObj, list_type, action_ID, dict_ID,


form_ID, command_ID

Parameters • list_type – An integer that specifies the type of list from which a core command is
being retrieved. The value corresponds to one of the following constants:

Constant Description
LISTTYPE_CARD A card list.
LISTTYPE_TRX A transaction list.

• action_ID – A long integer specifying the item for which the ID information is being
retrieved. The value corresponds to one of the following constants:

Constant Description
LISTRIBBONGROUP_USERDEF1 The first user-defined group for the list.
LISTRIBBONGROUP_USERDEF2 The second user-defined group for the list.
LISTACTION_EXPORTTOEXCEL The action to export to Microsoft Excel.
LISTACTION_PRINTLIST The action to print the list content.
LISTRIBBONGROUP_RESTRICT The Restrictions group for the list.
LISTACTION_LISTRESTRICT The restriction drop-list for the list.
LISTACTION_DATERESTRICT The date restriction drop-list for the list.

• dict_ID – A returned integer containing the ID of the dictionary that defines the
command.

• form_ID – A returned integer containing the resource ID of the form that defines the
command.

• command_ID – A returned integer containing the ID of the command.

Examples The following is a portion of the CreateListRibbonData procedure for the Leads
card list defined in the sample integrating application. This portion of the procedure
retrieves and adds the two user-defined groups that can be added to the action pane
for a list.

in ListDictID nListDictID;
in ListID nListID;

local CmdDictID nCmdDictID;


local CmdFormID nCmdFormID;
local CmdID nCmdID;
local CmdSequence nGroupSeq;

{ User Defined Group 1 }


increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTRIBBONGROUP_USERDEF1, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID,

INTEGRATION GUIDE 577


L I S T S C R I P T S L I S T _ G E T ID S F O R C O R E C O M M A N D

nListID,
LIST_PRIMARYVIEWID,
nGroupSeq,
nCmdDictID,
nCmdFormID,
nCmdID,
""{caption},
false{visible}) of form syListViewCmdBarObj;

{ User Defined Group 2 }


increment nGroupSeq;
call List_GetIDsForCoreCommand of form syListObj, LISTTYPE_CARD,
➥ LISTRIBBONGROUP_USERDEF2, nCmdDictID, nCmdFormID, nCmdID;
nStatus = AddGroup(nListDictID,
nListID,
LIST_PRIMARYVIEWID,
nGroupSeq,
nCmdDictID, nCmdFormID, nCmdID,
""{caption},
false{visible}) of form syListViewCmdBarObj;

578 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ M U L T I S E L E C T A C T I O N C O M P L E T E E V E N T

List_MultiSelectActionCompleteEvent
Description The List_MultiSelectActionCompleteEvent procedure of the syListObj form is
used to indicate that a multiselect action has finished processing.

Syntax List_MultiSelectActionCompleteEvent of form syListObj, list_object

Parameters • list_object – The list object composite that manages the state information for the list.

Examples Refer to the example for ActionStatus_LogError().

INTEGRATION GUIDE 579


L I S T S C R I P T S L I S T _ O P E N

List_Open
Description The List_Open procedure defined in the syListObj form is used to open a list from
sanScript code. The list content can be displayed in the main Microsoft Dynamics
GP window or in a separate window.

This procedure must always be called with the background keyword to prevent conflicts
with other list code that may be running.

Syntax List_Open of form syListObj, list_dict_ID, list_ID, view_ID {, restriction_integer}


{, restriction_string1} {, restriction_string2} {, separate_window}

Parameters • list_dict_ID – An integer specifying the ID of the product that defines the list.

• list_ID – An integer specifying the unique ID assigned to the list.

• view_ID – An integer specifying the view to use for the list. Typically, the constant
LIST_PRIMARYVIEWID is used to specify that the primary view is used.

• restriction_integer – An optional integer parameter that can be used to specify a


restriction for the list.

• restriction_string1 – An optional string parameter that can be used to specify a


restriction for the list.

• restriction_string2 – An optional string parameter that can can be used to specify a


restriction for the list.

• separate_window – An optional boolean that specifies whether the list is displayed in


a separate window. The value true specifies that the list will appear in a separate
window, while false specifies that the list will appear in the main Microsoft
Dynamics GP window. The default is to display in the main window.

Comments Microsoft Dynamics GP can display one card list, one trasaction list, and one report
list at a time. The lists can be in either the main Microsoft Dynamics GP window or
a separate window. Before you open a list using sanScript code, you must verify
that a list of that type is not already open.

You can use the optional restriction parameters for the List_Open procedure to pass
information to the list that specifies what data will be displayed in the list. If you
supply the restriction parameters, their values will be temporarily stored as
properties for the command associated with the list. You can retrieve the property
values using the Command_GetNamedProperty() function. The following table
lists the constants defined in the syListObj form that correspond to the named
properties that will be set for the command used for the list.

Constant Description
NAMEDPROP_RESTRICTIONTYPE The optional integer restriction parameter.
NAMEDPROP_RESTRICTIONSTRING1 The first string restriction parameter.
NAMEDPROP_RESTRICTIONSTRING2 The second string restriction parameter.

Typically, these restriction parameters are retrieved and used in the Refresh
procedure for the list being opened.

580 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ O P E N

Examples The following example opens the Sales Order Transactions list in a separate
window. The code examines whether a transaction list is already open before Sales
Order Transactions list is displayed. Notice that the List_Open procedure is called
with the background keyword.

local boolean list_is_open;


local string list_name;

{Assume that a list of the specified type is not open.}


list_is_open = false;

if isopen(form syTrxList) then


if (ListObjState:IsCreated of window TrxList of form syTrxList) then

{A list is already open. Tell the user which list to close.}


call GetListPropertiesForListID of form syListObj,
GetListDictID(ListObjState of window TrxList of form syTrxList)
of form syListObj, GetListID(ListObjState of window TrxList
of form syTrxList) of form syListObj, none, list_name;

{Set the flag indicating the list is open.}


list_is_open = true;

{Display a message indicating the situation for the user.}


warning "You need to close the list: " + list_name;
end if;
end if;

if list_is_open = false then


call background List_Open of form syListObj, DYNAMICS, LISTID_SOPTRX,
➥ LIST_PRIMARYVIEWID, none, none, none, true;
end if;

INTEGRATION GUIDE 581


L I S T S C R I P T S L I S T _ R E G I S T E R A C T I O N ( )

List_RegisterAction()

Description The List_RegisterAction() function defined in the syListObj form is used to register
commands that appear in the action pane for a list. The commands must be
registered for them to be accessed by other list processing code.

Syntax List_RegisterAction(list_object, command, command_type, action)

Parameters • list_object – The list object (composite) that specifies characteristics for the list. This
value will have been passed into the procedure that is registering actions for the list.

• command – The command resource that is being registered for the list’s action pane.

• command_type – A constant that specifies the conditions under which the command
will be active on the action pane. The value corresponds to one of the following
constants:

Constant Description
LISTCMDTYPE_SINGLESELECT The action is available when only one item is selected in
the list.
LISTCMDTYPE_MULTISELECT The action is available when one or more items is selected
in the list.
LISTCMDTYPE_ALWAYSAVAILABLE The action is always available.

• action – A long integer value that specifies the action that will be performed for each
of the items selected in the list. Typically, this value is a constant that was defined
for the specific list action.

Return value A long integer containing the index of the registered command.

Comments This function is used during the list initialization procedure.

Examples The following example is a portion of the RegisterCommands procedure for the
Leads list in the sample integrating application. This example registers the
“Actions” group and the QualifyLead command. The constant named
ACTION_QUALIFYLEAD has been defined to indentify the action that is being
performed.

inout ListObjState list_object;

List_RegisterGroup(list_object, command CL_ActionsGroup) of form syListObj;


List_RegisterAction(list_object, command QualifyLead,
➥ LISTCMDTYPE_MULTISELECT, ACTION_QUALIFYLEAD) of form syListObj;

582 IN T E G R AT I O N G U ID E
L I S T S C R I P T S L I S T _ R E G I S T E R G R O U P ()

List_RegisterGroup()

Description The List_RegisterGroup() function defined in the syListObj form is used to register
command lists that appear as groups in the action pane for a list. The command lists
must be registered for them to be accessed by other list processing code.

Syntax List_RegisterGroup(list_object, command_list)

Parameters • list_object – The list object (composite) that specifies characteristics for the list. This
value will have been passed into the procedure that is registering groups for the list.

• command_list – The command list resource that is being registered as a group for the
list’s action pane.

Return value A long integer containing the index of the registered command list.

Comments This function is used during the list initialization procedure.

Examples The following example is a portion of the RegisterCommands procedure for the
Leads list in the sample integrating application. This example registers the
“Actions” group defined by the CL_ActionsGroup command list.

inout ListObjState list_object;

List_RegisterGroup(list_object, command CL_ActionsGroup) of form syListObj;


List_RegisterAction(list_object, command QualifyLead,
➥ LISTCMDTYPE_MULTISELECT, ACTION_QUALIFYLEAD) of form syListObj;

INTEGRATION GUIDE 583


L I S T S C R I P T S L I S T _ S E T F A C T B O X P A R A M E T E R

List_SetFactBoxParameter
Description The List_SetFactBoxParameter procedure in the syListObj form sets the value of a
specified parameter for the SQL Server Reporting Services reports displayed in the
Business Analyzer for a list.

Syntax List_SetFactBoxParameter of form syListObj, list_object, parameter_name, values

Parameters • list_object – The list object (composite) that specifies characteristics for the list. This
value will have been passed into the procedure that is setting the report parameter.

• parameter_name – A string containing the name of the report parameter to be set.


Typically, this will be the physical name of the table field from which the values for
the parameter are being retrieved. By following this convention, you allow new
SSRS reports to know the parameter name and use the parameter value that is based
on the selection.

• values – A text field that contains the parameter value or values.

Examples Refer to the example for FactBoxParameter_Add.

584 IN T E G R AT I O N G U ID E
L I S T S C R I P T S R E G I S T E R L I S T N A V I G A T I O N C O M M A N D ()

RegisterListNavigationCommand()
Description The RegisterListNavigationCommand() function defined in the syListObj form
registers the command that opens a list. The command must be added to one of the
command lists used for the Navigation Pane.

Syntax RegisterListNavigationCommand(command, list_dict_ID, list_ID, form_dict_ID,


form_ID, sublist, list_type, parent_command)

Parameters • command – The command that is defined to open the list.

• list_dict_ID – The ID of the dictionary that is defining the list.

• list_ID – An integer specifying the unique identifier assigned to the list.

• form_dict_ID – The ID of the dictionary that contains the form used to define the list
characteristics.

• form_ID – The resource ID of the form that defines the list characteristics.

• sublist – An integer specifying the sublist to be displayed. The sublist is used when a
single list form is used to display different sets of information. The sublist value
indicates to the list which set of information to display. In the list processing code,
the sublist specified by this parameter can be retrieved using the SubList
component of the ListObjState composite. If no sublist is being used, specify the
value 0.

• list_type – An integer specifying the type of list being registered. The value
corresponds to one of the following constants:

Constant Description
LISTTYPE_CARD A card list
LISTTYPE_TRX A transaction list

• parent_command – The command list for the Navigation Pane into which the
command being registered had been added.

Return value A boolean. The value true indicates the navigation command was registered
successfully, while the value false indicates it was not.

Examples The following example is a form pre script for a command form that defines a
command to open the Leads list. The script registers the Leads list, which was
added to the Sales command list in the Navigation Pane. The value “1” is assigned
as the ID for the list.

local boolean result;

result = RegisterListNavigationCommand(command ListObj_Leads,


IG_PROD_ID,
1,
IG_PROD_ID,
resourceid(form ListObj_Leads),
0,
LISTTYPE_CARD,
command SalesButton of form Command_NavBar) of form syListObj;

INTEGRATION GUIDE 585


L I S T S C R I P T S X M L D O C _ A D D C O L U M N

XMLDoc_AddColumn
Description The XMLDoc_AddColumn procedure of the syListObj form adds a column to the
end of the set of line items for the current Information Pane.

Syntax XMLDoc_AddColumn of form syListObj, XML_state, column_name {,right_align})

Parameters • XML_state – A field of the type ListPrevPaneXMLState that contains the state
information for the Information Pane XML document.

• column_name – A string specifying the name of the column to add.

• right_align – An optional boolean. The value true indicates the name will be right-
aligned, while the value false indicates the value will be left-aligned. The default is
left-aligned.

Examples The following trigger processing procedure adds the Company column to the end
of the set of line items for the Account Transaction list.

in integer nTrxType;
inout ListPrevPaneXMLState XMLState;

{Add the Company header item, with the item right-justified}


call XMLDoc_AddColumn of form syListObj, XMLState, "Company", true;

586 IN T E G R AT I O N G U ID E
L I S T S C R I P T S X M LD O C _ A D D H E A D E R F I E L D

XMLDoc_AddHeaderField
Description The XMLDoc_AddHeaderField procedure of the syListObj form adds a value to the
end of the specified column in the header for the current Information Pane.

Syntax XMLDoc_AddHeaderField of form syListObj, XML_state, prompt, value, column

Parameters • XML_state – A field of the type ListPrevPaneXMLState that contains the state
information for the Information Pane XML document.

• prompt – A string specifying the prompt to display for the value being added to the
end of the column.

• value – A string specifying the value to add to the end of the column.

• column – An integer specifying which column to add the value to. The value can be
1, 2, or 3.

Examples The following is a portion of the GeneratePreviewPaneXML procedure for the


Leads list defined in the sample integrating application. This example adds two
values for address information to the end of the first column in the header for the
Information Pane. Notice how the second value is added, but a prompt isn’t
supplied.

{Address}
sValue = 'Address 1' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "Address", sValue, 1;
sValue = 'Address 2' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "", sValue, 1;

INTEGRATION GUIDE 587


L I S T S C R I P T S X M L D O C _ A D D L I N E I T E M

XMLDoc_AddLineItem
Description The XMLDoc_AddLineItem procedure of the syListObj form adds a new line item
to the current Information Pane.

Syntax XMLDoc_AddLineItem of form syListObj, XML_state, row_element

Parameters • XML_state – A field of the type ListPrevPaneXMLState that contains the state
information for the Information Pane XML document.

• row_element – A returned reference value for the new line item that was added. This
value is used by the XMLDoc_AddLineItemValue procedure when values are
added to the line.

Examples The following is a portion of the GeneratePreviewPaneXML procedure for the


Contact History transaction list in the sample integrating application. This portion
of the script uses the XMLDoc_AddLineItem procedure creates a new line item for
the Information Pane. It then uses the XMLDoc_AddLineItemValue procedure to
add values to that new line item.

local ListPrevPaneXMLState XMLState;


local reference RowValuesElement;

{Add the line items}


{First Contact}
call XMLDoc_AddLineItem of form syListObj, XMLState, RowValuesElement;
sValue = "First Contact";
call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

sValue = List_FormatDate('First Contact Date' of


table(Contact_History_MSTR_Temp), LIST_FORMATFOR_PREVPANE) of form syListObj;
call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

sValue = 'Contact Salesperson ID' of table(Contact_History_MSTR_Temp);


call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,
➥ sValue, false;

588 IN T E G R AT I O N G U ID E
L I S T S C R I P T S X M LD O C _ A D D L I N E I T E M V A L U E

XMLDoc_AddLineItemValue
Description The XMLDoc_AddLineItemValue procedure of the syListObj form adds a column
value to the end of the current line item row in the Information Pane.

Syntax XMLDoc_AddLineItemValue of form syListObj, XML_state, row_element, value


{, right_align} {, URL})

Parameters • XML_state – A field of the type ListPrevPaneXMLState that contains the state
information for the Information Pane XML document.

• row_element – A reference to the current row element to which a line item value is
being added.

• value – A string specifying the value to add.

• right_align – An optional boolean. The value true indicates the value will be right-
aligned, while the value false indicates the value will be left-aligned. The default is
left-aligned.

• URL – An optional string. The value specifies the URL to associate with the item
being added.

Examples The following trigger processing procedure adds the company information to the
end of the current line item row in the Information Pane for the Account
Transactions list.

in anonymous table TrxHdr;


in anonymous table TrxLine;
in integer nTrxStatus;
in integer nTrxType;
inout ListPrevPaneXMLState XMLState;
inout reference RowValuesElement;

call XMLDoc_AddLineItemValue of form syListObj, XMLState, RowValuesElement,


➥ 'Intercompany ID' of table TrxLine, true;

INTEGRATION GUIDE 589


L I S T S C R I P T S X M L D O C _ C R E A T E

XMLDoc_Create
Description The XMLDoc_Create procedure of the syListObj form starts the process of creating
the content for the Information Pane displayed by a list.

Syntax XMLDoc_Create of form syListObj, XML_state, XML_file_path, title

Parameters • XML_state – A returned field of the type ListPrevPaneXMLState that contains the
state information for the Information Pane XML document. This value will be used
by the other procedures used to define Information Pane content.

• XML_file_path – A string that specifies the file path where the XML document used
for the Information Pane will be created. Use the value passed into the
GeneratePreviewPaneXML procedure defined for the list.

• title – A string specifying the title to display for the Information Pane.

Examples The following is the complete GeneratePreviewPaneXML procedure defined for the
Leads card list in the sample integrating application. It uses the XMLDoc_Create
procedure to start the process of creating the XML content to be displayed in the
Information Pane. After the content has been specified, the XMLDoc_Save
procedure is called to complete the process.

inout ListObjState list_object;


inout string XMLFilePath;
inout string sTitle;

local ListPrevPaneXMLState XMLState;


local string sName;
local string sValue;
local integer iAlignment;
local reference Leads_MSTR_Temp;

{Get the reference for the temporary table used by the list}
Leads_MSTR_Temp = list_object:'Table Reference';

sTitle = str('Lead ID' of table(Leads_MSTR_Temp)) + CH_SPACE + CH_COLON +


CH_SPACE + 'Lead Name' of table(Leads_MSTR_Temp);

{ Build up basic XML file }


call XMLDoc_Create of form syListObj, XMLState, XMLFilePath, sTitle;

{Add the fields that will be displayed}

{--Column 1--}

{Address}
sValue = 'Address 1' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "Address", sValue, 1;
sValue = 'Address 2' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "", sValue, 1;

{City, State, Zip}


sValue = 'City' of table(Leads_MSTR_Temp) + ", " + 'State' of
➥ table(Leads_MSTR_Temp) + " " + 'Zip' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, "", sValue, 1;

590 IN T E G R AT I O N G U ID E
L I S T S C R I P T S X M L D O C _ C R E A T E

{Phone 1}
call GetColumnName of form ListObj_Leads, resourceid(field 'Phone 1'), 0,
➥ sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Phone 1'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 1;

{Phone 2}
call GetColumnName of form ListObj_Leads, resourceid(field 'Phone 2'), 0,
➥ sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Phone 2'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 1;

{Fax}
call GetColumnName of form ListObj_Leads, resourceid(field 'Fax'), 0, sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Fax'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 1;

{--Column 2--}

{Lead Category}
call GetColumnName of form ListObj_Leads, resourceid(field 'Lead Business
➥ Category'), 0, sName;
sValue = itemname('Lead Business Category' of window State, 'Lead Business
➥ Category' of table(Leads_MSTR_Temp));
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 2;

{Contact}
call GetColumnName of form ListObj_Leads, resourceid(field 'Contact'), 0,
➥ sName;
sValue = 'Contact' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 2;

{Potential Revenue}
call GetColumnName of form ListObj_Leads, resourceid(field 'Potential
➥ Revenue'), 0, sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Potential Revenue'), 0, 1, sValue, iAlignment;
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 2;

{--Column 3--}

{Qualified Lead}
call GetColumnName of form ListObj_Leads, resourceid(field 'Qualified Lead'),
➥ 0, sName;
sValue = itemname('Qualified Lead' of window State, 'Qualified Lead' of
➥ table(Leads_MSTR_Temp));
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 3;

{Qualification Date}
call GetColumnName of form ListObj_Leads, resourceid(field 'Qualification
➥ Date'), 0, sName;
call FormatField of form ListObj_Leads, Leads_MSTR_Temp, resourceid(field
➥ 'Qualification Date'), 0, 1, sValue, iAlignment;

INTEGRATION GUIDE 591


L I S T S C R I P T S X M L D O C _ C R E A T E

call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 3;

{Source}
call GetColumnName of form ListObj_Leads, resourceid(field 'Lead Source'), 0,
➥ sName;
sValue = 'Lead Source' of table(Leads_MSTR_Temp);
call XMLDoc_AddHeaderField of form syListObj, XMLState, sName, sValue, 3;

{Save the XML document.}


call XMLDoc_Save of form syListObj, XMLState;

592 IN T E G R AT I O N G U ID E
L I S T S C R I P T S X M LD O C _ S A V E

XMLDoc_Save
Description The XMLDoc_Save procedure of the syListObj form completes the process of
creating the content for the Information Pane displayed by a list.

Syntax XMLDoc_Save of form syListObj, XML_state

Parameters • XML_state – A field of the type ListPrevPaneXMLState that contains the state
information for the Information Pane XML document.

Examples Refer to the example for XMLDoc_Create.

INTEGRATION GUIDE 593


594 IN T E G R AT I O N G U ID E
Menu scripts
The following scripts are used when defining menu items for an integrating
application:

• AddCommandToMenu()
• AddNavBarButton()
• AlreadyExistsOnMenu()
• FindCommandInMenu()
• MenusExistForProduct()

INTEGRATION GUIDE 595


M E N U S C R I P T S A D D C O M M A N D T O M E N U ( )

AddCommandToMenu()

Description The AddCommandToMenu function provided by Microsoft Dynamics GP is used


to add a command or command list to an existing menu.

Syntax AddCommandToMenu ParentDictID, ParentFormID, ParentCmdID, Sequence,


CmdDictID, CmdFormID, CmdID, CloneCmd, LoadMode;

Parameters • ParentDictID – The ID of the dictionary that contains the command list (menu or
submenu) to which the new command will be added. Use the constant DYNAMICS
to specify that you are adding items to the Microsoft Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list to which you are adding a command.

• ParentCmdID – The resource ID of the command list to which you are adding a
command.

• Sequence – An integer variable that can be used to specify the sequence of the item in
the command list. The value 0 specifies the command will be added to the end of
the list. The actual position of the command will be returned after the command is
added.

• CmdDictID – The ID of the dictionary that contains the command you are adding.

• CmdFormID – The resource ID of the command form that contains the definition of
the command you are adding.

• CmdID – The resource ID of the command you are adding.

• CloneCmd – A boolean parameter. The value true specifies that the command will be
added for all users, while the value false specifies that the command will be added
for only the current user.

• LoadMode – An integer that specifies where the command will be added. The value
corresponds to one of the following constants:

Constant Description
MENULOAD_TOTABLE The menu items are being added to the default menu set
in the syMenuMstr table.
MENULOAD_TOMEMORY The menu items are being added directly to the menu set
displayed in Microsoft Dynamics GP.

Return value An integer indicating whether the command was added to the menu. The value
corresponds to one of the following constants:

Constant Description
OKAY The command was successfully added.
DUPLICATE The command was not added because it already exists.

Comments When you add your menu items, we recommend that you add them to the end of
the menu or submenu. You should also consider using a separator to separate your
items from the default items.

596 IN T E G R AT I O N G U ID E
M E N U S C R I P T S A D D C O M M A N D T O M E N U ()

To add a separator to a menu, use the following constants to specify the built-in
separator command:

Constant Description
CMD_BUILTINCMD_DICTID Specifies the ID of the dictionary that contains the
separator built-in command.
CMD_BUILTINCMD_FORMID Specifies the resource ID of the form that defines
the separator built-in command.
cmdSeparator The built-in separator command.

Examples The following example is a portion of the IG_CreateMenuItems procedure in the


sample integrating application. It uses the AddCommandToMenu() function to
add a separator and the IG_Lead_Maintenance command to the CL_Sales_Cards
command list (submenu).

{Add a separator, which is a built-in command}


Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
Seq,
CMD_BUILTINCMD_DICTID,
CMD_BUILTINCMD_FORMID,
resourceid(command cmdSeparator),
true,
LoadMode);

if Status <> OKAY then


error "Could not add separator item.";
end if;

{Add the IG_Lead_Maintenance command}


Seq = 0;
Status = AddCommandToMenu(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
Seq,
3333,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true,
LoadMode);

if Status <> OKAY then


error "Could not add command IG_Lead_Maintenance.";
end if;

INTEGRATION GUIDE 597


M E N U S C R I P T S A D D N A V B A R B U T T O N ()

AddNavBarButton()
Description The AddNavBarButton() function defined for the syNavBarBtnObj form adds a
button to the Navigation pane.

Syntax AddNavBarButton(UserID, Sequence, Visible, CmdDictID, CmdFormID, CmdID, 0, 0,


0, CloneCmd)

Parameters • UserID – A string that specifies to which user’s set of menus the button will be
added. Specify the empty string ("") to add to the default set of menus.

• Sequence – An integer variable that specifies the position of the button in the
Navigation pane. The value 0 specifies the button will be added to the end of the
list. The actual position of the button will be returned after it is added.

You should always specify the value 0 for this variable to add the new Navigation pane
button to the end of the list.

• Visible – A boolean that specifies whether the button is visible in the Navigation
pane. The value true specifies the button is visible, while the value false specifies
that it is not.

• CmdDictID – The ID of the dictionary that contains the command to use for the
Navigation pane button.

• CmdFormID – The resource ID of the command form that contains the definition of
the command to be added to the Navigation pane.

• CmdID – The resource ID of the command to be added to the Navigation pane.

• CloneCmd – A boolean parameter. The value true specifies that the command will be
added for all users, while the value false specifies that the command will be added
for only the current user. You should always specify the value true when adding a
new Navigation pane button.

Return value An integer indicating whether the command was added to the menu. The value
corresponds to one of the following constants:

Constant Description
OKAY The button was successfully added.
DUPLICATE The button was not added because it already exists.

Comments Microsoft Dynamics GP can have a maximum of 20 Navigation pane buttons.

Examples The following example is the IG_CreateNavigationBarButton procedure for the


sample integrating application. It adds the Sample button to the Navigation pane.
local string sWhere;
local integer nStatus;
local integer nSeq;

{Find out whether the Navigation pane categories for this product have already
been added}
sWhere = physicalname('CmdParentDictID' of table syNavBarButtons) + CH_SPACE
➥ + CH_EQUAL + CH_SPACE + str(IG_PROD_ID);

598 IN T E G R AT I O N G U ID E
M E N U S C R I P T S A D D N A V B A R B U T T O N ()

range clear table syNavBarButtons;


range table syNavBarButtons where sWhere;
get first table syNavBarButtons;
if err() = OKAY then
abort script;
end if;

nSeq = 0;

{Add the button to navigation}


nStatus = AddNavBarButton("",
nSeq,
true,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command Navigation_IGSample of form Command_IG_Sample),
0,
0,
0,
true) of form syNavBarBtnObj;

INTEGRATION GUIDE 599


M E N U S C R I P T S A L R E A D Y E X I S T S O N M E N U ()

AlreadyExistsOnMenu()

Description The AlreadExistsOnMenu() function defined in the syMenuObj form is provided


by Microsoft Dynamics GP so you can easily determine whether a command or
command list is part of an existing menu.

Syntax AlreadyExistsOnMenu(UserID, ParentDictID, ParentFormID, ParentCmdID,


CmdDictID, CmdFormID, CmdID {,Sequence})

Parameters • UserID – A string that specifies which user’s set of menus will be examined to find
out whether the menu item exists. Specify the empty string ("") to examine the
default set of menus.

• ParentDictID – The ID of the dictionary that contains the command list (menu or
submenu) that is being examined. Use the constant DYNAMICS to specify the
Microsoft Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that is being examined.

• ParentCmdID – The resource ID of the command list that is being examined.

• CmdDictID – The ID of the dictionary that contains the command whose existance is
being examined.

• CmdFormID – The resource ID of the command form that contains the definition of
the command whose existance is being examined.

• CmdID – The resource ID of the command whose existance is being examined.

• Sequence – An optional integer variable that can be used to retrieve the sequence of
the item in the command list, if the item exists. The value 0 indicates the item does
not exist.

Return value The function returns a boolean. The value true indicates the command already
exists on the menu, while the value false indicates it does not.

Examples The following example uses the AlreadyExistsOnMenu() function to verify


whether the IG_Lead_Maintenance command exists on the CL_Sales_Cards
command list (submenu).

if AlreadyExistsOnMenu("", DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Cards of form Command_Sales),
3333,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
➥ Seq) of form syMenuObj = true then

{Do not need to add the menu items}


AddMenuItems = false;
end if;

600 IN T E G R AT I O N G U ID E
M E N U S C R I P T S F I N D C O M M A N D I N M E N U ()

FindCommandInMenu()

Description The FindCommandInMenu() function provided by Microsoft Dynamics GP is used


to find the location of a command or command list in an existing menu.

Syntax FindCommandInMenu(ParentDictID, ParentFormID, ParentCmdID, CmdDictID,


CmdFormID, CmdID, LoadMode {, UserID})

Parameters • ParentDictID – The ID of the dictionary that contains the command list (menu or
submenu) that is being examined. Use the constant DYNAMICS to specify the
Microsoft Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that is being examined.

• ParentCmdID – The resource ID of the command list that is being examined.

• CmdDictID – The ID of the dictionary that contains the command whose location is
being examined.

• CmdFormID – The resource ID of the command form that contains the definition of
the command whose location is being examined.

• CmdID – The resource ID of the command whose location is being examined.

• LoadMode – An integer that specifies which set of menus is being examined. The
value corresponds to one of the following constants:

Constant Description
MENULOAD_TOTABLE The menu set in the syMenuMstr table is being examined.
MENULOAD_TOMEMORY The menu set displayed in Microsoft Dynamics GP is
being examined.

• UserID – An optional string that specifies which user’s set of menus will be
examined to find the position of the menu item. Specify the empty string ("") to
examine the default set of menus.

Return value An integer that specifies the location (sequence number) of the specified menu item.
The value 0 indicates the item was not found in the menu or submenu.

Examples The following example uses the FindCommandInMenu() function to retrieve the
location of the ListObj_Salespeople (Salesperson) command that appears in the
Sales Lists menu.

local integer Seq;

Seq = FindCommandInMenu(DYNAMICS,
resourceid(form Command_System),
resourceid(command CL_Sales_Lists of form Command_System),
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command ListObj_Salespeople of form Command_Sales),
LoadMode,
"");

INTEGRATION GUIDE 601


M E N U S C R I P T S M E N U S E X I S T F O R P R O D U C T ( )

MenusExistForProduct()

Description The MenusExistForProduct() function defined in the syMenuObj form is provided


by Microsoft Dynamics GP so you can easily determine whether any default menu
items have been defined for an integrating product.

Syntax MenusExistForProduct(Product_ID)

Parameters • Product_ID– The ID of the dictionary for which default menu items will be
examined.

Return value A boolean. The value true indicates that default menu items exist for the product,
while false indicates they do not.

Examples The following example is a portion of the IG_CreateMenuItems procedure in the


sample integrating application. It uses the MenusExistForProduct() function to
verify whether the default menu items have been added to the syMenuMstr table.

if MenusExistForProduct(3333) of form syMenuObj = true then


{Do not need to add the menu items}
AddMenuItems = false;
end if;

602 IN T E G R AT I O N G U ID E
Report scripts
The following scripts are used when working with reports and report templates for
an integrating application:

• syImportReportTemplate()
• syRemoveReportTemplate()

INTEGRATION GUIDE 603


R E P O R T S C R I P T S S Y I M P O R T R E P O R T T E M P L A T E ( )

syImportReportTemplate()

Description The syImportReportTemplate() function is used to import a report template


document for a report into Microsoft Dynamics GP.

Syntax syImportReportTemplate(display_name, product_ID, resource_ID, report_type,


filename, replace, series_dictionary_ID, series)

Parameters • display_name – A string specifying the display name of the report. Typically, this is
the same name as the report template document being imported, but without the
.docx file extension.

• product_ID – The product ID of the dictionary that contains the report for which a
report template is being imported.

• resource_ID – An integer specifying the resource ID for the report for which a report
template is being imported.

• report_type – An integer specifying the type of report for which a report template is
being imported. The following table lists the possible values:

Value Description
1 Original report
2 Modified report
3 Alternate report
4 Modified alternate report

• filename – A string specifying the complete path and filename for the report
template document. The path must be in native format.

• replace – A boolean. The value true indicates that any existing report template with
the same name should be replaced.

• series_dictionary_ID – The dictionary that defines the series. Set this to the product
ID of the dictionary that contains the report definition for which a template is being
imported.

• series – An integer specifying the series the report is included in. The series values
are listed in the following table.

Series Value
Financial 1
Sales 2
Purchasing 3
Inventory 4
Payroll 5
Project 6
System 7
Company 8
3rd Party 10

604 IN T E G R AT I O N G U ID E
R E P O R T S C R I P T S S Y I M P O R T R E P O R T T E M P L A T E ()

Return value An integer indicating the status. The value corresponds to one of the following
constants:

Constant Description
TEMPLATE_OKAY The template was successfully imported.
TEMPLATE_INVALID The template is not valid or cannot be found.
TEMPLATE_EXISTS The template already exists.
TEMPLATE_NOREPLACE A default template is already installed and cannot be replaced.

Examples The following example is the IG_Trigger_Delayed_Install_Actions procedure for the


sample integrating application. This procedure runs after the user has successfully
logged into Microsoft Dynamics GP. In this script, a report template for the
IG_Leads_List report is imported.

local integer result;


local string location;

{Retrieve the location of Microsoft Dynamics GP}


location = Path_GetForApp(PATH_EXEFOLDER);

{Make the path native}


location = Path_MakeNative(location);

{Import the report template for the report}


result = syImportReportTemplate("IG_Leads_List Template",
IG_PROD_ID,
resourceid(report IG_Leads_List),
1 {original},
location + "IG_Leads_List Template.docx",
true,
IG_PROD_ID,
2); {Sales series}
case result
in [TEMPLATE_OKAY, TEMPLATE_EXISTS]
{No error, so do nothing}
in [TEMPLATE_INVALID]
error "Template is invalid or cannot be found.";
else
error "An unknown error occurred importing the template for
➥ IG_Leads_List.";
end case;

INTEGRATION GUIDE 605


R E P O R T S C R I P T S S Y R E M O V E R E P O R T T E M P L A T E ( )

syRemoveReportTemplate()

Description The syRemoveReportTemplate() function is used to remove a report template


document for a report from Microsoft Dynamics GP.

Syntax syRemoveReportTemplate(product_ID, resource_ID, display_name)

Parameters • product_ID – The product ID of the dictionary that contains the report for which a
report template is being removed.

• resource_ID – An integer specifying the resource ID for the report for which a report
template is being removed.

• display_name – A string specifying the display name of the report for which a report
template is being removed. This name must match the display name that was used
when the report template was imported into Microsoft Dynamics GP.

Return value An integer indicating the status. The value corresponds to one of the following
constants:

Constant Description
TEMPLATE_OKAY The template was successfully removed.
TEMPLATE_INVALID The template could not be found.
TEMPLATE_ISDEFAULT The template was pre-defined and cannot be removed.
TEMPLATE_ISASSIGNED The template is assigned to a company and cannot be
removed.

Examples The following example...

local integer result;

result = syRemoveReportTemplate(IG_PROD_ID, resourceid(report IG_Leads_List),


➥ "IG_Leads_List Template");
case result
in [TEMPLATE_OKAY]
{No error, so do nothing}
in [TEMPLATE_INVALID]
error "Template cannot be found.";
in [TEMPLATE_ISDEFAULT]
error "Template is a default template.";
in [TEMPLATE_ISASSIGNED]
error "Template is assigned to a company.";
else
error "An unknown error occurred remvoing the template for
➥ IG_Leads_List.";
end case;

606 IN T E G R AT I O N G U ID E
Security scripts
The following scripts are used when implementing security features for an
integrating application:

• AddSecurityTaskOperation()
• AddTaskToRole()
• CreateSecurityRole()
• CreateSecurityTask()
• DeleteSecurityForProduct()
• Exists() -- Security Role
• Exists() -- Security Task
• Exists() -- Security Task Operation
• Exists() -- Security Task Role
• GetValidSystemPassword()
• LoadListView
• Security()
• SetIndex
• syUserInRole()

INTEGRATION GUIDE 603


S E C U R I T Y S C R I P T S A D D S E C U R I T Y T A S K O P E R A T I O N ( )

AddSecurityTaskOperation()

Description The AddSecurityTaskOperation() function of the sySecurityTaskOperations form


adds an operation to the specified security task.

Syntax AddSecurityTaskOperation(task_ID, dict_ID, security_restype, security_ID)

Parameters • task_ID – A string specifying the ID of the task to which an operation is being
added.

• dict_ID – An integer specifying the ID of the dictionary that contains the resource
for which a security operation is being added.

• security_restype – An integer specifying the type of resource for which a security


operation is being added. Use one of the following constants:

Contant Value
TABLETYPE 1
FORMTYPE 2
REPORTTYPE 23
SECURITYTYPE_LISTS 900
SECURITYTYPE_SMARTLISTOBJECT 1000

• security_ID – A long integer identifying the resource for which a security operation
is being added. The following table describes the value to use for each security
resource type:

Security resource type Security ID


Tables Table Resource ID
Forms Form Resource ID
Reports Report Resource ID
Lists Dictionary-specific ID for the list
SmartLists Dictionary-specific ID for the SmartList object

Return value An integer indicating whether the operation was added to the security task. The
value corresponds to one of the following constants:

Constant Description
OKAY The operation was added successfully
DUPLICATE The operation already exists

Comments To build the security ID for a list, use the BuildDictSpecificID() function. The
following constants are defined for the portions of the list for which security can be
controlled:

Constant Description
LISTSECURITYTYPE_LIST The base list
LISTSECURITYTYPE_PREVPANE The information pane for the list
LISTSECURITYTYPE_CUSTOMIZE The customization capability for the list

Use one of these constants as the product ID (first parameter) for the
BuildDictSpecificID() function. Use the unique integer identifier you assigned to
the list as the action (second parameter).

604 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S A D D S E C U R I T Y T A S K O P E R A T I O N ()

To build the security ID for a SmartList object, use the BuildDictSpecificID()


function. Use your dictionary ID (first parameter) and the ID value you assigned to
the SmartList object you created as the action (second parameter).

Examples The following is a portion of the IG_CreateSecurityData prodcure for the sample
integrating application. It adds security operations to the CART_IGSAMPLE_01
task. A form operation, table operation, report operation, the various list operations,
and a SmartList operation are added to the security task.
local long status;
local string taskID;

taskID = "CARD_IGSAMPLE_01";

{Lead Maintenance form}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
FORMTYPE,
resourceid(form IG_Lead_Maintenance))
of form sySecurityTaskOperations;

{Leads report}
status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
REPORTTYPE,
resourceid(report IG_Leads))
of form sySecurityTaskOperations;

{Lead master table}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
TABLETYPE,
resourceid(table IG_Leads_MSTR))
of form sySecurityTaskOperations;

{Leads list - Base List}


{The value 1 is the ID of the Lead list}
status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
SECURITYTYPE_LISTS,
BuildDictSpecificID(LISTSECURITYTYPE_LIST, 1))
of form sySecurityTaskOperations;

{Leads list - Information Pane}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
SECURITYTYPE_LISTS,
BuildDictSpecificID(LISTSECURITYTYPE_PREVPANE, 1))
of form sySecurityTaskOperations;

{Leads list - Customization}


status = AddSecurityTaskOperation(taskID,
IG_PROD_ID,
SECURITYTYPE_LISTS,
BuildDictSpecificID(LISTSECURITYTYPE_CUSTOMIZE, 1))
of form sySecurityTaskOperations;

INTEGRATION GUIDE 605


S E C U R I T Y S C R I P T S A D D S E C U R I T Y T A S K O P E R A T I O N ( )

{Leads SmartList}
status = AddSecurityTaskOperation(taskID,
SMARTLIST,
1000, {Use constant SECURITYTYPE_SMARTLISTOBJECT in GP 10 SP1 and later}
BuildDictSpecificID(IG_PROD_ID, SMARTLIST_OBJECTTYPE_LEADS))
of form sySecurityTaskOperations;

606 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S A D D T A S K T O R O L E ()

AddTaskToRole()
Description The AddTaskToRole() function of the sySecurityTaskRole form adds a task to the
specified security role.

Syntax AddTaskToRole(role_ID, task_ID)

Parameters • role_ID – A string specifying the ID of the security role to which a task is being
added.

• task_ID – A string specifying the ID of the task being added.

Return value An integer indicating whether the task was added to the security role. The value
corresponds to one of the following constants:

Constant Description
OKAY The task was added successfully
DUPLICATE The task already exists

Examples The following example adds the CARD_IGSAMPLE_01 security task to the LEAD
GENERATION security role.

local long status;


local string roleID;

roleID = "LEAD GENERATION";


status = AddTaskToRole(roleID, "CARD_IGSAMPLE_01") of form
➥ sySecurityTaskRole;

INTEGRATION GUIDE 607


S E C U R I T Y S C R I P T S C R E A T E S E C U R I T Y R O L E ( )

CreateSecurityRole()

Description The CreateSecurityRole() function of the sySecurityRole form creates a new


security role.

Syntax CreateSecurityRole(role_ID, role_name, description)

Parameters • role_ID – A string specifying the ID of the role being created.

• role_name – A string specifying the name displayed for the security role.

• description – A string specifying the description for the security role.

Return value An integer indicating whether the security role was added. The value corresponds
to one of the following constants:

Constant Description
OKAY The security role was added successfully
DUPLICATE The security role already exists

Examples The following example adds the LEAD GENERATION role for the sample
integrating application.

local long status;


local string roleID;

{Add the Lead Generation security role}


roleID = "LEAD GENERATION";
if Exists(roleID) of form sySecurityRole = false then

{Role does not exist, so create it}


status = CreateSecurityRole(roleID, {ID}
"Lead Generation", {Name}
"Tasks include creating and updating customer leads.") {Description}
of form sySecurityRole;
end if;

608 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S C R E A T E S E C U R I T Y T A S K ()

CreateSecurityTask()

Description The CreateSecurityTask() function of the sySecurityTask form creates a new


security task.

Syntax CreateSecurityTask(task_ID, task_name, description, category)

Parameters • task_ID – A string specifying the ID of the security task that is being created.

• task_name – A string specifying the name displayed for the security task.

• description – A string specifying the description for the security task.

• category – An integer specifying the category for the security task. Use one of the
following constants, defined in the sySecurityRoleEntry form:

Constant Description
CATEGORY_COMPANY Company
CATEGORY_FINANCIAL Financial
CATEGORY_INVENTORY Inventory
CATEGORY_OTHER Other
CATEGORY_PAYROLL Payroll
CATEGORY_PROJECT Project
CATEGORY_PURCHASING Purchasing
CATEGORY_SALES Sales
CATEGORY_SYSTEM System

Return value An integer indicating whether the security task was added. The value corresponds
to one of the following constants:

Constant Description
OKAY The security task was added successfully
DUPLICATE The security task already exists

Examples The following example adds the CARD_IGSAMPLE_01 security task used for the
sample integrating application. The new security task is part of the Sales category.

local long status;


local string taskID;

taskID = "CARD_IGSAMPLE_01";
status = CreateSecurityTask(taskID, {ID}
"Maintain leads", {Name}
"Maintain lead information and setup.", {Description}
CATEGORY_SALES of form sySecurityRoleEntry)
of form sySecurityTask;

INTEGRATION GUIDE 609


S E C U R I T Y S C R I P T S D E L E T E S E C U R I T Y F O R P R O D U C T ()

DeleteSecurityForProduct()
Description The DeleteSecurityForProduct() function removes the security task operations and
the modified/alternate forms and reports settings for the specified product.

Syntax DeleteSecurityForProduct(dict_ID)

Parameters • dict_ID – An integer specifying the ID of the dictionary for which the security
information is being deleted.

Return value A boolean. The value true indicates the security data was removed, while the value
false indicates it was not.

Examples The following example removes the security data for the sample integrating
application.

local boolean result;

result = DeleteSecurityForProduct(IG_PROD_ID);

610 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S E X I S T S ( ) -- S E C U R I T Y R O L E

Exists() -- Security Role

Description The Exists() function of the sySecurityRole form verifies whether the specified
security role exists in Microsoft Dynamics GP.

Syntax Exists(role_ID)

Parameters • role_ID – A string specifying the ID of the security role.

Return value A boolean. The value true indicates the security role exists, while the value false
indicates it does not.

Examples The following example uses the Exists() function to indicate whether the LEAD
GENERATION security role exists. If it does not, the role is added.

local string roleID;

roleID = "LEAD GENERATION";


if Exists(roleID) of form sySecurityRole = false then
{Role does not exist, so create it}
status = CreateSecurityRole(roleID, {ID}
"Lead Generation", {Name}
"Tasks include creating and updating customer leads.") {Description}
of form sySecurityRole;
end if;

INTEGRATION GUIDE 611


S E C U R I T Y S C R I P T S E X I S T S ( ) - - S E C U R I T Y T A S K

Exists() -- Security Task

Description The Exists() function of the sySecurityTask form verifies whether the specified task
exists in Microsoft Dynamics GP.

Syntax Exists(task_ID)

Parameters • task_ID – A string specifying the ID of the security task.

Return value A boolean. The value true indicates the security task exists, while the value false
indicates it does not.

Examples The following example uses the Exists() function to indicate whether the
CARD_IGSAMPLE_01 security task exists. If it does not, the security task is added.

local string taskID;

taskID = "CARD_IGSAMPLE_01";
if Exists(taskID) of form sySecurityTask = false then
{Task does not exist, so create it}
status = CreateSecurityTask(taskID, {ID}
"Maintain leads", {Name}
"Maintain lead information and setup.", {Description}
CATEGORY_SALES of form sySecurityRoleEntry)
of form sySecurityTask;
end if;

612 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S E X I S T S ( ) - - S E C U R I T Y T A S K O P E R A T I O N

Exists() -- Security Task Operation

Description The Exists() function of the sySecurityTaskOperations form verifies whether the
specified security task operation exists in Microsoft Dynamics GP.

Syntax Exists(task_ID, dict_ID, security_ID, security_restype)

Parameters • task_ID – A string specifying the ID of the task which could contain the specified
operation.

• dict_ID – An integer specifying the ID of the dictionary that contains the resource
for the security operation.

• security_ID – A long integer identifying the resource for the security operation. The
following table describes the value to use for each security resource type:

Security resource type Security ID


Tables Table Resource ID
Forms Form Resource ID
Reports Report Resource ID
Lists Dictionary-specific ID for
the list

• security_restype – An integer specifying the type of resource for the security


operation. Use one of the following constants:

Contant Value
TABLETYPE 1
FORMTYPE 2
REPORTTYPE 23
SECURITYTYPE_LISTS 900

Return value A boolean. The value true indicates the security task operation exists, while the
value false indicates it does not.

Comments To build the security ID for a list, use the BuildDictSpecificID() function. The
following constants are defined for the portions of the list for which security can be
controlled:

Constant Description
LISTSECURITYTYPE_LIST The base list
LISTSECURITYTYPE_PREVPANE The information pane for the list
LISTSECURITYTYPE_CUSTOMIZE The customization capability for the list

Use one of these constants as the product ID (first parameter) for the
BuildDictSpecificID() function. Use the unique integer identifier you assigned to
the list as the action (second parameter).

INTEGRATION GUIDE 613


S E C U R I T Y S C R I P T S E X I S T S ( ) - - S E C U R I T Y T A S K O P E R A T I O N

Examples The following example verifies whether the security task operation for access to the
base functionality of the Leads list exists for the sample integrating application. The
ID for the Leads lists is 1.

local string taskID;

taskID = "CARD_IGSAMPLE_01";
if Exists(taskID,
IG_PROD_ID,
BuildDictSpecificID(LISTSECURITYTYPE_LIST, 1),
SECURITYTYPE_LISTS) of form sySecurityTaskOperations = false then
warning "Security task operation does not exist for the Leads list.";
end if;

614 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S E X I S T S ( ) - - S E C U R I T Y T A S K R O L E

Exists() -- Security Task Role


Description The Exists() function of the sySecurityTaskRole form verifies whether the specified
security task has been added to a security role.

Syntax Exists(role_ID, task_ID)

Parameters • role_ID – A string specifying the ID of the security role.

• task_ID – A string specifying the ID of the security task.

Return value A boolean. The value true indicates the security task exists for the security role,
while the value false indicates it does not.

Examples The following example verifies whether the security task CARD_IGSAMPLE_01
has been added to the LEAD GENERATION security role.

local string taskID;


local string roleID;

taskID = "CARD_IGSAMPLE_01";
roleID = "LEAD GENERATION";
if Exists(roleID, taskID) of form sySecurityTaskRole = false then
warning "Security task does not exist for the LEAD GENERATION role.";
end if;

INTEGRATION GUIDE 615


S E C U R I T Y S C R I P T S G E T V A L I D S Y S T E M P A S S W O R D ( )

GetValidSystemPassword()

Description The GetValidSystemPassword() function prompts the current user to enter the
system password defined when Microsoft Dynamics GP was installed. The value
true or false is returned, depending on whether the correct password was supplied.

Syntax GetValidSystemPassword()

Parameters • None

Return value A boolean. The value true indicates the correct system password was supplied,
while false indicates that it was not.

Comments Carefully consider where you place the GetValidSystemPassword() function to


control access. For example, when restricting access for a form, place the function in
the form pre script. This ensures that the restriction code is run, regardless of how
the form is opened.

Examples The following example is the form pre script for the IG_Sample_Setup form. It uses
the GetValidSystemPassword() function to prompt the user for the system
password before opening a setup window for the sample integrating application.

local boolean result;

result = GetValidSystemPassword();

if result = false then


close form IG_Lead_Maintenance;
abort script;
end if;

616 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S L O A D L I S T V I E W

LoadListView
Description The LoadListView procedure defined for the sySecurityTaskEntry form is used to
add a security operation to the list of operations for that type that are displayed in
the Security Task Setup window in Microsoft Dynamics GP.

Syntax LoadListView of form sySecurityTaskEntry, operation, operation_ID, security_type,


dict_ID, accessible

Parameters • operation – A string containing the name of the operation being added to the list.

• operation_ID – An integer specifying the ID of the operation being added to the list.

• security_type – An integer specifying the security type that contains the operation
being added.

• dict_ID – An integer specifying the dictionary that defines the security type and
operation.

• accessible – A boolean. The value true specifies the operation is marked and will be
accessible to the task. The value false specifies the operation is unmarked and will
not accessible to the task.

Examples Refer to the example for SetIndex.

INTEGRATION GUIDE 617


S E C U R I T Y S C R I P T S S E C U R I T Y ( )

Security()

Description The Security() function is used to verify whether the current user has access to the
specified resource.

Syntax Security(product_ID, restype, item_ID)

Parameters • product_ID – An integer specifying the ID of the product that contains the item for
which security is being examined. This must be an integer variable. If an alternate
version of a form or report is being used, the product ID of the dictionary containing
the alternate version being used will be returned to this parameter.

• restype – An integer that specifies what type of item is being examined. The value
corresponds to one of the following constants:

Constant Description
FORMTYPE A form
REPORTTYPE A report
TABLETYPE A table

• item_ID – An integer specifying the resource ID of the item for which security is
being examined.

Return value An integer. The value 0 indicates the user has access, while the value corresponding
to the constant REJECT_RECORD indicates they do not.

Examples The following script examines the IG_Contact_History form to verify that the
current user has access. Notice that a local variable containing the product ID is
passed into the function.
local integer dict_ID = 3333;
local integer result;

result = Security(dict_ID, FORMTYPE, resourceid(form IG_Contact_History));

The following script examines the security status of the Account_Lookup form in
the Dynamics dictionary to find out whether an alternate version of the form is
being used. If an alternate form is being used, the product ID for the dictionary is
returned and displayed.
local integer dict_ID;
local integer result;

dict_ID = 0;
result = Security(dict_ID, FORMTYPE, resourceid(form Account_Lookup));

if result = 0 then
if dict_ID = 0 then
{Acess to the original version}
warning "Access to Original";
else
{Access to an alternate version}
warning "Access to alternate in dictionary with ID: " + str(dict_ID);
end if;
else
warning "Access denied.";
end if;

618 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S S E T I N D E X

SetIndex
Description The SetIndex procedure defined for the sySecurityTaskOperations form is used to
specify a security operation that will be examined for its current status. The
procedure is used when an integration defines a new security type, and the
operations for that type are displayed in the Security Task Setup window in
Microsoft Dynamics GP.

Syntax SetIndex of form sySecurityTaskOperations, task_state, task_ID, dict_ID,


operation_ID, security_type

Parameters • task_state – A composite of type sySecurityTaskOperationsState that maintains the


state information for the operations in the specified task.

• task_ID – The ID for the current task. This is typically the 'Security Task ID' field in
the syTaskEntry winow of the sySecurityTaskEntry form.

• dict_ID – An integer specifying the dictionary that defines the security type and
operations.

• operation_ID – An integer specifying the ID of the operation that is being examined.

• security_type – An integer specifying the security type that contains the operations.

Examples The following example is the trigger processing procedure that runs when the
operations for a security task are to be displayed in the Security Task Setup window.
The procedure uses the SetIndex procedure to specify the operation to be added to
the list. The operation is examined, and the status information is used to control
how the LoadListView procedure adds the operation to the list.

in integer dict_ID;
in integer security_type;
in integer security_series;

local sySecurityTaskOperationsState TaskOperationsState;


local long status;

if isopen(window syTaskEntry of form sySecurityTaskEntry) then


if dict_ID = IG_PROD_ID then
if security_type = 100 then
status = Create(TaskOperationsState, table
➥ sySecurityAssignTaskOperations) of form
➥ sySecurityTaskOperations;
if status <> OKAY then
abort script;
end if;

if security_series = 1 then
{Look up the security status of each item as it is added, so
that the marked or unmarked state can be set}

{Series 1 Item 1 -- ID is 101}


call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form

INTEGRATION GUIDE 619


S E C U R I T Y S C R I P T S S E T I N D E X

➥ sySecurityTaskEntry,
IG_PROD_ID,
101,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 101",
➥ 101, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 101",
➥ 101, security_type, dict_ID, false;
end if;

{Series 1 Item 2 -- ID is 102}


call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
102,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 102",
➥ 102, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 102",
➥ 102, security_type, dict_ID, false;
end if;
end if;

if security_series = 2 then
{Series 2 Item 1 -- ID is 201}
call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
201,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}

620 IN T E G R AT I O N G U ID E
S E C U R I T Y S C R I P T S S E T I N D E X

call LoadListView of form sySecurityTaskEntry, "Item 201",


➥ 201, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 201",
➥ 201, security_type, dict_ID, false;
end if;

{Series 2 Item 2 -- ID is 202}


call SetIndex of form sySecurityTaskOperations,
TaskOperationsState,
'Security Task ID' of window syTaskEntry of form
➥ sySecurityTaskEntry,
IG_PROD_ID,
202,
security_type;

status = Get(TaskOperationsState, GET + EQUAL) of form


➥ sySecurityTaskOperations;

if status = OKAY then


{User already has access}
call LoadListView of form sySecurityTaskEntry, "Item 202",
➥ 202, security_type, dict_ID, true;
else
{User does not have access}
call LoadListView of form sySecurityTaskEntry, "Item 202",
➥ 202, security_type, dict_ID, false;
end if;
end if;

call ClearRange of form sySecurityTaskOperations,


➥ TaskOperationsState;
call Destroy of form sySecurityTaskOperations,
➥ TaskOperationsState;
end if;
end if;
end if;

INTEGRATION GUIDE 621


S E C U R I T Y S C R I P T S S Y U S E R I N R O L E ( )

syUserInRole()
Description The syUserInRole() function is used to find whether a user is assigned to specific
server or database roles for SQL Server.

Syntax syUserInRole(user_ID, role {, database})

Parameters • user_ID – A string specifying the ID of a user in Microsoft Dynamics GP.

• role – A string specifying the role being examined. Use one of the following
constants:

Constant Description
ROLE_SYSADMIN Members of the sysadmin fixed server role can perform any
activity in the database.
ROLE_SECURITYADMIN Members of the securityadmin fixed server role manage
logins and their properties. They can GRANT, DENY, and
REVOKE server-level permissions. They can also GRANT,
DENY, and REVOKE database-level permissions. Additionally,
they can reset passwords for SQL Server logins.
ROLE_DBCREATOR Members of the dbcreator fixed server role can create, alter,
drop, and restore any database.
ROLE_DBOWNER* Members of the db_owner fixed database role can perform all
configuration and maintenance activities on the database.
ROLE_DBACCESSADMIN* Members of the db_accessadmin fixed database role can add
or remove access for Windows logins, Windows groups, and
SQL Server logins.
ROLE_DBSECURITYADMIN* Members of the db_securityadmin fixed database role can
modify role membership and manage permissions.
ROLE_DBBACKUPOPERATOR* Members of the db_backupoperator fixed database role can
backup the database.
*Requires the database to be specified

• database – An optional string parameter specifying the database for which access is
being examined. This parameter must be supplied when querying whether a user is
assigned to a specific role for the database.

Return value A boolean. The value true indicates the user is in the specified role, while false
indicates the user is not.

Comments The 'User ID' global variable contains the user ID for the user currently logged into
Microsoft Dynamics GP. The 'Intercompany ID' global variable contains the
database name for the current company’s database.

Examples The following example verifies whether the current user logged into Microsoft
Dynamics GP is assigned to the “sysadmin” role.
if syUserInRole('User ID' of globals, ROLE_SYSADMIN) then
warning "User is System Administrator";
end if;

The following example verifies whether the current user logged into Microsoft
Dynamics GP is assigned to the “dbowner” role for the current company.
if syUserInRole('User ID' of globals, ROLE_DBOWNER, 'Intercompany ID' of
➥ globals) then
warning "User is DB Owner";
end if;

622 IN T E G R AT I O N G U ID E
Shortcut scripts
The following form-level functions are used by integrating applications to add
shortcuts to the Navigation pane:

• ScBar_AddDexForm()
• ScBar_AddExternalFile()
• ScBar_AddFolder()
• ScBar_AddMacro()
• ScBar_AddUrl()
• ScBar_ItemExists

INTEGRATION GUIDE 623


S H O R T C U T S C R I P T S S C B A R _ A D D D E X F O R M ( )

ScBar_AddDexForm()

Description The ScBar_AddDexForm() function adds a Dexterity-based form from the specified
dictionary to the Shortcut Bar.

Syntax ScBar_AddDexForm(type, name, parent_ID, shortcut_display_name, resource_ID,


product_ID)

Parameters • type – An integer indicating whether the shortcut is being added for a specific user
or for a specific user class. Use one of the following constants (which are part of the
syScBarObj form):

Constant Description
scgPERSONAL The shortcut is being added for a specific user.
scgUSERCLASS The shortcut is being added for a specific user class.

• name – A string specifying the user name or user class to which the shortcut is being
added.

• parent_ID – An integer indicating the parent node to which the shortcut will be
added. The value 0 indicates the root level.

• shortcut_display_name – A string containing the text that will be used for the
shortcut.

• resource_ID – A integer specifying the resource ID of the form for which the shortcut
is being added. You can use the Resource_GetID() function in Dexterity to retrieve
the ID of a specific form in your dictionary.

• product_ID – The product ID of the dictionary that contains the form for which the
shortcut is being created.

Return value A boolean. True indicates the shortcut was successfully added, while false indicates
it was not.

Examples The following example adds a shortcut for the Lead Maintenance form from the
sample integration application. This shortcut will be available only for
LESSONUSER1.
local boolean result;
local integer res_id;

res_id = Resource_GetID(3333, 2, "IG_Lead_Maintenance");


result = ScBar_AddDexForm(scgPERSONAL of form syScBarObj,
➥ "LESSONUSER1", 0, "Lead Maintenance", res_id, 3333) of form syScBarObj;

624 IN T E G R AT I O N G U ID E
S H O R T C U T S C R I P T S S C B A R _ A D D E X T E R N A L F I L E ()

ScBar_AddExternalFile()

Description The ScBar_AddExternalFile() function adds a shortcut for an external file to the
Shortcut Bar.

Syntax ScBar_AddExternalFile(type, name, parent_ID, shortcut_display_name, filename)

Parameters • type – An integer indicating whether the shortcut is being added for a specific user
or for a specific user class. Use one of the following constants (which are part of the
syScBarObj form):

Constant Description
scgPERSONAL The shortcut is being added for a specific user.
scgUSERCLASS The shortcut is being added for a specific user class.

• name – A string specifying the user name or user class to which the shortcut is being
added.

• parent_ID – An integer indicating the parent node to which the shortcut will be
added. The value 0 indicates the root level.

• shortcut_display_name – A string containing the text that will be used for the
shortcut.

• filename – A string specifying the complete path to the file. The path must be in
native format.

Return value A boolean. True indicates the shortcut was successfully added, while false indicates
it was not.

Examples The following example adds a shortcut for the Notepad application. This shortcut
will be available only for LESSONUSER1.

local boolean result;

result = ScBar_AddExternalFile(scgPERSONAL of form syScBarObj,


➥ "LESSONUSER1", 0, "Notepad", "C:\windows\notepad.exe") of form syScBarObj;

INTEGRATION GUIDE 625


S H O R T C U T S C R I P T S S C B A R _ A D D F O L D E R ( )

ScBar_AddFolder()

Description The ScBar_AddFolder() function adds a folder to the Shortcut Bar. Folders are used
for grouping items in the Shortcut Bar.

Syntax ScBar_AddFolder(type, name, parent_ID, folder_name)

Parameters • type – An integer indicating whether the folder is being added for a specific user or
for a specific user class. Use one of the following constants (which are part of the
syScBarObj form):

Constant Description
scgPERSONAL The folder is being added for a specific user.
scgUSERCLASS The folder is being added for a specific user class.

• name – A string specifying the user name or user class to which the folder is being
added.

• parent_ID – An integer indicating the parent node to which the folder will be added.
The value 0 indicates the root level.

• folder_name – A string containing the text that will be used for the folder name.

Return value An integer containing the node ID of the new folder.

Examples The following example adds a folder named “Sample” to the Shortcut Bar. This
folder will be available only for LESSONUSER1.

local boolean result;

result = ScBar_AddFolder(scgPERSONAL of form syScBarObj,


➥ "LESSONUSER1", 0, "Sample") of form syScBarObj;

626 IN T E G R AT I O N G U ID E
S H O R T C U T S C R I P T S S C B A R _ A D D M A C R O ()

ScBar_AddMacro()

Description The ScBar_AddMacro() function adds a shortcut for a macro to the Shortcut Bar.

Syntax ScBar_AddMacro(type, name, parent_ID, shortcut_display_name, macro_name)

Parameters • type – An integer indicating whether the shortcut is being added for a specific user
or for a specific user class. Use one of the following constants (which are part of the
syScBarObj form):

Constant Description
scgPERSONAL The shortcut is being added for a specific user.
scgUSERCLASS The shortcut is being added for a specific user class.

• name – A string specifying the user name or user class to which the shortcut is being
added.

• parent_ID – An integer indicating the parent node to which the shortcut will be
added. The value 0 indicates the root level.

• shortcut_display_name – A string containing the text that will be used for the
shortcut.

• macro_name – A string specifying the path to the macro file. The path must be in
native format.

Return value A boolean. True indicates the shortcut was successfully added, while false indicates
it was not.

Examples The following example adds a shortcut for a macro named “Setup.mac”. This
shortcut will be available only for LESSONUSER1.

local boolean result;

result = ScBar_AddMacro(scgPERSONAL of form syScBarObj, "LESSONUSER1", 0,


➥ "Setup Workspace", "C:\macros\setup.mac") of form syScBarObj;

INTEGRATION GUIDE 627


S H O R T C U T S C R I P T S S C B A R _ A D D U R L ( )

ScBar_AddUrl()

Description The ScBar_AddUrl() function adds a shortcut for a URL to the Shortcut Bar.

Syntax ScBar_AddUrl(type, name, parent_ID, shortcut_display_name, url)

Parameters • type – An integer indicating whether the shortcut is being added for a specific user
or for a specific user class. Use one of the following constants (which are part of the
syScBarObj form):

Constant Description
scgPERSONAL The shortcut is being added for a specific user.
scgUSERCLASS The shortcut is being added for a specific user class.

• name – A string specifying the user name or user class to which the shortcut is being
added.

• parent_ID – An integer indicating the parent node to which the shortcut will be
added. The value 0 indicates the root level.

• shortcut_display_name – A string containing the text that will be used for the
shortcut.

• url – A string specifying the URL to display.

Return value A boolean. True indicates the shortcut was successfully added, while false indicates
it was not.

Examples The following example adds a shortcut to open the Microsoft web site. This shortcut
will be available only for LESSONUSER1.

local boolean result;

result = ScBar_AddUrl(scgPERSONAL of form syScBarObj, "LESSONUSER1", 0,


➥ "Microsoft", "http://www.microsoft.com") of form syScBarObj;

628 IN T E G R AT I O N G U ID E
S H O R T C U T S C R I P T S S C B A R _ I T E M E X I S T S

ScBar_ItemExists

Description The ScBar_ItemExists() function indicates whether the specified shortcut has been
added to the Shortcut Bar.

Syntax ScBar_ItemExists(type, name, shortcut_display_name)

Parameters • type – An integer indicating whether the shortcut is for a specific user or for a
specific user class. Use one of the following constants (which are part of the
syScBarObj form):

Constant Description
scgPERSONAL The shortcut is for a specific user.
scgUSERCLASS The shortcut is for a specific user class.

• name – A string specifying the user name or user class which is being examined to
find out whether the shortcut exists.

• shortcut_display_name – A string containing the text of the shortcut to search for.

Return value A boolean. True indicates the shortcut exists, while false indicates it does not.

Examples The following example verifies that the shortcut to open the Microsoft web site
exists for LESSONUSER1. If it doesn’t, the shortcut is added.

local boolean shortcut_exists;


local boolean result;

shortcut_exists = ScBar_ItemExists(scgPERSONAL, of form syScBarObj,


➥ "LESSONUSER1", "Microsoft") of form syScBarObj;
if shortcut_exists = false then
result = ScBar_AddUrl(scgPERSONAL of form syScBarObj, "LESSONUSER1", 0,
➥ "Microsoft", "http://www.microsoft.com") of form syScBarObj;
end if;

INTEGRATION GUIDE 629


630 IN T E G R AT I O N G U ID E
Setup Checklist scripts
The following scripts are used when adding items to the Setup Checklist for
Microsoft Dynamics GP:

• AddSetupChecklistItem()
• FindSetupChecklistItem()

INTEGRATION GUIDE 631


S E T U P C H E C K L I S T S C R I P T S A D D S E T U P C H E C K L I S T I T E M ( )

AddSetupChecklistItem()

Description The AddSetupChecklistItem() function of the sySetupChecklistObj form adds an


item or category to the Setup Checklist.

Syntax AddSetupChecklistItem(ParentDictID, ParentFormID, ParentCmdID, Sequence,


CmdDictID, CmdFormID, CmdID, WindowTechName, Optional, HelpFile, HelpTopic)

Parameters • ParentDictID – The ID of the dictionary that contains the command list used for the
node to which the Setup Checklist item will be added. Use the constant DYNAMICS
to specify that you are adding an item to a category defined by the Microsoft
Dynamics GP main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list used for the node to which you are adding an item.

• ParentCmdID – The resource ID of the command list used for the node to which you
are adding an item.

• Sequence – An integer variable that can be used to specify the position of the item
being added. The value 0 specifies the item will be added to the end of the category
list. The actual position of the item will be returned after it is added.

• CmdDictID – The ID of the dictionary that contains the command you are adding.

• CmdFormID – The resource ID of the command form that contains the definition of
the command you are adding.

• CmdID – The resource ID of the command you adding.

• WindowTechName – A string specifying the technical name of the window to be


accessed by the Setup Checklist item. If you are adding a category to the Setup
Checklist, specify the empty string ("").

• Optional – A boolean that indicates whether the setup action to be performed by the
Setup Checklist item is optional. The value true indicates the action is optional,
while the value false indicates it is required.

• HelpFile – A string specifying the name of the constant in your application


dictionary that contains the name of the compiled HTML Help file to display a topic
from. The value of the constant must include the .chm file extension.

• HelpTopic – A string specifying the HTML Help topic to display for the Setup
Checklist item or category. You must specify the HTML filename of the topic to
display, including the .htm file extension. You cannot use a help context number to
specify a topic to display.

Return value An integer indicating whether the item was added to the Setup Checklist. The value
corresponds to one of the following constants:

Constant Description
OKAY The item was successfully added.
DUPLICATE The item was not added because it already exists.

632 IN T E G R AT I O N G U ID E
S E T U P C H E C K L I S T S C R I P T S A D D S E T U P C H E C K L I S T I T E M ()

Comments The constant SETUPCHECKLIST_TOPLEVEL is used to specify the dictionary ID,


command form ID, and command ID of the top-level node in the Setup Checklist
tree. This node isn’t visible in the tree.

Every item you add to the Setup Checklist should have a corresponding help topic
in the compiled HTML Help file for your integration. For individual items, the topic
should describe the setup actions the user can perform with the setup window. For
categories, the topic should describe the overall setup process for the group.

Examples The following example uses the AddSetupChecklistItem() function to add a new
category as a first-level node in the Setup Checklist tree. The new category is
defined by the CL_IG_Sample_Setup command list. The constant value
SETUPCHECKLIST_TOPLEVEL indicates the category is being added to the top-
level node in the tree. Because it is a category, no window technical name is needed.
The constant IG_CHM_NAME contains the name of the help file from which to
display a topic. The topic named “SampleSetup.htm” will be displayed from this
help file.

local integer status;


local integer seq = 0;

status = AddSetupChecklistItem(DYNAMICS,
SETUPCHECKLIST_TOPLEVEL,
SETUPCHECKLIST_TOPLEVEL,
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_Setup of form Command_IG_Sample),
"",
false,
"IG_CHM_NAME",
"SampleSetup.htm") of form sySetupChecklistObj;

The following example uses the AddSetupChecklistItem() function to add a Setup


Checklist item to the end of the Sales category already defined in the Setup
Checklist. The new item is defined by the command IG_Contact_History_Setup.
The technicalname() function is used to retrieve the technical name for the setup
window being opened. The setup item will be displayed as required. The constant
IG_CHM_NAME contains the name of the help file from which to display a topic.
The topic named “ContactHistorySetup.htm” will be displayed from this help file.

local integer status;


local integer seq = 0;

status = AddSetupChecklistItem(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History_Setup of form Command_IG_Sample),
technicalname(window Contact_History_Setup of form
➥ IG_Contact_History_Setup),
false,
"IG_CHM_NAME",
"ContactHistorySetup.htm") of form sySetupChecklistObj;

INTEGRATION GUIDE 633


S E T U P C H E C K L I S T S C R I P T S A D D S E T U P C H E C K L I S T I T E M ( )

The following example uses the FindSetupChecklistItem() function to locate the


Customer item in the Sales category of the Setup Checklist. The
AddSetupChecklistItem() function is used to add a new category and item below
the Customer node in the tree.

local integer status;


local integer seq;

{Find the Customers item}


seq = FindSetupChecklistItem(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command RM_Customer_Maintenance of form Command_Sales))
➥ of form sySetupChecklistObj;

{Add the new item after the Customers item}


seq = seq + 1;

status = AddSetupChecklistItem(DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_Setup of form Command_IG_Sample),
"",
false,
"IG_CHM_NAME",
"SampleSetup.htm") of form sySetupChecklistObj;

{Add an item to the new category}


seq = 0; {At the end}
status = AddSetupChecklistItem(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_Setup of form Command_IG_Sample),
seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Contact_History_Setup of form Command_IG_Sample),
technicalname(window Contact_History_Setup of form
➥ IG_Contact_History_Setup),
false,
"IG_CHM_NAME",
"ContactHistorySetup.htm") of form sySetupChecklistObj;

634 IN T E G R AT I O N G U ID E
S E T U P C H E C K L I S T S C R I P T S F I N D S E T U P C H E C K L I S T I T E M ()

FindSetupChecklistItem()

Description The FindSetupChecklistItem() function of the sySetupChecklistObj form retrieves


the location of the specified item in a Setup Checklist category.

Syntax FindSetupChecklistItem(ParentDictID, ParentFormID, ParentCmdID, CmdDictID,


CmdFormID, CmdID)

Parameters • ParentDictID – The ID of the dictionary that contains the command list used for the
Setup Checklist category that will be searched.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list used for the Setup Checklist category that will be searched.

• ParentCmdID – The resource ID of the command list used for the Setup Checklist
category that will be searched.

• CmdDictID – The ID of the dictionary that contains the command for the Setup
Checklist item whose location is being examined.

• CmdFormID – The resource ID of the command form that contains the definition of
the command for the Setup Checklist item whose location is being examined.

• CmdID – The resource ID of the command for the Setup Checklist item whose
location is being examined.

Return value An integer that specifies the location (sequence number) of the specified Setup
Checklist item. The value 0 indicates the item was not found in the category
specified for the Setup Checklist.

Examples The following example uses the FindSetupChecklistItem() function to retrieve the
location of the Sales category in the Setup Checklist.

local integer seq;

seq = FindSetupChecklistItem(DYNAMICS,
SETUPCHECKLIST_TOPLEVEL,
SETUPCHECKLIST_TOPLEVEL,
DYNAMICS,
resourceid(form Command_Sales),
resourceid(command CL_Sales_Setup of form Command_Sales)) of form
➥ sySetupChecklistObj;

INTEGRATION GUIDE 635


636 IN T E G R AT I O N G U ID E
SmartList scripts
The following scripts are used when integrating with SmartList. These scripts are
found in the SmartList dictionary, not the core dictionary. They must be called using
the call with name statement along with the constant SMARTLIST to specify the
product.

• Explorer_Add_Column_To_Object
• Explorer_Add_GoTo_Item
• Explorer_Add_Object
• Explorer_AddItem_To_ListView
• Explorer_Add_SubItem_To_ListView
• Explorer_Check_Stop_Processing
• Explorer_Remove_Column_From_Object
• Explorer_Remove_GoTo_Item
• Explorer_Remove_Object
• Explorer_Search_Generic
• Explorer_Set_SQL_Join_Info
• Explorer_Set_SQL_Query_Field
• Explorer_SQL_Search_Generic

INTEGRATION GUIDE 637


S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ C O L U M N _ T O _ O B J E C T

Explorer_Add_Column_To_Object

Description The Explorer_Add_Column_To_Object procedure defined in the SmartList


dictionary adds a new column to a SmartList object.

Syntax Explorer_Add_Column_To_Object, Object_Dict_ID, Object_Type, Field_Dict_ID,


Field_ID, Display_Name, Field_Name, Default_Display, Datatype, DDL_Type, In_Lookup,
User_Defined_Field, Display_Sequence, Field_Sequence, Error

Parameters • Object_Dict_ID – An integer specifying the dictionary that defines the SmartList
object to which a column is being added. For SmartList objects defined in the core
application, use the constant DYNAMICS.

• Object_Type – An integer indicating the SmartList object in the specified dictionary


to which the column is being added. For SmartList objects defined in the core
application, use one of the constants described in SmartList objects on page 332.

• Field_Dict_ID – An integer specifying the dictionary in which the field to use for the
column is located.

• Field_ID – An integer specifying the unique ID to use for the column. Typically, this
will be the resource ID of the field used for the column.

• Display_Name – A string that will be the default name for the column. The string can
be up to 80 characters long.

• Field_Name – A string containing the technical name of the field used for the new
column.

• Default_Display – A boolean that indicates whether the column will be displayed as


part of the default query. The value true indicates it will, while false indicates it will
not.

• Datatype – An integer specifying the underlying datatype of the column being


added. The value corresponds to one of the following constants:

Datatype Constant Value


Integer SMARTLIST_DATATYPE_INTEGER 1
Long integer SMARTLIST_DATATYPE_LONG 2
Date SMARTLIST_DATATYPE_DATE 3
Currency SMARTLIST_DATATYPE_CURRENCY 4
String SMARTLIST_DATATYPE_STRING 5
Boolean SMARTLIST_DATATYPE_BOOLEAN 6
Drop-down list SMARTLIST_DATATYPE_DDL 7
Account index SMARTLIST_DATATYPE_ACCOUNTINDEX 8
Account number SMARTLIST_DATATYPE_ACCOUNTNUMBER 9
Phone number SMARTLIST_DATATYPE_PHONENUMBER 10
Social Security number SMARTLIST_DATATYPE_SSN 11
Time SMARTLIST_DATATYPE_TIME 12

638 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ C O L U M N _ T O _ O B J E C T

• DDL_Type – An integer that specifies whether the list field used for the column is 0-
based (items numbered 0, 1, 2) or 1-based (items numbered 1, 2, 3). Specify 0 for 0-
based numbering. Specify 1 for 1-based numbering. If the field is not a list, specify 1.

Radio groups use 0-based numbering. All other list fields, such as drop-down lists and list
boxes, use 1-based numbering.

• In_Lookup – A boolean that indicates whether the column should appear in the
Advanced Lookup window for the SmartList object to which you are adding a
column. This parameter should be set to true only if your added columns to an
existing SmartList object in the core dictionary that has a corresponding Advanced
Lookup window.

• User_Defined_Field – A boolean that indicates whether the field used for the column
is a user-defined field. The value true indicates that it is, while false indicates that it
is not. User-defined fields have their prompts defined at runtime by the user.

• Display_Sequence – A returned integer that indicates the sequence the new colum
will be displayed in if you have chosen to include it in the default query. You should
initially set this value to zero. SmartList will return the next available sequence
number that you can use when adding additional columns to the specified
SmartList object.

• Field_Sequence – A returned integer that indicates the sequence number of the


column being added to the SmartList object. You should initially set this value to
zero. SmartList will return the next available sequence number that you can use
when adding additional columns to the specified SmartList object.

• Error – A returned integer containing the database error that was returned by
SmartList when the column was added. The following table lists the typical values
returned:

Constant Value Error type


OKAY 0 No Error
DUPLICATE 17 Duplicate Record

Comments When a new column is added to a SmartList object, the information about the
column is written to the ASITAB20 table. If incorrect parameter values were used
when you wrote the column, you will have to manually remove the record from this
table. If you leave the existing record and try to rewrite the column information
with parameter changes, you will receive a dupliate record error.

Examples The following example adds a new column to the Customers SmartList object. This
column will not be included in the default query for the SmartList object.

local integer l_error;


local string l_message;
local integer display_sequence, field_sequence;

{Add additional columns to the Customer object for SmartList}


call with name "Explorer_Add_Column_To_Object" in dictionary SMARTLIST,
DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
IG_PROD_ID,
resourceid(field 'First Contact Date'),
"First Contact",

INTEGRATION GUIDE 639


S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ C O L U M N _ T O _ O B J E C T

"First Contact Date",


false, {Do not include in default query}
SMARTLIST_DATATYPE_DATE,
1,
false,
false,
display_sequence,
field_sequence,
l_error;

if (l_error <> OKAY) or (l_error <> DUPLICATE) then


warning "Error "+ str(l_error) +" occurred writing the SmartList column.";
end if;

640 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ G O T O _ I T E M

Explorer_Add_GoTo_Item

Description The Explorer_Add_GoTo_Item procedure defined in the SmartList dictionary adds


a new Go To item to a SmartList object.

Syntax Explorer_Add_GoTo_Item, Object_Dict_ID, Object_Type, GoTo_Prompt,


GoTo_Dict_ID, GoTo_Item, GoTo_Default, Error

Parameters • Object_Dict_ID – An integer specifying the dictionary that defines the SmartList
object to which a Go To item is being added. For SmartList objects defined in the
core application, use the constant DYNAMICS.

• Object_Type – An integer indicating the SmartList object in the specified dictionary


to which the Go To item is being added. For SmartList objects defined in the core
application, use one of the constants described in SmartList objects on page 332.

• GoTo_Prompt – A string that specifies the prompt to display in the Go To button


drop list. The string can be up to 50 characters long.

• GoTo_Dict_ID – An integer specifying the dictionary that contains the code to


process the Go To item.

• GoTo_Item – An integer that uniquely identifies the Go To item. Often, the resource
ID of the form used to process the Go To item will be used.

• GoTo_Default – A boolean that specifies whether the Go To item will be the default
Go To action for the specified SmartList. There should be only one default item for
each SmartList object type.

• Error – A returned integer containing the database error that was returned by
SmartList when the Go To item was added. The following table lists the typical
values returned:

Constant Value Error type


OKAY 0 No Error
DUPLICATE 17 Duplicate Record

Comments When a new Go To item is added to a SmartList object, the information about the
item is written to the ASIEXP60 table. If incorrect parameter values were used when
you wrote the Go To item, you will have to manually remove the record from this
table. If you leave the existing record and try to rewrite the Go To information with
parameter changes, you will receive a dupliate record error.

INTEGRATION GUIDE 641


S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ G O T O _ I T E M

Examples The following example adds a Go To item to the Customers SmartList object.

local integer l_error;


local string l_message;

call with name "Explorer_Add_GoTo_Item" in dictionary SMARTLIST,


DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
"Contact History",
IG_PROD_ID,
resourceid(form IG_Contact_History), {Unique ID for this form}
false, {Not the default GoTo item}
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
warning "Error " + str(l_error) + " occurred writing the Go To item.";
end if;

642 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ O B J E C T

Explorer_Add_Object

Description The Explorer_Add_Object procedure creates a new SmartList object.

Syntax Explorer_Add_Object, Object_Dict_ID, Object_Type, Object_Name, Error

Parameters • Object_Dict_ID – An integer specifying the dictionary that is defining the new
SmartList object, typically the ID of your integrating product.

• Object_Type – An integer specifying the unique ID for the new SmartList object. The
object type must be unique within the scope of the dictionary defining the new
object. You may want to create a constant that contains the object type.

• Object_Name – A string specifying the name of the new SmartList object. The name
can be up to 80 characters long.

• Error – A returned integer containing the database error that was returned by
SmartList when the new SmartList object was created. The following table lists the
typical values returned:

Constant Value Error type


OKAY 0 No Error
DUPLICATE 17 Duplicate Record

Comments You must create the new SmartList object before you can add new columns and Go
To items to it.

Examples The following example creates a new Leads SmartList object for the sample
integrating application. The IG_PROD_ID constant contains the product ID for the
sample.

local integer l_error;

{Create the new SmartList object}


call with name "Explorer_Add_Object" in dictionary SMARTLIST,
IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
"Leads",
l_error;
if l_error <> OKAY and l_error <> DUPLICATE then
error "Error creating Leads SmartList object";
end if;

INTEGRATION GUIDE 643


S M A R T L I S T S C R I P T S E X P L O R E R _ A D D I T E M _ T O _ L I S T V I E W

Explorer_AddItem_To_ListView

Description The Explorer_AddItem_To_ListView procedure adds one item to the list view field
in the SmartList window. It is used in the procedure that is called as individual
records are added to the SmartList.

Syntax Explorer_AddItem_To_ListView, Label, Record_Count, Object_Name, Index

Parameters • Label – A string that must contain the primary key values needed to retrieve the
record that supplies the data for the item being added. Other applications will use
the key values stored in the label to identify the record, such as when processing Go
To items.

• Record_Count – A long integer specifying the total number of items being added to
the list view. This number will be displayed in the status area at the bottom of the
SmartList window.

• Object_Name – A string that contains the name of the type of objects being displayed
in the SmartList. This name will be displayed in the status area at the bottom of the
SmartList window.

• Index – A returned long integer that contains the index of the new list view item.
You will use this index with the Explorer_Add_SubItem_To_ListView procedure
to add subitems to the new item.

Comments This procedure should be called with the foreground parameter, ensuring that it
runs in the foreground.

Examples The following example is the SmartList_Leads_FillOneRowAtTime procedure from


the sample integrating application. This procedure is called in the foreground and
adds one Lead record to the SmartList window by calling the
Explorer_AddItem_To_ListView procedure. Once the item is added, the subitems
for the Lead record are added.

in integer IN_Total_SubItems;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in long IN_Record_Count;
inout table IG_Leads_MSTR;

local long n;
local integer l_Count;
local string l_Field_As_String;
local long l_Field_As_Integer;
local date l_Field_As_Date;
local currency l_Field_As_Currency;
local time l_Field_As_Time;
local integer l_Datatype;
local boolean b_Success;

call with name "Explorer_AddItem_To_ListView" in dictionary SMARTLIST,


'Lead ID' of table IG_Leads_MSTR,
IN_Record_Count,
"Leads",
n;

644 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ A D D I T E M _ T O _ L I S T V I E W

set l_Count to 1;

while (l_Count <= IN_Total_SubItems) do

{The list of field IDs is contained in the IN_Field_List[] Array}

case IN_Field_List[l_Count]
in [resourceid(field 'Lead ID')]
l_Field_As_String = 'Lead ID' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Lead Name')]
l_Field_As_String = 'Lead Name' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Lead Business Category')]
{Need a "helper" window field to get the category name}
'Lead Business Category' of window Dummy of form Command_IG_Sample
➥ = 'Lead Business Category' of table IG_Leads_MSTR;
l_Field_As_String = itemname('Lead Business Category' of window
➥ Dummy of form Command_IG_Sample, 'Lead Business Category' of
➥ table IG_Leads_MSTR);
l_Field_As_Integer = 'Lead Business Category' of table
➥ IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Potential Revenue')]
l_Field_As_String = format('Potential Revenue' of table
➥ IG_Leads_MSTR, true, true, 2, SYSTEMNEG);
l_Field_As_Currency = 'Potential Revenue' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_CURRENCY;
in [resourceid(field 'Contact')]
l_Field_As_String = 'Contact' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 1')]
l_Field_As_String = 'Address 1' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Address 2')]
l_Field_As_String = 'Address 2' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'City')]
l_Field_As_String = 'City' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'State')]
l_Field_As_String = 'State' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Zip')]
l_Field_As_String = 'Zip' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Phone 1')]
l_Field_As_String = FormatPhoneNumber('Phone 1' of table
➥ IG_Leads_MSTR);
l_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Phone 2')]
l_Field_As_String = FormatPhoneNumber('Phone 2' of table
➥ IG_Leads_MSTR);
l_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Fax')]

INTEGRATION GUIDE 645


S M A R T L I S T S C R I P T S E X P L O R E R _ A D D I T E M _ T O _ L I S T V I E W

l_Field_As_String = FormatPhoneNumber('Fax' of table


➥ IG_Leads_MSTR);
l_Datatype = SMARTLIST_DATATYPE_PHONENUMBER;
in [resourceid(field 'Salesperson ID')]
l_Field_As_String = 'Salesperson ID' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
in [resourceid(field 'Qualified Lead')]
{Need a "helper" window field to get the qualification status}
'Qualified Lead' of window Dummy of form Command_IG_Sample =
➥ 'Qualified Lead' of table IG_Leads_MSTR;
l_Field_As_String = itemname('Qualified Lead' of window Dummy of
➥ form Command_IG_Sample, 'Qualified Lead' of table
➥ IG_Leads_MSTR);
l_Field_As_Integer = 'Qualified Lead' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_DDL;
in [resourceid(field 'Qualification Date')]
l_Field_As_String = str('Qualification Date' of table
➥ IG_Leads_MSTR);
l_Field_As_Date = 'Qualification Date' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_DATE;
in [resourceid(field 'Lead Source')]
l_Field_As_String = 'Lead Source' of table IG_Leads_MSTR;
l_Datatype = SMARTLIST_DATATYPE_STRING;
end case;

call with name "Explorer_AddSubItem_To_ListView" in dictionary SMARTLIST,


n,
l_Count,
l_Field_As_String,
l_Field_As_Integer,
l_Field_As_Date,
l_Field_As_Currency,
l_Field_As_Time,
l_Datatype,
b_Success;

increment l_Count;
end while;

646 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ A D D _ S U B I T E M _ T O _ L I S T V I E W

Explorer_Add_SubItem_To_ListView

Description The Explorer_AddSubItem_To_ListView procedure adds one subitem to an item


in the list view field of the SmartList window. It is used after a item has been added
using the Explorer_AddItem_To_ListView procedure.

Syntax Explorer_Add_SubItem_To_ListView, Index, Column, Display_String, Sort_Integer,


Sort_Date, Sort_Currency, Sort_Time, Datatype, Result

Parameters • Index – A long integer that specifies the list view item to which the subitem is to be
added. Use the value that was returned from the Explorer_AddItem_To_ListView
procedure.

• Column – An integer specifying the column number of the subitem being added to
the list view.

• Display_String – A string specifying the text that will be displayed in the column.
The string will be displayed exactly as it’s supplied. Any formatting (such as for
currency fields) must be done before the value is passed to this parameter.

• Sort_Integer – For an integer subitem, the integer value that will be used for sorting
the column.

• Sort_Date – For a date subitem, the data value that will be used for sorting the
column.

• Sort_Currency – For a currency subitem, the currency value that will be used for
sorting the column.

• Sort_Time – For a time subitem, the time value that will be used for sorting the
column.

• Datatype – An integer specifying the underlying datatype of the subitem being


added. The value corresponds to one of the following constants:

Datatype Constant Value


Integer SMARTLIST_DATATYPE_INTEGER 1
Long integer SMARTLIST_DATATYPE_LONG 2
Date SMARTLIST_DATATYPE_DATE 3
Currency SMARTLIST_DATATYPE_CURRENCY 4
String SMARTLIST_DATATYPE_STRING 5
Boolean SMARTLIST_DATATYPE_BOOLEAN 6
Drop-down list SMARTLIST_DATATYPE_DDL 7
Account index SMARTLIST_DATATYPE_ACCOUNTINDEX 8
Account number SMARTLIST_DATATYPE_ACCOUNTNUMBER 9
Phone number SMARTLIST_DATATYPE_PHONENUMBER 10
Social Security number SMARTLIST_DATATYPE_SSN 11
Time SMARTLIST_DATATYPE_TIME 12

• Result – A returned boolean that indicates whether the subitem was added. The
value true indicates it was added, while the value false indicates it was not.

Comments Be sure this procedure is called so that it runs in the foreground.

Examples Refer to the example for Explorer_AddItem_To_ListView.

INTEGRATION GUIDE 647


S M A R T L I S T S C R I P T S E X P L O R E R _ C H E C K _ S T O P _ P R O C E S S I N G

Explorer_Check_Stop_Processing

Description The Explorer_Check_Stop_Processing procedure is used to determine whether the


user clicked the Stop button or closed the SmartList window during processing.

Syntax Explorer_Check_Stop_Processing, Stop

Parameters • Stop – A returned boolean that will be true if the user has chosen to stop processing,
and false if they have not.

Comments This procedure should be called at least once in the loop that fills the SmartList with
data items.

Examples The following example is the procedure from the sample integrating application
that adds Leads records to the SmartList. Notice that the procedure uses the
Explorer_Check_Stop_Processing procedure to know whether to continue adding
items to the SmartList.

in integer IN_Total_SubItems;
in Explorer_BOOL_List IN_Searching;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
in Explorer_INT_List IN_Datatype;
in Explorer_INT_List IN_Type;
in Explorer_STR30_List IN_Search_From;
in Explorer_STR30_List IN_Search_To;
in Explorer_BOOL_List IN_Match_Case;
in integer IN_Global_Search_Type;
in Explorer_Field_Comparison IN_Field_Comparison;
in Explorer_Start_Comp_Field_ID IN_Start_Comp_Field_ID;
in Explorer_Start_Comp_Field_Dict IN_Start_Comp_Field_Dict;
in Explorer_End_Comp_Field_ID IN_End_Comp_Field_ID;
in Explorer_End_Comp_Field_Dict IN_End_Comp_Field_Dict;

inout long IO_Max_Records;

in boolean IN_GetSummary;
in integer IN_Summary_Type; {0 = Number of records, 1 = Total of Column}
inout integer IO_SummaryCount;
in integer IN_nSummaryFieldDictID;
in integer IN_nSummaryFieldID;
inout currency IO_ColumnTotal;

local boolean b_Stop, b_Found;


local long l_Record_Count;
local integer l_Key;

set l_Record_Count to 0;
set l_Key to 1;
call with name "Explorer_Check_Stop_Processing" in dictionary SMARTLIST,
➥ b_Stop;

{ Loop through table to get records }

648 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ C H E C K _ S T O P _ P R O C E S S I N G

get first table IG_Leads_MSTR by number l_Key;


while(err() <> EOF) and (l_Record_Count < IO_Max_Records) and (not b_Stop) do

{Set the global SmartList Master ID}


SmartList_Master_ID of globals = 'Lead ID' of table IG_Leads_MSTR;

call with name "Explorer_Search_Generic" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
IN_Searching,
IN_Field_Dict_ID,
IN_Field,
IN_Datatype,
IN_Type,
IN_Search_From,
IN_Search_To,
IN_Match_Case,
IN_Global_Search_Type,

IN_Field_Comparison,
IN_Start_Comp_Field_ID,
IN_Start_Comp_Field_Dict,
IN_End_Comp_Field_ID,
IN_End_Comp_Field_Dict,

b_Found;

if b_Found then
increment l_Record_Count;
call foreground SmartList_Leads_FillOneRowAtTime,
IN_Total_SubItems,
IN_Dict_List,
IN_Field_List,
l_Record_Count,
table IG_Leads_MSTR;
end if;

get next table IG_Leads_MSTR by number l_Key;


call with name "Explorer_Check_Stop_Processing" in dictionary SMARTLIST,
➥ b_Stop;
end while;

INTEGRATION GUIDE 649


S M A R T L I S T S C R I P T S E X P L O R E R _ R E M O V E _ C O L U M N _ F R O M _ O B J E C T

Explorer_Remove_Column_From_Object

Description The Explorer_Remove_Column_From_Object procedure removes the specified


column from a SmartList object.

Syntax Explorer_Remove_Column_From_Object, Object_Dict_ID, Object_Type,


Field_Dict_ID, Field_ID

Parameters • Object_Dict_ID – An integer specifying the dictionary that defines the SmartList
object from which a column is being removed. For SmartList objects defined in the
core application, use the constant DYNAMICS.

• Object_Type – An integer indicating the SmartList object in the specified dictionary


from which the column is being removed. For SmartList objects defined in the core
application, use one of the constants described in SmartList objects on page 332.

• Field_Dict_ID – An integer specifying the dictionary in which the field used for the
column is located.

• Field_ID – An integer specifying the unique ID used for the column. Typically, this
will be the resource ID of the field used for the column.

Comments Use this procedure to remove columns that you have added for your integration.
You cannot remove columns defined by the core dictionary.

Examples The following example removes the First Contact Date column from the Customers
SmartList object.

call with name "Explorer_Remove_Column_From_Object" in dictionary SMARTLIST,


DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
IG_PROD_ID,
resourceid(field 'First Contact Date');

650 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ R E M O V E _ G O T O _ I T E M

Explorer_Remove_GoTo_Item

Description The Explorer_Remove_GoTo_Item procedure removes the specified Go To item


from a SmartList object.

Syntax Explorer_Remove_GoTo_Item, Object_Dict_ID, Object_Type, GoTo_Dict_ID,


GoTo_Item, Error

Parameters • Object_Dict_ID – An integer specifying the dictionary that defines the SmartList
object from which a Go To item is being removed. For SmartList objects defined in
the core application, use the constant DYNAMICS.

• Object_Type – An integer indicating the SmartList object in the specified dictionary


from which the Go To item is being removed. For SmartList objects defined in the
core application, use one of the constants described in SmartList objects on page 332.

• GoTo_Dict_ID – An integer specifying the dictionary that contains the code to


process the Go To item.

• GoTo_Item – An integer that uniquely identifies the Go To item. Often, the resource
ID of the form used to process the Go To item will be used.

• Error – A returned integer containing the database error that was returned by
SmartList when the Go To item was removed. The following table lists the typical
values returned:

Constant Value Error type


OKAY 0 No Error
MISSING 18 Missing record

Comments Use this procedure to remove Go To items that you have added for your integration.
You cannot remove Go To items defined by the core dictionary.

Examples The following example removes the Contact History Go To item added to the
Customers SmartList object.

local integer l_error;

call with name "Explorer_Remove_GoTo_Item" in dictionary SMARTLIST,


DYNAMICS,
SMARTLIST_OBJECTTYPE_CUSTOMERS,
IG_PROD_ID,
resourceid(form IG_Contact_History), {Unique ID for this form}
l_error;
if l_error <> OKAY then
error "An error occurred while removing the Go To item.";
end if;

INTEGRATION GUIDE 651


S M A R T L I S T S C R I P T S E X P L O R E R _ R E M O V E _ O B J E C T

Explorer_Remove_Object

Description The Explorer_Remove_Object procedure removes the specified SmartList object.

Syntax Explorer_Remove_Object, Object_Dict_ID, Object_Type, Error

Parameters • Object_Dict_ID – An integer specifying the dictionary that defined the SmartList
object being removed.

• Object_Type – An integer specifying the unique ID for the SmartList object.

• Error – A returned integer containing the database error that was returned by
SmartList when the SmartList object was removed. The following table lists the
typical values returned:

Constant Value Error type


OKAY 0 No Error
MISSING 18 Missing record

Comments Use this procedure to remove SmartList objects that you have added for your
integration. You cannot remove SmartList objects defined by the core dictionary.

Examples The following example removes the Leads SmartList object defined by the sample
integrating application.

local integer l_error;

call with name "Explorer_Remove_Object" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
l_error;
if l_error <> OKAY then
error "Error removing Lead SmartList object";
end if;

652 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ S E A R C H _ G E N E R I C

Explorer_Search_Generic

Description The Explorer_Search_Generic procedure is called to determine whether the current


record meets the search criteria specified by the SmartList user. The return value
true indicates the record should be displayed in the SmartList.

Syntax Explorer_Search_Generic, Object_Dict_ID, Object_Type, Searching, Field_Dict_ID,


Field, Datatype, Type, Search_From, Search_To, Match_Case, Global_Search_Type,
Field_Comparison, Start_Comp_Field_ID, Start_Comp_Field_Dict_ID,
End_Comp_Field_ID, End_Comp_Field_Dict_ID, Found

Parameters • Object_Dict_ID – An integer specifying the dictionary that has defined the SmartList
object.

• Object_Type – An integer indicating the SmartList object in the specified dictionary


that is being used to display records. For SmartList objects defined in the core
application, use one of the constants described in SmartList objects on page 332.

• Searching – An array of four boolean values indicating whether any search criteria
are being used. If no search criteria are used, the Found parameter will always return
true.

• Field_Dict_ID – An array of four integers containing the dictionary IDs of the fields
being searched.

• Field – An array of four integers containing the resource IDs of the fields being
searched.

• Datatype – An array of four integers containing the datatypes of the fields being
searched.

• Type – An array of four integers that indicate the type of searches being performed.
For instance, “contains” or “is equal to” are common search types.

• Search_From – An array of four strings that the search fields will be compared to.

• Search_To – An array of four strings that the search fields will be compared to.

• Match_Case – An array of four booleans indicating whether the search should match
case.

• Global_Search_Type – An integer indicating the type of search: Match All or Match 1


or More.

• Field_Comparison – An array of four booleans indicating that the search to be


performed is comparing the contents of two fields in the SmartList.

• Start_Comp_Field_ID – An array of four integers containing the resource IDs of the


fields that will be compared.

• Start_Comp_Field_Dict_ID – An array of four integers containing the dictionary IDs


for the fields that will be compared.

• End_Comp_Field_ID – An array of four integers containing the resource IDs of the


fields that will be compared.

INTEGRATION GUIDE 653


S M A R T L I S T S C R I P T S E X P L O R E R _ S E A R C H _ G E N E R I C

• End_Comp_Field_Dict_ID – An array of four integers containing the dictionary IDs


for the fields that will be compared.

• Found – A returned boolean indicating whether the record matches the search
criteria.

Comments This procedure is used for SmartList objects that are not optimized for SQL Server.
Most of the parameters passedto this procedure originate from the SmartList.

Examples The following example from the sample integrating application fills the Leads
SmartList object with records. The Explorer_Search_Generic procedure is called to
determine whether the current record matches the search criteria specified by the
SmartList user. This check occurs only if the object indicates that it is not optimized
for SQL.

in integer IN_Total_SubItems;
in Explorer_BOOL_List IN_Searching;
in Explorer_Resource_List IN_Dict_List;
in Explorer_Resource_List IN_Field_List;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
in Explorer_INT_List IN_Datatype;
in Explorer_INT_List IN_Type;
in Explorer_STR30_List IN_Search_From;
in Explorer_STR30_List IN_Search_To;
in Explorer_BOOL_List IN_Match_Case;
in integer IN_Global_Search_Type;
in Explorer_Field_Comparison IN_Field_Comparison;
in Explorer_Start_Comp_Field_ID IN_Start_Comp_Field_ID;
in Explorer_Start_Comp_Field_Dict IN_Start_Comp_Field_Dict;
in Explorer_End_Comp_Field_ID IN_End_Comp_Field_ID;
in Explorer_End_Comp_Field_Dict IN_End_Comp_Field_Dict;

inout long IO_Max_Records;

in boolean IN_GetSummary;
in integer IN_Summary_Type; {0 = Number of records, 1 = Total of Column}
inout integer IO_SummaryCount;
in integer IN_nSummaryFieldDictID;
in integer IN_nSummaryFieldID;
inout currency IO_ColumnTotal;

local boolean b_Stop, b_Found;


local long l_Record_Count,SQL_Context;
local integer l_Key,Error;

{This block of code will be run only if the Explorer_Optimize_For_SQL


procedure returns false}
if 'SQL Server' of globals > 0 and (IN_Searching[1] or IN_Searching[2] or
➥ IN_Searching[3] or IN_Searching[4]) then

call with name "Explorer_SQL_Search_Generic" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
IN_Searching,
IN_Field_Dict_ID,

654 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ S E A R C H _ G E N E R I C

IN_Field,
IN_Datatype,
IN_Type,
IN_Search_From,
IN_Search_To,
IN_Match_Case,
IN_Field_Comparison,
IN_Start_Comp_Field_ID,
IN_Start_Comp_Field_Dict,
IN_End_Comp_Field_ID,
IN_End_Comp_Field_Dict,
IN_Global_Search_Type,
SQL_Context,
Error,
IN_GetSummary,
IN_Summary_Type,
IO_SummaryCount,
IN_nSummaryFieldDictID,
IN_nSummaryFieldID,
IO_ColumnTotal;

{If Error returns -1, then a sequential search should be used}


if Error = OKAY then
call Explorer_Process_SQL_Data, IG_PROD_ID,
➥ SMARTLIST_OBJECTTYPE_LEADS, IN_Total_SubItems, IN_Dict_List,
➥ IN_Field_List, IO_Max_Records, SQL_Context;
abort script;
end if;
end if;

{This is the traditional SmartList code that works for all database types}

set l_Record_Count to 0;
set l_Key to 1;
call with name "Explorer_Check_Stop_Processing" in dictionary SMARTLIST,
➥ b_Stop;

{ Loop through table to get records }


get first table IG_Leads_MSTR by number l_Key;
while(err() <> EOF) and (l_Record_Count < IO_Max_Records) and (not b_Stop) do
{Set the global SmartList Master ID}
SmartList_Master_ID of globals = 'Lead ID' of table IG_Leads_MSTR;

call with name "Explorer_Search_Generic" in dictionary SMARTLIST,


IG_PROD_ID,
SMARTLIST_OBJECTTYPE_LEADS,
IN_Searching,
IN_Field_Dict_ID,
IN_Field,
IN_Datatype,
IN_Type,
IN_Search_From,
IN_Search_To,
IN_Match_Case,
IN_Global_Search_Type,
IN_Field_Comparison,

INTEGRATION GUIDE 655


S M A R T L I S T S C R I P T S E X P L O R E R _ S E A R C H _ G E N E R I C

IN_Start_Comp_Field_ID,
IN_Start_Comp_Field_Dict,
IN_End_Comp_Field_ID,
IN_End_Comp_Field_Dict,
b_Found;

if b_Found then
increment l_Record_Count;
call foreground SmartList_Leads_FillOneRowAtTime,
IN_Total_SubItems,
IN_Dict_List,
IN_Field_List,
l_Record_Count,
table IG_Leads_MSTR;
end if;

get next table IG_Leads_MSTR by number l_Key;


call with name "Explorer_Check_Stop_Processing" in dictionary SMARTLIST,
b_Stop;
end while;

656 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ S E T _ S Q L _ J O I N _ I N F O

Explorer_Set_SQL_Join_Info

Description The Explorer_Set_SQL_Join_Info procedure is used to define the relationships


between SQL tables for SQL-optimized SmartList objects. When adding additional
columns to existing SmartList objects, you will use this procedure to define how the
tables for the new columns are related to the main table used for the SmartList
object.

Syntax Explorer_Set_SQL_Join_Info, From_Table, From_Table_Dict_ID, From_Field, To_Table,


To_Table_Dict_ID, To_Field, Join_Type, Error

Parameters • From_Table – A string specifying the technical name of the primary table to join
from.

• From_Table_Dict_ID – An integer specifying the ID of the dictionary containing the


primary table to join from.

• From_Field – A string up to 80 characters long specifying the technical name of the


field from the primary table to join from.

• To_Table – A string specifying the technical name of the secondary table to join to.

• To_Table_Dict_ID – An integer specifying the ID of the dictionary containing the


secondary table to join to.

• To_Field – A string up to 80 characters long specifying the technical name of the field
in the secondary table to join to.

• Join_Type – An integer specifying the type of join being created. Use one of the
following constants:

Constant Value Comments


SMARTLIST_JOINTYPE_NONE 0 Use when no join is needed.
SMARTLIST_JOINTYPE_REGULAR 1
SMARTLIST_JOINTYPE_RIGHTOUTER 2
SMARTLIST_JOINTYPE_LEFTOUTER 3 Virtually all joins needed for SmartList
objects are this type.
SMARTLIST_JOINTYPE_CROSS 4
SMARTLIST_JOINTYPE_INNER 5
SMARTLIST_JOINTYPE_FULL 6
SMARTLIST_JOINTYPE_DISTINCT 7

• Error – A returned integer containing any database errors that occurred while
adding the join information.

Comments This procedure is typically called from the Explorer_Get_SQL_Join_Info procedure


you will add to your integrating application.

When multiple fields are needed to create the join (such as for a multi-segment key)
you will call this procedure once for each individual field in the join.

INTEGRATION GUIDE 657


S M A R T L I S T S C R I P T S E X P L O R E R _ S E T _ S Q L _ J O I N _ I N F O

Examples The following example is the Explorer_Get_SQL_Join_Info procedure for the


sample integrating application, which adds additional columns to the Customers
SmartList object. This procedure adds a join to create the relationship between the
RM_Customer_MSTR table and IG_Contact_History_MSTR table.

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;
in Explorer_INT_List IN_Field_Dict_ID;
in Explorer_INT_List IN_Field;
inout integer Document_Type;

local string l_From_Table, l_From_Field, l_To_Table, l_To_Field;


local integer l_From_Table_Dict_ID, l_To_Table_Dict_ID, l_Join_Type, l_Error;

if IN_Object_Dict_ID = DYNAMICS then


if IN_Object_Type = SMARTLIST_OBJECTTYPE_CUSTOMERS then

{Set the characteristics of the join}


l_From_Table = "RM_Customer_MSTR";
l_From_Table_Dict_ID = DYNAMICS;
l_From_Field = "Customer Number";
l_To_Table = "IG_Contact_History_MSTR";
l_To_Table_Dict_ID = IG_PROD_ID;
l_To_Field = "Customer Number";
l_Join_Type = SMARTLIST_JOINTYPE_LEFTOUTER;

{Add the join}


call with name "Explorer_Set_SQL_Join_Info" in dictionary SMARTLIST,
l_From_Table,
l_From_Table_Dict_ID,
l_From_Field,
l_To_Table,
l_To_Table_Dict_ID,
l_To_Field,
l_Join_Type,
l_Error;

{Check for a join error}


if l_Exp_Error <> 0 then
warning "SQL join error: " + str(l_Exp_Error);
end if;
end if;
end if;

658 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ S E T _ S Q L _ Q U E R Y _ F I E L D

Explorer_Set_SQL_Query_Field

Description The Explorer_Set_SQL_Query_Field procedure is used to specify which fields are


returned to SmartList when processing a SQL-optimized query. Only fields from the
primary key should be returned.

Syntax Explorer_Set_SQL_Query_Field, Sequence, Table, Dict_ID, Field, Error

Parameters • Sequence – An integer specifying the position of this field in the results set. The value
0 indicates the first position.

• Table – A string up to 80 characters long containing the technical name of the table
the key field comes from.

• Dict_ID – An integer specifying the dictionary ID of the product that defines the
table the key field comes from.

• Field – A string up to 80 characters long containing the technical name of the field to
return in the results set.

• Error – A returned integer indicating any error that occurred adding the field to the
results set.

Comments This procedure is typically called from the Explorer_Get_SQL_Query_Fields


procedure you will add to your integrating application.

When multiple fields are needed to uniquely indentify each record in the table, you
will call this procedure once for each individual field.

Examples The following example is the Explorer_Get_SQL_Query_Fields procedure from the


sample integrating application. It specifies which fields from the IG_Leads_MSTR
table used for the Leads SmartList object are required to uniquely identify each row
in the table.

in integer IN_Object_Dict_ID;
in integer IN_Object_Type;

local integer l_Exp_Error, l_Dict, l_Sequence;


local string l_Table, l_Field;

if IN_Object_Dict_ID = IG_PROD_ID then


case IN_Object_Type
in [SMARTLIST_OBJECTTYPE_LEADS]
l_Table = "IG_Leads_MSTR";
l_Dict = IG_PROD_ID;
l_Field = "Lead ID";
call with name "Explorer_Set_SQL_Query_Field" in dictionary
➥ SMARTLIST,
l_Sequence,
l_Table,
l_Dict,
l_Field,
l_Exp_Error;
end case;
end if;

INTEGRATION GUIDE 659


S M A R T L I S T S C R I P T S E X P L O R E R _ S Q L _ S E A R C H _ G E N E R I C

Explorer_SQL_Search_Generic

Description The Explorer_SQL_Search_Generic procedure is used to create a SQL results set


that contains the key values for the records matching the specified search criteria.
This procedure can be used if SmartList is running with SQL Server but you have
chosen not to use the SmartList’s built-in SQL optimization.

We strongly recommend that you use SmartList’s built-in optimization when creating
SmartList objects that are designed to work with SQL Server.

Syntax Explorer_SQL_Search_Generic, Object_Dict_ID, Object_Type, Searching,


Field_Dict_ID, Field, Datatype, Type, Search_From, Search_To, Match_Case, DDL_Type,
Field_Comparison, Start_Comp_Field_ID, Start_Comp_Field_Dict_ID,
End_Comp_Field_ID, End_Comp_Field_Dict_ID, Global_Search_Type,
Search_Field_Name, Search_Field_Dict_ID, Search_Table_Name, SQL_Connection, Error,
Get_Summary, Summary_Type, Summary_Count, Summary_Field_Dict_ID,
Summary_Field_ID, Column_Total

Parameters • Object_Dict_ID – An integer specifying the dictionary that has defined the SmartList
object.

• Object_Type – An integer indicating the SmartList object in the specified dictionary


that is being used to display records. For SmartList objects defined in the core
application, use one of the constants described in SmartList objects on page 332.

• Searching – An array of four boolean values indicating whether any search criteria
are being used.

• Field_Dict_ID – An array of four integers containing the dictionary IDs of the fields
being searched.

• Field – An array of four integers containing the resource IDs of the fields being
searched.

• Datatype – An array of four integers containing the datatypes of the fields being
searched.

• Type – An array of four integers that indicate the type of searches being performed.
For instance, “contains” or “is equal to” are common search types.

• Search_From – An array of four strings that the search fields will be compared to.

• Search_To – An array of four strings that the search fields will be compared to.

• Match_Case – An array of four booleans indicating whether the search should match
case.

• DDL_Type – An array of four integers indicating whether list fields used for the
search are 0-based or 1-based. The value 0 indicates 0-based, while the value 1
indicates 1-based.

• Field_Comparison – An array of four booleans indicating that the search to be


performed is comparing the contents of two fields in the SmartList.

660 IN T E G R AT I O N G U ID E
S M A R T L I S T S C R I P T S E X P L O R E R _ S Q L _ S E A R C H _ G E N E R I C

• Start_Comp_Field_ID – An array of four integers containing the resource IDs of the


fields that will be compared.

• Start_Comp_Field_Dict_ID – An array of four integers containing the dictionary IDs


for the fields that will be compared.

• End_Comp_Field_ID – An array of four integers containing the resource IDs of the


fields that will be compared.

• End_Comp_Field_Dict_ID – An array of four integers containing the dictionary IDs


for the fields that will be compared.

• Global_Search_Type – An integer indicating the type of search: Match All or Match 1


or More.

• Search_Field_Name – An array of four strings containing the technical names of all of


the search fields.

• Search_Field_Dict_ID – An array of four integers containing the dictionary IDs for


the search fields.

• Search_Table_Name – An array of four strings containing the names of the tables for
the search fields.

• SQL_Connection – A returned long integer that is the connect to the SQL results set
containing the key values for the items returned by the search. Use functions such
as SQL_FetchNext() and SQL_GetData() to retrieve the results.

• Error – A returned integer indicating whether the search could be completed. The
value 0 indicates the search was completed. The value -1 indicates the search could
not be completed, and a manual sequential search should be performed.

• Get_Summary – A boolean specifying whether summary information for a column is


being retrieved.

• Summary_Type – An integer specifing the type of summary information to retrieve


for a column. The value 0 indicates the number of records will be retrieved, while
the value 1 indicates the total of the column will be retrieved.

• Summary_Count – A returned integer containing the number of records that match


the search.

• Summary_Field_Dict_ID – An integer indicating the dictionary ID of the field that


will be summarized.

• Summary_Field_ID – An integer indicating the resource ID of the field that will be


summarized.

• Column_Total – A returned currency containing the total of the specified column for
the records that match the search.

Examples Refer to the example for Explorer_SQL_Search_Generic.

INTEGRATION GUIDE 661


662 IN T E G R AT I O N G U ID E
SQL scripts
The following scripts are used when working with SQL Server through Microsoft
Dynamics GP:

• GrantAccess()
• SQL_GetConnection()

INTEGRATION GUIDE 663


SQ L S C R I P T S G R A N T A C C E S S ( )

GrantAccess()

Description The GrantAccess() function of the SQL Maintenance form is used to grant security
access to SQL tables and stored procedures.

Syntax GrantAccess(object_name, type, group_name, database)

Parameters • object_name – A string specifying the object to which access is being granted.
Typically, this is a table physical name.

• type – A boolean that indicates whether access is being granted to a table or to the
auto-generated stored procedures for the table. The value false indicates access is
being granted to the SQL table. The value true indicates access is being granted to
the auto-generated stored procedures for the specified table.

• group_name – A string specifying the SQL group to which access is being granted.
Typically, this will be “DYNGRP”.

• database – A string specifying the database that contains the table or auto-generated
stored procedures for which access is being granted.

Return value A boolean. The value true indicates that access was granted, while false indicates it
was not.

Comments When granting access to a new table, you will first grant access to the table, and
then to the auto-generated stored procedures for the table.

If an error occurs while granting access, an error dialog will be displayed that lists
the number of the SQL error that occurred.

Examples The following example uses the GrantAccess() function to grant access to the
IG_Leads_MSTR table and its auto-generated stored procedures. The name of the
current database is stored in the Intercompany ID global variable.

local boolean result;

{Grant access to the table}


result = GrantAccess(physicalname(table IG_Leads_MSTR), false, "DYNGRP",
➥ 'Intercompany ID' of globals) of form 'SQL Maintenance';

{Grant access to the table auto-generated procedures}


result = GrantAccess(physicalname(table IG_Leads_MSTR), true, "DYNGRP",
➥ 'Intercompany ID' of globals) of form 'SQL Maintenance';

664 IN T E G R AT I O N G U ID E
SQ L S C R I P T S S Q L _ G E T C O N N E C T I O N ()

SQL_GetConnection()

Description The SQL_GetConnection() function of the XSQLExec form retrieves a pass-through


SQL connection maintained by Microsoft Dynamics GP.

Syntax SQL_GetConnection(type, connection)

Parameters • type – Specifies how the pass-through SQL connection will be used. The value
corresponds to one of the following constants:

Constant Description
FOREGROUND Pass-through SQL will be executed
from a foreground script.
BACKGROUND Pass-through SQL will be executed
from a background script.

• connection – A returned long integer containing the pass-through SQL connection.

Return value An integer indicating whether the connection was returned. The value 0 indicates
the connection was returned. Any othe value indicates an error occurred.

Examples The following example is a portion of the metric processing script for a Home Page
metric. It uses the SQL_GetConnection() function to retrieve a pass-through SQL
connection that is used to access data for the metric.

local string sDbName;


local long SQL_connection;
local long SQL_status;
local text SQL_Statements;

{Retrieve the current company's database}


sDbName = 'Intercompany ID' of globals;

if 'SQL Server' of globals > 0 then


SQL_status = SQL_GetConnection(FOREGROUND, SQL_connection) of form
➥ XSQLExec;
if SQL_status = OKAY then
{Build SQL statement to use the appropriate database.}
SQL_Statements = "use " + sDbName;

{Execute the SQL statements.}


SQL_status = SQL_Execute(SQL_connection, SQL_Statements);
end if;

SQL_Statements = "select top 5 LeadName, PotentialRevenue from IG001 order


➥ by PotentialRevenue desc";
{Execute the SQL statements.}
SQL_status = SQL_Execute(SQL_connection, SQL_Statements);
end if;

INTEGRATION GUIDE 665


666 IN T E G R AT I O N G U ID E
Toolbar scripts
The following scripts are used when defining toolbars for an integrating
application:

• AddCommandBar()
• AddCommandToCmdBar()
• ButtonsExistForProduct()
• CmdBarIsVisible()
• ExistsForUserID()
• FindCommandInCmdList()
• ToggleCommandBar()

INTEGRATION GUIDE 667


T O O L B A R S C R I P T S A D D C O M M A N D B A R ()

AddCommandBar()

Description The AddCommandBar() function defined in the syCmdBarObj form is used to add
a toolbar to Microsoft Dynamics GP.

Syntax AddCommandBar(UserID, ParentDictID, ParentFormID, ParentCmdID, visible,


row_number, position, clone)

Parameters • UserID – A string that specifies which user’s set of toolbars the new toolbar will be
added to. Specify the empty string ("") to add the new toolbar to the default set of
toolbars.

• ParentDictID – The ID of the dictionary that contains the command list that will be
used to contain the toolbar items.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that will be used to contain the toolbar items.

• ParentCmdID – The resource ID of the command list that will contain the toolbar
items.

• visible – A boolean that indicates whether the toolbar will be displayed by default.
The value true indicates the toolbar will be displayed, while false indicates it will
not.

• row_number – An integer that specifies which row the toolbar will attempt to be
placed on. If the row doesn’t exist, a new row will be added.

• position – An integer variable that specifies the horizontal position of the toolbar on
the row. The value is measured in pixels from the left edge of the main Microsoft
Dynamics GP window. The value 0 specifies the toolbar will be added as the first
item in the row.

• clone – A boolean parameter. The value true specifies that the toolbar will be added
for all users, while the value false specifies that the toolbar will be added for only
the specified user.

Return value An integer indicating whether the toolbar was added. The value corresponds to one
of the following constants:

Constant Description
OKAY The toolbar was successfully added.
DUPLICATE The toolbar was not added because it already exists.

668 IN T E G R AT I O N G U ID E
T O O L B A R S C R I P T S A D D C O M M A N D B A R ()

Examples The following example is the IG_CreateToolbars procedure in the sample


integrating application. It uses the AddCommandBar() function to add the sample
integration’s toolbar for all users. It attempts to place the toolbar at the beginning of
the second row.

local integer status;


local integer pos;

{Add command bar only if it doesn't exist for the user}


if ExistsForUserID("",
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample)) of
➥ form syCmdBarObj = true then
abort script;
end if;

{Add the toolbar and clone for each user who has toolbars}
pos = 0; {Place at the beginning of the row}
status = AddCommandBar("",
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
true, {visibility}
2, {row number}
pos, {position}
true) of form syCmdBarObj;

INTEGRATION GUIDE 669


T O O L B A R S C R I P T S A D D C O M M A N D T O C M D B A R ( )

AddCommandToCmdBar()

Description The AddCommandToCmdBar() function is used to add a command to a toolbar to


Microsoft Dynamics GP.

Syntax AddCommandBar(ParentDictID, ParentFormID, ParentCmdID, Sequence, CmdDictID,


CmdFormID, CmdID, CloneCmd, LoadMode)

Parameters • ParentDictID – The ID of the dictionary that contains the command list that is used
for the toolbar.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that is used for the toolbar.

• ParentCmdID – The resource ID of the command list that is used for the toolbar.

• Sequence – An integer variable that can be used to specify the position of the item in
the toolbar. The value 0 specifies the command will be added to the end of the
toolbar. The actual position of the command will be returned after the command is
added.

• CmdDictID – The ID of the dictionary that contains the command you are adding.

• CmdFormID – The resource ID of the command form that contains the definition of
the command you are adding.

• CmdID – The resource ID of the command you adding.

• CloneCmd – A boolean parameter. The value true specifies that the command will be
added for all users, while the value false specifies that the command will be added
for only the current user.

• LoadMode – An integer that specifies where the command will be added. The value
corresponds to one of the following constants:

Constant Description
MENULOAD_TOTABLE The toolbar items are being added to the default toolbar
set in Microsoft Dynamics GP.
MENULOAD_TOMEMORY This value is not currently used.

Return value An integer indicating whether the command was added to the toolbar. The value
corresponds to one of the following constants:

Constant Description
OKAY The command was successfully added.
DUPLICATE The command was not added because it already exists.

670 IN T E G R AT I O N G U ID E
T O O L B A R S C R I P T S A D D C O M M A N D T O C M D B A R ()

Examples The following example is a portion of the IG_CreateToolbars procedure in the


sample integrating application. It uses the AddCommandToCmdBar() function to
add two commands to the toolbar created for the sample integration.

local integer Seq;


local integer status;

{Add default items to the toolbar}


Seq = 1;
status = AddCommandToCmdBar(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true, {available for all users}
MENULOAD_TOTABLE);

increment Seq;
status = AddCommandToCmdBar(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Inquiry of form Command_IG_Sample),
true, {available for all users}
MENULOAD_TOTABLE);

INTEGRATION GUIDE 671


T O O L B A R S C R I P T S B U T T O N S E X I S T F O R P R O D U C T ()

ButtonsExistForProduct()

Description The ButtonsExistForProduct() function defined in the syCmdBarBtnObj form is


provided by Microsoft Dynamics GP so you can easily determine whether any
toolbar buttons have been defined for an integrating product.

Syntax ButtonsExistForProduct(Product_ID)

Parameters • Product_ID– The ID of the dictionary for which toolbar buttons will be examined.

Return value A boolean. The value true indicates that toolbar buttons exist for the product, while
false indicates they do not.

Examples The following example is a portion of the IG_CreateToolbarItems procedure in the


sample integrating application. It uses the ButtonsExistForProduct() function to
verify whether the toolbar buttons have been already been added to the
syCmdBarButtons table. If they have not, the commands are added.

local integer status;


local integer Seq;

{Add default items to the toolbar if they don't already exist}


if ButtonsExistForProduct(IG_PROD_ID) of form syCmdBarBtnObj = true then
abort script;
end if;

Seq = 1;
status = AddCommandToCmdBar(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Maintenance of form Command_IG_Sample),
true, {available for all users}
MENULOAD_TOTABLE);

increment Seq;

status = AddCommandToCmdBar(IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
Seq,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command IG_Lead_Inquiry of form Command_IG_Sample),
true, {available for all users}
MENULOAD_TOTABLE);

672 IN T E G R AT I O N G U ID E
T O O L B A R S C R I P T S C M D B A R I S V I S I B L E ()

CmdBarIsVisible()

Description The CmdBarIsVisible() function defined in the syCmdBarObj form is used to find
out whether a toolbar is visible in Microsoft Dynamics GP.

Syntax CmdBarIsVisible(UserID, ParentDictID, ParentFormID, ParentCmdID)

Parameters • UserID – A string that specifies the user for whom the state of the toolbar will be
examined. Specify the empty string ("") to examine the default set of toolbars.

• ParentDictID – The ID of the dictionary that contains the command list for the
toolbar that is being examined.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list used for the toolbar that is being examined.

• ParentCmdID – The resource ID of the command list for the toolbar that is being
examined.

Return value A boolean. The value true indicates that the toolbar is displayed for the specified
user, while false indicates that it is not.

Examples The following example uses the CmdBarIsVisible() function to find out whether
the toolbar for the sample integrating application is displayed. If it is, the
corresponding menu item in the Toolbars submenu is checked.
local boolean visible;
local integer tag;

{Get the visible state of the sample toolbar}


visible = CmdBarIsVisible('User ID' of globals,
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample))
➥ of form syCmdBarObj;

{Set the menu item appropriately}


if visible = true then
{Mark the menu item}
tag = Command_GetTag(command Toolbar_IGSample of form Command_IG_Sample);
Command_SetBooleanProperty(tag, COMMAND_PROP_CHECKED, true);
end if;

INTEGRATION GUIDE 673


T O O L B A R S C R I P T S E X I S T S F O R U S E R ID ( )

ExistsForUserID()

Description The ExistsForUserID() function defined in the syCmdBarObj form is provided by


Microsoft Dynamics GP so you can easily determine whether a specific toolbar
exists for a user.

Syntax ExistsForUser(UserID, ParentDictID, ParentFormID, ParentCmdID)

Parameters • UserID – A string that specifies the user for whom the existance of the toolbar will
be examined. Specify the empty string ("") to examine the default set of toolbars.

• ParentDictID – The ID of the dictionary that contains the command list for the
toolbar that is being examined.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list used for the toolbar that is being examined.

• ParentCmdID – The resource ID of the command list for the toolbar that is being
examined.

Return value A boolean. The value true indicates that the toolbar exists for the specified user,
while false indicates it does not.

Comments This function does not indicate whether a toolbar is visible. Use the
CmdBarIsVisible() function to find out whether a toolbar is visible.

Examples The following example is the IG_CreateToolbars procedure in the sample


integrating application. It uses the ExistsForUserID() function to verify whether the
default toolbar set contains the toolbar for the sample. If it does not, the toolbar is
added to the default set and cloned for all users.

local integer Seq;


local integer status;

{Add command bar only if it doesn't exist for the user}


if ExistsForUserID("",
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form
➥ Command_IG_Sample)) of form syCmdBarObj = true then
abort script;
end if;

{Add the toolbar}


Seq = 1;
status = AddCommandBar("",
IG_PROD_ID,
resourceid(form Command_IG_Sample),
resourceid(command CL_IG_Sample_CMDBAR of form Command_IG_Sample),
true, {visible by default}
2, {row number}
Seq,
true) of form syCmdBarObj;

674 IN T E G R AT I O N G U ID E
T O O L B A R S C R I P T S F I N D C O M M A N D I N C M D L I S T ()

FindCommandInCmdList()

Description The FindCommandInCmdList() function defined in the syCmdBarBtnObj form in


Microsoft Dynamics GP is used to find the location of a command or command list
in an existing command list, such as one used for a toolbar.

Syntax FindCommandInCmdList(UserID, ParentDictID, ParentFormID, ParentCmdID,


CmdDictID, CmdFormID, CmdID)

Parameters • UserID – A string that specifies which user’s set of commands will be examined to
find the position of the command in the command list. Specify the empty string ("")
to examine the default set of commands.

Parameters • ParentDictID – The ID of the dictionary that contains the command list that is being
examined. Use the constant DYNAMICS to specify the Microsoft Dynamics GP
main dictionary.

• ParentFormID – The resource ID of the command form that contains the definition of
the command list that is being examined.

• ParentCmdID – The resource ID of the command list that is being examined.

• CmdDictID – The ID of the dictionary that contains the command whose location is
being examined.

• CmdFormID – The resource ID of the command form that contains the definition of
the command whose location is being examined.

• CmdID – The resource ID of the command whose location is being examined.

Return value An integer that specifies the location (sequence number) of the specified command.
The value 0 indicates the item was not found in the command list.

Examples The following example uses the FindCommandInCmdList() function to retrieve the
location of the GL_Transaction_Entry command that appears in the Financial
toolbar in Microsoft Dynamics GP.

local integer Seq;

Seq = FindCommandInCmdList("",
DYNAMICS,
resourceid(form Command_System),
resourceid(command CL_Financial_CMDBAR of form Command_System),
DYNAMICS,
resourceid(form Command_Financial),
resourceid(command GL_Transaction_Entry of form Command_Financial)) of
FindCommandInCmdListform syCmdBarBtnObj;

INTEGRATION GUIDE 675


T O O L B A R S C R I P T S T O G G L E C O M M A N D B A R ( )

ToggleCommandBar()

Description The ToogleCommandBar() function defined in the syCmdBarObj form is used to


change the display state of a toolbar and its corresponding menu item in Microsoft
Dynamics GP.

Syntax ToggleCommandBar(menu_item_tag, toolbar_tag)

Parameters • menu_item_tag – The integer tag value for the menu item in the Toolbars submenu
that is used to control whether the toolbar is displayed. If the toolbar is being
displayed, the menu item will be set to the checked state. Otherwise it will be set to
the unchecked state.

• toolbar_tag – The integer tag value for the command list used to define the the
toolbar. If the toolbar is visible, it will be hidden. If it is hidden, it will be made
visible.

Return value An integer indicating whether the toolbar status was changed. The constant value
OKAY indicates the toolbar status was changed.

Examples The following example is the command script for the Toolbar_IGSample command.
This command is added to the Toolbars submenu in Microsoft Dynamics GP. When
a user chooses the command, the script uses the ToggleCommandBar() function to
show or hide the toolbar for the sample integration.

local integer nMenuTag, nCmdBarTag, nStatus;

nMenuTag = Command_GetTag(command Toolbar_IGSample);


nCmdBarTag = Command_GetTag(command CL_IG_Sample_CMDBAR);

nStatus = ToggleCommandBar(nMenuTag, nCmdBarTag) of form syCmdBarObj;

676 IN T E G R AT I O N G U ID E
Unified Communications scripts
The following scripts are used when working with Unified Communications for
Microsoft Dynamics GP:

• Activate
• GatherSIP()
• Register
• Unregister

INTEGRATION GUIDE 677


U N I F I E D C O M M U N I C A T I O N S S C R I P T S A C T I V A T E

Activate

Description The Activate procedure of the Dummy_Presence_Form form is used to perform the
action the user selected in the button drop list for a presence indicator.

Syntax Activate of form Dummy_Presence_Form, form_name, window_name, index,


SIP_address, title, action, master_ID, master_type, master_address, product_ID

Parameters • form_name – A string specifying the name of the form. Typically, this parameter is
set to the empty string.

• window_name – A string specifying the name of the window. Typically, this


parameter is set to the empty string.

• index – An integer value that must be set to 0.

• SIP_address – A string specifying the SIP address for which the action is being
performed. Typically, this value is retrieved from the corresponding Label_Presence
field for the presence indicator.

• title – A string that specifies the additional text to display in the title of the
messenger window when the action is performed.

• action – An integer that specifies the action to be performed. This corresponds to the
position of the item the user chose from the button drop list.

• master_ID – A string parameter that is not used. Set this to the empty string.

• master_type – A string parameter that is not used. Set this to the empty string.

• master_address – A string parameter that is not used. Set this to the empty string.

• product_ID – An integer specifying the product ID for the product that contains the
presence fields.

Examples The following example is the change script for the PB_Presence_Button field for the
first presence instance in the Lead Inquiry window. This change script builds the
title to display in the messenger dialog, and then calls the Activate procedure to
perform the action. The constant IG_PROD_ID is used to specify the product in
which the presence indicator has been implemented.

local string convo_title;

{Build the title to use for any conversation}


convo_title = 'Lead Name' + CH_SPACE + CH_DASH + CH_SPACE + 'Lead ID';

{Perform the action that was chosen from the button drop list}
call Activate of form Dummy_Presence_Form, "", "", 0, Label_Presence[1],
➥ convo_title, PB_Presence_Button[1], "", "", "", IG_PROD_ID;

678 IN T E G R AT I O N G U ID E
U N I F I E D C O M M U N I C A T I O N S S C R I P T S G A T H E R S IP ()

GatherSIP()

Description The GatherSIP() function retrieves the SIP address (messenger address) for the
specified entity in Microsoft Dynamics GP.

Syntax GatherSIP(master_type, master_ID, address_code)

Parameters • master_type – A string that specifies the type of entity from which to retrieve the SIP
address. The following table lists the possible values:

Value Constant Description


CUS CO_INETADDRS_CUSTOMER Customer
EMP CO_INETADDRS_EMPLOYEE Employee
SLP CO_INETADDRS_SALESPERSON Salesperson
VEN CO_INETADDRS_VENDOR Vendor

• master_ID – A string that contains the ID of the entity. For instance, when retrieving
the SIP address for a salesperson, this is the Salesperson ID.

• address_code – If multiple addresses can be defined for the entity, specifies the ID of
the set of address information from which the SIP address will be retrieved. If the
entity does not support multiple addresses, use the empty string ("").

Return value A string containing the SIP address for the entity.

Examples The following example is the change script for the Label_Presence[1] field in the
Lead Maintenance window of the sample integrating application. This script
retrieves the SIP address for the salesperson currently selected in the Salesperson ID
field, and then registers the presence indicator for that field.

local string form_name;


local string window_name;

form_name = "IG_Lead_Maintenance";
window_name = "'Lead Maintenance'";

{Retrieve the SIP address for the salesperson and store it in the array
element}
Label_Presence[1] = GatherSIP(CO_INETADDRS_SALESPERSON, 'Salesperson ID',
➥ "");

{Register the presence trigger for the field}


call Register of form Dummy_Presence_Form, form_name, window_name, 1,
➥ Label_Presence[1], 'Salesperson ID', CO_INETADDRS_SALESPERSON, "",
➥ IG_PROD_ID;

INTEGRATION GUIDE 679


U N I F I E D C O M M U N I C A T I O N S S C R I P T S R E G I S T E R

Register
Description The Register procedure of the Dummy_Presence_Form form registers the presence
indicator for a field so the indicator can be updated.

Syntax Register of form Dummy_Presence_Form, form_name, window_name, index,


SIP_address, master_ID, master_type, address_code, product_ID

Parameters • form_name – A string specifying the name of the form that contains the presence
indicator field.

• window_name – A string specifying the name of the window that contains the
presence indicator field.

• index – An integer specifying the presence field instance that is being registered. The
value 1 indicates the first presence field for the window, the value 2 indicates the
second, and so on.

• SIP_address – A string specifying the SIP address for the entity. Typically, this value
is retrieved from the corresponding Label_Presence field for the presence indicator.

• master_ID – A string that contains the ID of the entity. For instance, when retrieving
the SIP address for a salesperson, this is the Salesperson ID.

• master_type – A string that specifies the type of entity. The following table lists the
possible values:

Value Constant Description


CUS CO_INETADDRS_CUSTOMER Customer
EMP CO_INETADDRS_EMPLOYEE Employee
SLP CO_INETADDRS_SALESPERSON Salesperson
VEN CO_INETADDRS_VENDOR Vendor

• address_code – If multiple addresses can be defined for the entity, specifies the ID of
the set of address information from which the SIP address will be retrieved. If the
entity does not support multiple addresses, use the empty string ("").

• product_ID – An integer specifying the product ID for the product that contains the
presence fields.

Examples The following example is the change script for the Label_Presence[1] field in the
Lead Inquiry window of the sample integrating application. This script retrieves the
SIP address for the salesperson currently selected in the Salesperson ID field, and
then registers the presence indicator for that field.

local string form_name;


local string window_name;

form_name = "IG_Lead_Inquiry";
window_name = "IG_Lead_Inquiry";

{Retrieve the SIP address for the salesperson and store it in the array
element}
Label_Presence[1] = GatherSIP(CO_INETADDRS_SALESPERSON, 'Salesperson ID',
➥ "");

680 IN T E G R AT I O N G U ID E
U N I F I E D C O M M U N I C A T I O N S S C R I P T S R E G I S T E R

{Register the presence trigger for the field}


call Register of form Dummy_Presence_Form, form_name, window_name, 1,
➥ Label_Presence[1], 'Salesperson ID', CO_INETADDRS_SALESPERSON, "",
➥ IG_PROD_ID;

INTEGRATION GUIDE 681


U N I F I E D C O M M U N I C A T I O N S S C R I P T S U N R E G I S T E R

Unregister
Description The Unregister procedure of the Dummy_Presence_Form form unregisters the
presence indicator for a field so the indicator will no longer be updated.

Syntax Unregister of form Dummy_Presence_Form, form_name, window_name, index,


SIP_address, master_ID, master_type, address_code, product_ID

Parameters • form_name – A string specifying the name of the form that contains the presence
indicator field.

• window_name – A string specifying the name of the window that contains the
presence indicator field.

• index – An integer specifying the presence field instance that is being unregistered.
The value 1 indicates the first presence field for the window, the value 2 indicates
the second, and so on.

• SIP_address – A string specifying the SIP address for the entity. Typically, this value
is retrieved from the corresponding Label_Presence field for the presence indicator.

• master_ID – A string that contains the ID of the entity. For instance, when retrieving
the SIP address for a salesperson, this is the Salesperson ID.

• master_type – A string that specifies the type of entity. The following table lists the
possible values:

Value Constant Description


CUS CO_INETADDRS_CUSTOMER Customer
EMP CO_INETADDRS_EMPLOYEE Employee
SLP CO_INETADDRS_SALESPERSON Salesperson
VEN CO_INETADDRS_VENDOR Vendor

• address_code – If multiple addresses can be defined for the entity, specifies the ID of
the set of address information from which the SIP address will be retrieved. If the
entity does not support multiple addresses, use the empty string ("").

• product_ID – An integer specifying the product ID for the product that contains the
presence fields.

Examples The following example is the change script for the PresenceChangeEventTrigger
field in the Lead Inquiry window of the sample integrating application. This script
handles two cases based on the value it is set to when the change script is run. When
its value is -1, the script unregisters all of the presence indicators for the fields in the
window. When its value is a specific presence field instance number, only that
presence indicator is unregistered.

local string form_name;


local string window_name;

form_name = "IG_Lead_Inquiry";
window_name = "IG_Lead_Inquiry";

case PresenceChangeEventTrigger
in [-1]

682 IN T E G R AT I O N G U ID E
U N I F I E D C O M M U N I C A T I O N S S C R I P T S U N R E G I S T E R

{Unregister all of the presence triggers for the window}


call Unregister of form Dummy_Presence_Form, form_name, window_name,
➥ 1, Label_Presence[1], 'Salesperson ID', CO_INETADDRS_SALESPERSON,
➥ "", IG_PROD_ID;
in [1]
{Unregister a specific presence trigger for the window}
call Unregister of form Dummy_Presence_Form, form_name, window_name,
➥ 1, Label_Presence[1], 'Salesperson ID', CO_INETADDRS_SALESPERSON,
➥ "", IG_PROD_ID;
end case;

INTEGRATION GUIDE 683


684 IN T E G R AT I O N G U ID E
APPENDIX
Appendix
This manual has the following appendix:

• Appendix A, “Naming Conventions,” describes the naming convention used


for Microsoft Dynamics GP.

686 IN T E G R AT I O N G U ID E
Appendix A: Naming Conventions
Microsoft Dynamics GP uses a standard naming convention for different resource
types. The following sections describe this convention:

• General naming guidelines


• Standard abbreviations
• Data types
• Formats
• Fields
• Tables
• Forms and windows
• Reports
• Scripts
• Native pictures
• Prompts and window text

General naming guidelines


The following conventions apply to all resource names. Additional resource-specific
conventions are included in the descriptions of each resource.

Resource names
All words in a resource name begin with an uppercase letter followed by the
remaining characters in lowercase, as in “Customer_Maintenance.” The exception
to this rule is any standard abbreviation used in a resource name, such as YTD
(year-to-date).

Using underscores
Use an underscore (_), not a space, between words in names given to composites,
formats, data types, forms, windows, native pictures, tables, table keys and
procedures.

Using spaces
Use a space between words in report names and field names, whether they’re local
fields, global fields or system variables. Since these names can be viewed by users in
the Report Writer and Modifier, using spaces between words makes them more
readable.

INTEGRATION GUIDE 687


A P PE N D I X A N A M I N G C O N V E N T I O N S

Standard abbreviations
Common accounting terms can be abbreviated. To ensure consistency, the following
standard abbreviations have been established for Microsoft Dynamics GP. Use the
technical abbreviations for resource names; use the display abbreviations for names
that will be displayed on the computer screen (in a message or in a window) or in
reports.

Term Technical abbreviation Display abbreviation


Account ACCT Acct
Balance BAL Bal
Budget BUD
Change CHG Chng
Constant CONS Cons
Detail DTL Dtl
Error ERR
Finance charge FC FC or Fin Chg
Fixed allocation account FXD (General Ledger only) Fxd (General Ledger only)
History HIST Hist
Invoice INVC Invc
Journal JRNL Jrnl
Last year LYR LYR
Maintenance MNT Maint
Month to date MTD MTD
Negative NEG
Order ORD
Period PER Period
Posting POST Post
Posting account PST (GL only)
Quarter to date QTD QTD
Reversing REV Rev
Sequence SEQ
Serial SERL Serial
Summary SUM
Transaction TRX Trx
Unit of measure U_Of_M U Of M
Variable allocation VAR (GL only) Var (GL only)
Year to date YTD YTD

688 IN T E G R AT I O N G U ID E
A PP E ND IX A N A M I N G C O N V E N T I O N S

Data types
Data type names should be as consistent and descriptive as possible to allow for
systemwide use. Keep in mind that you can use existing Microsoft Dynamics GP
data types for fields in your dictionary, rather than creating new data types.

We currently use three categories of data types: standard, object and control field.

Standard data types


See Formats on Standard data types include string, integer or currency types. Names for standard
page 689 for addi- data types begin with the control type abbreviation followed by the keyable length.
tional information Standard data type names using a format begin with the control type abbreviation
about the abbrevia- followed by the keyable length, an underscore and the second and third parts of the
tions used for the for- format name.
mat portion of a data
type’s name. Name Control type Example
INTXX Integer INT7
STRXX String STR30_LBAU
DLRXX Currency (Dollar) DLR9_LB0_UTR$

Object data types


Names for object data types, such as push buttons or list boxes, begin with the
control type abbreviation followed by a descriptive name indicating how the object
is used.

Name Control type Example


PB_Name Push Button PB_Save
DDL_Name Drop-down List DDL_Sort_By

Control field data types


Names for control field data types are always uppercase. Control fields contain key
values used to identify records, like Customer ID, Vendor ID or Item ID.

Each control field should have its own data type. In addition to the naming
conventions already described, identify the data type as a control field data type by
adding a prefix that describes the functionality of the control field.

Name Control type Example


Prefix_STR15 String Item_ID_STR15_LBAU
Prefix_STR15 String Bank_ID_STR15_LBAU

Formats
Format names consist of three parts, each separated by underscores. String formats
contain the first and second parts of the name, while currency and integer formats
may contain all three, where appropriate. If any abbreviation does not appear in the
name, the type of information it corresponds to isn’t applicable to the format:

Name Format type Example


INT Integer INT_RB3_UT%
STR String STR_LBAU
DLR Currency DLR_LB0_UTR$
CP Composite CP_Account_Number

INTEGRATION GUIDE 689


A P PE N D I X A N A M I N G C O N V E N T I O N S

The second part of the name indicates the format’s alignment, fill, decimal digits
and whether it’s numeric, alphanumeric or uppercase:

Name Definition Example


L, R Left or right alignment INT_RB3_UT%
*, B, Z Fill character – asterisk, blank or zero STR_LBAU
N, A Numeric or alphanumeric STR255_LBA
U Uppercase STR_LBAU
# Number of decimal digits INT4_2%
$ The currency symbol is to be shown DLR19_U2$
% The percent symbol is to be shown DLR4_%2

The last part of the name is used only with integer or currency control types. It
indicates whether the format is signed or unsigned, if it shows the thousands
separator or not, its relative decimal position and if it uses the currency symbol or
the percent sign:

Name Definition Example


U, S Signed or unsigned INT2_R2N0_U%
R Relative decimal position is used DLR_LB0_UTR$
% Percent symbol is to be shown INT2_R2N0_U%
T Thousands separator DLR_LB0_UTR$
# Number of decimal digits INT4_2%
$ The currency symbol is to be shown DLR19_U2$

Fields
To distinguish fields from other resources in scripts, avoid using underscores in
field names. Other resource types can be easily identified by the underscores in
their names.

Invisible fields
Invisible fields are typically used to hold a temporary value in a window. Many
invisible fields have scripts attached to them, allowing other window scripts to use
the run script statement to access the invisible field’s script. However, a more
appropriate method for accessing a script for a form is through form procedures.

Distinguish these fields in the layout window by selecting the following field
properties:

Editable False
Visible False
BackColor Yellow if the field has a script attached. Magenta if the
field has no script attached.

690 IN T E G R AT I O N G U ID E
A PP E ND IX A N A M I N G C O N V E N T I O N S

Tables
Each table has three names – a table name, display name and physical name.

Table names
Table names are comprised of a two-, three- or four-character module abbreviation,
followed by a term that describes the contents of the table, and a three- or four-
character main table type abbreviation, following this format:

• MODULE_Contents_MAIN

When appropriate, use a sub-type abbreviation before the main-type abbreviation


to further define the table. Use sub-types to distinguish tables that are included
within a table group. (The main type indicates the table group to which the tables
belong.) If it’s included, the sub-type abbreviation appears before the main type
abbreviation, in the following order:

• MODULE_Contents_SUB_MAIN

The following tables indicate the currently-accepted standard abbreviations for


table names. These abbreviations should always appear in uppercase.

Module Technical abbreviation


Advanced Financial Analysis AFA
Cash Management CM
General Ledger GL
Inventory Control IV
Invoicing IVC
Multicurrency Management MC
Payables Management PM
Payroll – Canada CPR
Payroll – USA UPR
Purchase Order Processing POP
Receivables Management RM
Sales Order Processing SOP
System Manager SY
Taxes TX

Sub-type Technical abbreviation


Address ADDR
Batch header BHDR
Detail DTL
Table Header FHDR
Header HDR
Header tax HTAX
Line item LINE
Line tax LTAX
Serial number SERL

INTEGRATION GUIDE 691


A P PE N D I X A N A M I N G C O N V E N T I O N S

Main table type Technical abbreviation


History HIST
Master MSTR
Open OPEN
Relation REL
Report Options ROPT
Setup SETP
Summary SUM
Temp TEMP
Work WORK

Display names
Each table also has a display name that may appear in windows or on reports.
Display names don’t use underscores or abbreviations.

Display name Technical name


Account Master GL_Account_MSTR
Budget Master GL_Budget_MSTR
Payables Vendor Master PM_Vendor_MSTR
Transaction Work GL_TRX_HDR_WORK
Transaction Amounts Work GL_TRX_LINE_WORK

Display names should begin with a one-word module or series identifier, such as
Receivables or Financials. If the table contains master records and is included in
System Manager, use the master record type, such as Customer or Account instead
of a module identifier.

Table groups
Display names for table groups typically end in Master, Work, Setup, History or
Open. The table group’s display name should be the same as the primary table in
the group.

Physical names
Physical names (names applied to a table by the operating system) are
alphanumeric, typically comprised of three segments, as shown in the following
table:

Segment Length
Module abbreviation 2 characters
Table type + sequence number 3 digits
Variant number 2 digits

692 IN T E G R AT I O N G U ID E
A PP E ND IX A N A M I N G C O N V E N T I O N S

The following illustration indicates each section of a typical physical name.

Module Variant
abbreviation number

Table type

GL10301
Sequence
number

Table type
The table type is a code corresponding to the type of data the table stores. Table
types and their corresponding values are shown in the following table.

Table type Table type value


Master 000 - 099
Work 100 - 199
Open 200 - 299
History 300 - 399
Setup 400 - 499
Temp 500 - 599
Relation 600 - 699
Report options 700 - 799

Sequence number
The sequence number is a way of categorizing different tables that have the same
table type (such as master or work), and are not in the same table group. For
example, the GL_Budget_MSTR table has a physical name of GL00200 (sequence
number of “2”), and GL_Account_MSTR table has a physical name of GL00100
(sequence number of “1”). Both of these store master record data, but do not belong
to the same table group.

Variant number
The variant number indicates the order the table belongs in a table group. For
example, the following chart shows tables in the Account Master table group in the
order they appear in the group. Notice that the variant number increments for each
table in the group.

Table Group Member Physical Name


GL_Account_MSTR GL00100
GL_Account_SUM_MSTR GL00101
GL_Account_Category_MSTR GL00102
GL_Allocation_Fixed_MSTR GL00103
GL_Allocation_Variable_MSTR GL00104

Key names
Names for a table key consist of the table name followed by [_Keyn] where n is the
number of the key. By including the table name, you won’t inadvertently create
duplicate key names. For example, the first two keys for the Inventory Item Master
Table are IV_Item_MSTR_Key1 and IV_Item_MSTR_Key2.

INTEGRATION GUIDE 693


A P PE N D I X A N A M I N G C O N V E N T I O N S

Forms and windows


Form and window names follow the same naming standards. Standards for
assigning window titles apply only to windows. In some instances, Microsoft
Dynamics GP displays a form’s title; however, this is actually the title of the form’s
main window.

Form and window names


Names for forms and windows begin with the two-, three-, or four-character
module or functional abbreviation. The form name should describe the overall
purpose of the windows it contains. For example, the Customer Maintenance form
in Receivables Management contains the following windows:

Form Windows
RM_Customer_Maintenance RM_Customer_Maintenance
RM_Customer_Accounts
RM_Customer_Options
RM_Credit_Limit

If abbreviations are required due to space restrictions, use only the standard
abbreviations indicated in Standard abbreviations on page 688.

Window titles
A window title is the text that appears in the title bar of a window. While using
underscores and abbreviations in the window name makes it easier to work with in
scripts, those conventions can be distracting and confusing for users if you use them
for a window title. Therefore, Microsoft Dynamics GP uses window titles that are
more familiar to users.

Window titles use spaces instead of underscores between words.

Window name Window title


RM_Customer_Accounts Customer Account Maintenance
RM_Customer_Address Customer Address Maintenance
RM_Customer_Options Customer Maintenance Options

Window titles for windows that maintain master records should begin with the
master record type, series or module that is affected by the form or window. Module
abbreviations should not be used in window titles. Typical window titles include:

• Account Maintenance
• Employee Benefit Maintenance
• Inventory Setup Reports

Window titles for windows that perform routines may begin with verbs, like
“reconcile” or “remove.” Some of these window titles include:

• Build Payroll Checks


• Remove Payables Distributions

694 IN T E G R AT I O N G U ID E
A PP E ND IX A N A M I N G C O N V E N T I O N S

The titles of parent windows should end in a word that indicates the type of action
performed.

Action Window name ending Example


Setup Setup Company Setup
Transactions Entry Receivables Entry
Inquiry Inquiry Sales Inquiry
Reports Report Payables Report
Options (from Reports Report Options Payables Report Options
window)
Cards Maintenance Account Maintenance

Lookup window names


Names assigned to a lookup window form and to the window in the form should be
identical and should end with (_Lookup). The name for the scrolling window in the
window should be identical to the window name with the suffix (_Scroll) at the end.

Level Technical name


Form Customer_Lookup
Window Customer_Lookup
Scrolling window Customer_Lookup_Scroll

Lookup window titles


Window titles for lookup windows should follow the same conventions that other
windows do. However, window titles for lookup windows should end in plural
nouns.

• Batch IDs
• Accounts
• Payment Terms

Reports
Report names do not contain abbreviations or underscores, since these names
typically appear in the Report Writer. You can use module abbreviations, if space
limitations apply. Report names must end with a noun that identifies the item as a
report, rather than a window, table or other object.

Report type Report name Example Information included


ending
Reports Report Company Settings Report Calculated information,
general financial information.
Lists List Employee Address List Master records, setup options
and lists of data in a table, but
no calculations.
Summaries Summary Tax Period Report – Total amounts for
Summary transactions, fiscal periods
and so on, but no individual
transactions.
Posting journals Journal Payables Journal Individual transactions that
have been posted.
Registers Register Receivables Distribution Distribution amounts (debit
Register and credit) to accounts, but no
individual transactions.

INTEGRATION GUIDE 695


A P PE N D I X A N A M I N G C O N V E N T I O N S

Scripts
We use script names automatically applied to field, window and form scripts using
the auto-naming feature in Dexterity.

Procedures
Procedure names are written using the following format:

[module]_[action]_[resource name]_[sequence number]

Procedure names start with the abbreviation for the module, followed by a word that
describes the action performed in the procedure, such as print, reconcile, add, delete
or create and so on. The main part of the name is the resource name of the object
that’s acted upon, such as a table, a report or another resource.

• MC_Verify_Currency_ID
• PM_Create_Vendor_Account_File
• UPR_Clear_Work_Files

If the script source is too large to fit into one script, split it into two or more sections.
Give each section the same name, but add a sequence number at the end of each script
to indicate its place in the sequence.

• RM_Open_Transactions_Logical_Table_1
• RM_Open_Transactions_Logical_Table_2
• RM_Open_Transactions_Logical_Table_3

Local variables
Local variables declared and used within a script should have the prefix (l_) (a
lowercase L), as shown in the following examples.
local string l_Customer_Number, l_Vendor_Number;
local integer l_Sequence_Number;

Native pictures
We use naming conventions for native pictures that are used with push buttons and
visual switches.

Native pictures with push buttons


Native pictures used with push buttons (for example, the lookup button) typically
use the following naming format:

[PB][_Native_Picture_Name][_Up | _Dn][TB | WA | WCA][_P | _P&T | _T]

Names for native pictures used with push buttons indicate the control type, name,
position and whether the picture contains pictures, text or both:

PB_Note_Absent_Dn_TB_P

In the example above, the first part (PB) indicates that the native picture is to be
used with a push button data type, followed by the name of the button (Note
Absent). “Up” or “Dn” indicates the button position depicted by the native picture.
The location of the picture in the window is indicated by TB (tool bar), WA (window
area) and WCA (window control area). The last part denotes that the native picture
uses only a picture (P). The name will also indicate whether the picture uses text (T)
or pictures and text (P&T).

696 IN T E G R AT I O N G U ID E
A PP E ND IX A N A M I N G C O N V E N T I O N S

Native pictures with visual switches


Native pictures used with push buttons use the following naming format:

[VS][_Native_Picture_Name][_Up | _Dn][_P | _P&T | _T]

Names for native pictures used with a visual switch indicate the control type, name,
position and location they appear in the window:

VS_Stick_Pin_Dn_WCA

In the example above, the first part (VS) indicates that the native picture is to be
used with a visual switch data type, followed by the name of the button (Stick Pin).
“Up” or “Dn” indicate the position depicted by the native picture. The location of
the picture is indicated by TB (tool bar), WA (window area) and WCA (window
control area).

Prompts and window text


Microsoft Dynamics GP uses the following conventions for text that will appear in a
window, such as prompts, static text and messages. As a general rule, text in
windows shouldn’t contain references to platform-specific objects, since the
application may be run in different operating environments.

Abbreviations
Words in windows should be spelled out whenever possible. If abbreviations are
required, follow these guidelines:

• Don’t abbreviate words with four or fewer letters. Abbreviations for words of
this length doesn’t save much space, and might confuse the user.

• Don’t use abbreviations of module names in windows if possible. If you must


abbreviate module names, refer to Standard abbreviations on page 688.

• Use standard abbreviations whenever possible. Refer to Standard abbreviations


on page 688 for a list of standard abbreviations.

• All text in windows should appear in upper- and lowercase.

• Regular text : Customer Account Maintenance


• Hyphenated words: Year-End Closing

• Batch names appear in all uppercase, such as POSTAP.

• Abbreviations in windows are usually upper- and lowercase. Exceptions are


OK and ID.

• Specific table names should be capitalized, but the word “tables” should be
lowercase. For example, use “Customer Table” to refer to a specific table or table
group, but “General Ledger tables” to refer to all the tables in the General Led-
ger module.

INTEGRATION GUIDE 697


A P PE N D I X A N A M I N G C O N V E N T I O N S

Messages
Microsoft Dynamics GP uses the following guidelines for writing alert messages:

• State the information, error or problem clearly. Avoid technical jargon, descrip-
tions or explanations, and use easily-understood language. Messages should
give users a concise summary of the situation, in an encouraging manner, so
they can easily correct the problem, if necessary, and continue.

• Make the message as specific as possible. For example, use “Another user
updated this customer record since you opened it. Re-enter the customer infor-
mation and save again” instead of messages like “Can’t save record” or
“Another user updated this table already.”

• Don’t use the word “error.” Avoid messages that imply that the user made an
error. For example, use “Not all required fields have been entered” rather than
“Required field error.”

• Write messages in full sentences. Avoid phrases and sentence fragments.

• Use “Cannot” instead of “Can not” or “Can’t”.

Punctuation
Be sure to use punctuation consistently throughout the application.

• Use closing punctuation (usually a period or question mark) at the end of warn-
ing dialog messages and alert messages. Do not use exclamation points after
messages.

• Use an ellipsis (...) after a menu item that brings up a window or dialog that
requires additional information be entered before an action (such as printing)
can take place. For example, Printer Setup... opens a window in which users can
specify the type of printer being used.

• Use apostrophes (’) only to indicate possession, as in “the table’s header


record.” Don’t use apostrophes to indicate plurals.

• Avoid comma splices (two independent sentences connected by a comma). For


example, “This record doesn’t exist, do you wish to continue?” contains two
independent phrases. Break the phrases into separate sentences. “This record
doesn’t exist. Do you want to add a new one?”

• Hyphenate words like the following examples:

• Double-Space
• Year-End
• Month-End
• Quarter-End

Note that the word after the hyphen should be capitalized.

698 IN T E G R AT I O N G U ID E
A PP E ND IX A N A M I N G C O N V E N T I O N S

Spelling
Microsoft Dynamics GP uses American English as their interface standard, so
international spelling variations may apply. In situations where more than one
spelling may be considered correct, follow these conventions:

• Use two l’s in words that may have either one or two, such as “totalling” and
“cancelled.”

• Words or phrases may be spelled differently depending upon their use:

• “Set up” is a verb, as in “Set up posting accounts first.”


• “Setup” is an adjective and a noun. “Use the Receivables Management
setup window to do so.”
• You should “back up” your data. Always make a “backup.”

Verb tenses
Use the present tense, not the past tense.

INTEGRATION GUIDE 699


700 IN T E G R AT I O N G U ID E
Glossary used to update the launch file with product
information and run scripts during the
Extracted dictionary
The dictionary created when developer
installation process. resources are extracted from the
Account index development dictionary using the Extract
A unique ID associated with account
Clear button utility.
A button that clears a record from a window
numbers. Typically, an account’s index is
used within a table, rather than the account without removing the record from the Field group
database. An area of a window in which fields are
field.
closely related to one another.
Account number Compress utility
A Dexterity utility used to remove source Focus event
A composite field that identifies General
code and unused spaces, or “blocks” from a Any event in Microsoft Dynamics GP where
Ledger accounts in Microsoft Dynamics GP.
The storage size of the account number is dictionary. Any dictionary delivered to a script can be attached, such as the pre and
customers should be compressed. post script for a window, the pre, change and
specified when the accounting system is
installed. post script for a field, or the change script for
Control field a button.
Additional menu A window field that’s also a key in a table.
This field controls the display of records in a Focus trigger
A menu to which submenus are added when
a trigger has been registered for the form. window by matching the key value that’s A trigger that responds to a focus event, such
entered to a corresponding record in a table. as a window opening. See also Trigger.
See also Form trigger.

Add-on-the-fly Database trigger Form-level note


A trigger that responds to database A user-defined comment that’s attached to a
A feature that allows a user to add a new
operations, including reads, writes, updates specific form by clicking a note button in a
master record, such as a customer, account or
item, when entering data in another window. and deletes. See also Trigger. window. See also Notes.

Alternate forms Delete button Form trigger


A push button in a window that deletes the A trigger that responds to the user selecting
A Microsoft Dynamics GP form that’s altered
directly by a Dexterity developer. Custom record, clears the form, and places the focus an item from the Extras menu for a form. See
in the first field in the window. also Trigger.
forms are transferred to an extracted
dictionary and delivered to customers. DEVELOP.DIC Forms dictionary
Access to custom forms is controlled through The sample integrating application’s The dictionary that stores forms modified by
security in the accounting system. See also dictionary. This dictionary contains source a customer using the Modifier. For developer
Forms dictionary. code and sample palette, maintenance, table applications, a separate forms dictionary
Alternate reports maintenance and trigger forms. stores developer forms that have been
A report that’s altered directly by a Dexterity modified by the customer. See also Modifier.
Developer Update utility
developer. Custom reports are transferred to A utility available in Dexterity Utilities for Function trigger
an extracted dictionary and delivered to transferring developer resources from an A trigger that responds to a function being
customers. Access to custom reports is extracted dictionary back into the run in Microsoft Dynamics GP. See also
controlled through security in the Dynamics.dic dictionary. Trigger.
accounting system. See also Reports
dictionary. Development dictionary Functional currency
The Dynamics.dic dictionary where a third- The base currency for all transactions
Auto-Chunk utility party developer completes application associated with a particular company in
A Dexterity utility used to quickly package a development. All resources added to the Microsoft Dynamics GP. A functional
chunk dictionary. development dictionary can be copied into currency is used only if the Multicurrency
Browse buttons an extracted dictionary that can be delivered Management module is installed. See also
A set of push buttons that allow users to to Microsoft Dynamics GP customers as a Originating currency and Reporting currency.
separate application.
sequentially scan records in a window. GPUtilities
Cancel button Dictionary chunk An application that performs setup and
See Chunk. maintenance tasks for Microsoft Dynamics
A button that dismisses a window without
prompting the user to save changes or GP.
Drill-down
provide more information prior to the See Zoom. Installation file
window closing.
A chunk dictionary that contains additional
Expansion window information for installing an application,
Change log reports A window that extends, or expands, the
Text files delivered with updates that list such as installation scripts and version
functionality of a window. Typically,
resources that have changes from the number information.
expansions are used when the window can’t
previous version of Microsoft Dynamics GP. be made large enough to display all the Installation script
Check links relevant fields. A sanScript procedure that runs when a
The process of verifying that all related chunk dictionary “unchunks.” Installation
Extract utility scripts are useful for completing installation
records exist for a table group. A utility available in Dexterity Utilities that
tasks, such as setting security and adding
Chunk copies developer resources from a palette items.
development dictionary to a new dictionary,
A dictionary format used for installing or
called an “extracted” dictionary.
updating an application. A chunk can also be

INTEGRATION GUIDE 701


GLOS SA RY

Launch file Procedure trigger Writer. For developer applications, a


A file used to start one or more dictionaries A trigger that responds to a procedure being separate reports dictionary stores developer
with the runtime engine. It contains run in Microsoft Dynamics GP. See also reports that have been modified by the
information about all the products operating Trigger. customer. See also Report Writer.
in a multidictionary environment.
Product Information utility Required fields
Lookup form A utility available in Dexterity Utilities that Fields in a window where valid data must
A form in that displays records in a scrolling attaches product information to a dictionary. exist for a record to be saved properly.
window. Developer applications can open a Typically, required fields are keys in a table.
Microsoft Dynamics GP lookup form and Product information
return values from the form to the current Information about a product, such as the Runtime engine
product name, the product ID, and the The executable application that interprets the
window.
names of the forms and reports dictionaries, resources in a dictionary to present a
Modified forms that’s added to a dictionary using the functional application.
Forms modified by a user. Modified forms Product Information utility. When this same
are stored in the application’s forms information is added to the launch file, the
Script logger
A tool that records all the scripts accessed
dictionary. See also Forms dictionary. runtime engine can run the Microsoft
while an application is running, as well as
Dynamics GP dictionary and the developer
Modifier dictionary in a multidictionary environment. any parameters passed to the scripts.
A forms customization tool built into the
runtime engine. The Modifier allows users to Progress control Secondary lookup control
make modifications to a form without A window that displays the progress of The control that performs a lookup operation
for a record related to a main record in a
affecting the logic and functionality of the process-intensive tasks, such as table
window, such as the salesperson record
form. A forms dictionary stores these maintenance.
modifications. related to a customer record. There are
Prompt typically one or more secondary lookup
Multidictionary A text object in a window that provides a controls in a window, and a secondary
The feature of the runtime engine that allows descriptive label for a field. lookup field typically allows users to add
multiple dictionaries to operate together as records on the fly. See also Primary lookup
though they are part of the same application. Push button control.
A button with a static text or picture label
Notes that a user can click to accomplish a task. Series Resources utility
A feature of Microsoft Dynamics GP that A utility available in Dexterity Utilities that
allows a user to attach comments to a record Rebuild updates the series resource lists with new
or to a window. See also Record-level note and A process that verifies the contents of each forms, reports and tables added to a
Form-level note. record in a table. Records that contain dictionary.
invalid data typically are removed and listed
OK button in an error log report. Shrinking
A push button used in windows where The process of removing unused portions of
information can only be viewed (such as an Record-level note a table, reducing the size of the table.
inquiry window). A user-defined comment that’s attached to a
specific record by clicking a note button next Software Development Kit (SDK)
Originating currency to the record’s control field. See also Notes. A set of tools and documentation available
A currency value entered or displayed in a for developers who want to integrate an
currency type other than the company’s base Redisplay button application with Microsoft Dynamics GP.
currency. An originating currency is used A push button that appears in lookup
only if the Multicurrency Management windows to refresh the contents of a Sort list
scrolling window. A drop-down list that specifies the sorting
module is installed. See also Functional
order of items in a scrolling window, or the
currency and Reporting currency. Referential integrity sort order of records being viewed using
Password control The relationship between two or more browse buttons. Typically, each item in the
The process by which a window is prevented records, and the capacity of an application to list corresponds to a key.
from displaying a record until the user enters maintain the logical set of information, or
a password assigned to that record. transaction, that resides in those records. Tab sequence
The order in which the focus moves from
Primary lookup control Report Writer field to field in a window when the user
The control that performs a lookup operation A report customization tool built into the presses the TAB key.
for the main record in a window, such as a runtime engine. The Report Writer allows
customer record. This usually is the first users to modify a report or create new Table group
reports. See also Reports dictionary. A logical grouping of tables that store related
lookup field in the window. See also
information, such as an invoice header
Secondary lookup control. Reporting currency record, invoice line item records, and an
Procedure A currency used for financial statements in invoice summary record. Table groups are
A script that isn’t associated with a single Microsoft Dynamics GP. A reporting created with Dexterity, and are used for
window or form but can be called from other currency is used only if the Multicurrency security and table maintenance. In earlier
scripts to perform a common function. In Management module is installed. See also versions of Dexterity, table groups were
earlier versions of Dexterity, procedures Functional currency and Originating currency. known as “logical files.”
were known as “global scripts.” Reports dictionary
The dictionary that stores reports modified
or created by a customer using the Report

702 IN T E G R AT I O N G U ID E
G L O S S A R Y

Transfer Dictionary Module


utility
A utility available in Dexterity Utilities that
transfers a Microsoft Dynamics GP form
that’s been modified by a developer to a
dictionary that’s been created using the
Extract utility.

Trigger
Functionality that allows an application to
respond to events in other dictionaries. To
create a trigger, you need to register it with
the runtime engine.

Trigger processing procedure


A procedure that runs in response to a
trigger.

Unchunking
The process by which a chunk dictionary
updates the launch file with product
information, runs installation scripts, and
converts itself into a dictionary.

Unmodified dictionary
A “clean” Dynamics.dic dictionary that
contains no developer resources or direct
customizations.

Update chunk dictionary


A chunk dictionary that’s used to deliver
application updates. The update chunk
typically includes an entire application, as
well as version number information
necessary for an application to update
properly.

Zoom
Also known as a “drill-down.” This is the
process of viewing a lower level of detail for
a given field. A zoom field is indicated by a
magnifying glass, or “zoom pointer.”

Zoom pointer
A special cursor that appears when the
pointer is over a push button field that has
the Zoom property set to True. Clicking
when the pointer is over such a field enables
users to “zoom” to the window where
records for the field can be added.

INTEGRATION GUIDE 703


704 IN T E G R AT I O N G U ID E
Index Action Pane (continued)
registering actions and groups 217
ActionStatus_LogError() function 526
Activate procedure 682
registering commands 264, 300 ActOnError procedure, for list action
A registering groups 264, 300, 583 errors 226
abbreviations Restrictions Group 577 add database triggers
for words appearing in windows 701 Restrictions predefined action 577 described 97
list of standard abbreviations 692 User-defined Group 1 577 example 97
access privileges User-defined Group 2 577 AddCategory procedure 494
determining SQL Server role 626 verifying actions 219 AddCommand procedure 495
for tables 36, 668 actions AddCommand() function 528
account indexes acting on errors 226 AddCommandBar() function 672
defined 705 action ID 211 AddCommandToCmdBar() function 674
described 38 adding to Action Pane 214, 528 AddCommandToMenu() function 596
storing in tables 38 adding to custom lists 214, 217 AddContentArea procedure 496
using 39 adding to for Microsoft Dynamics GP AddGroup() function 533
account numbers lists 230 adding records on the fly
see also account indexes adding to Microsoft Dynamics GP defined 705
defined 705 lists 214 described 132
storing in tables 38 always available actions 217 script example 132
action ID chapter 211-227 Adding to SmartList Objects, chapter
creating 211, 536 checking action access for custom 341-352
describes 211 lists 218 AddItems procedure 498
disassembling 212, 553 checking action access for Microsoft Additional menu
Action Pane Dynamics GP lists 218 defined 705
acting on action errors 226 commands for 212 described 28
adding actions 260, 296 confirming for lists 541 naming items in 81
adding command lists 533 constants for 211, 259, 296 AddMetric procedure 506
adding commands 528 default action 266, 301 AddMyReport() function 507
adding groups 260, 296 determining whether exists 556 AddNavBarButton() function 598
adding items 214 drop dialogs for actions 220 AddNew procedure 508
adding to card list 259 enabling and disabling for Action AddQuickLink procedure 509
adding to transaction list 296 Pane 265, 300 AddReport() function 535
button sizes 212 executing 220 AddSection procedure 511
button types 212 executing for custom lists 220 AddSecurityTaskOperation() function 608
checking access for actions 217 executing for Microsoft Dynamics GP AddSetupChecklistItem() function 636
command scripts 214 lists 221 AddSubSection procedure 512
commands for actions 212, 259, 296 for card lists 259 AddTaskToRole() function 611
commands for groups 212 for lists 203 alias file, described 437
constants for actions 259, 296 for Report List 323 AlreadyExistsOnMenu() function 600
Date Restrictions predefined action for transaction lists 296 alternate forms
577 images for 213 see also alternate windows
determining whether action exists indicating action complete 525 described 27
556 indicating mutli-select action is determining if being used 622
determining whether group exists complete 579 alternate reports
557 logging action status 223 alternative to
drop dialogs for actions 220 logging errors during processing 526 described 49
enabling and disabling actions 265, Message Bar usage 223 examples 50
300 multi-select actions 217 controlling access to 48
executing actions 266 overview 211 defined 705
Export To Excel predefined action 577 performing for marked rows 222 described 43
finding commands 560 predefined actions 577 determining if being used 622
images for 213 registering for Action Pane 264, 300, limitations 49
layout priority 213 582 testing in a multidictionary
logging status for actions 223 registering for lists 217 environment 47
Message Bar usage 223 registering for Microsoft Dynamics alternate windows
performing actions for marked rows GP lists 217 see also alternate forms
222 single-select actions 217 controlling access to 31
predefined actions 577 types 217 defined 705
predefined groups 577 verifying 219 delivering online help for 433
Print This List predefined action 577 ActionStatus_LogActionComplete() Alternate/Modified Forms and Reports
registering actions 264, 300, 582 function 525 window 31, 49

INTEGRATION GUIDE 709


IN DEX

always-available actions building an application (continued) card lists (continued)


described 217 checklist 449 list options 249
performing 223 using macros for 454 main table 245
Application Services, part 392-438 Business Analyzer opening 272
applications adding a parameter 584 options 249
adding product information 451 adding a value to a report parameter options drop-down list 249
building, checklist 449 558 overview 243
compressing 453 default reports for 546 predefined selections 249
developing 9 default reports for list 270 procedures
extracting 449 enabling for lists 270 CheckActionAccessForRecord
installing with Windows Installer 475 passing list selection as a parameter 265
operating in multidictionary 271 CheckFactBoxEnabled 270
environment 7 path for reports 546 CheckListAccess 244
testing installation 458-459 SQL Server Reporting Services Close 273
testing updated applications 469 reports 270 CreateListColumnsData 246
transferring alternate forms and using for lists 270 CreateListFactBoxData 270
reports 450 button size, for Action Pane buttons 212 CreateListOptionsData 249
types 7 button type, for Action Pane buttons 212 CreateListRibbonData 260
updating, checklist 461 buttons, see browse buttons, push buttons, ExecuteAction 266
Area Pages lookup buttons FillListOptionsDDL 249
adding categories to 494 ButtonsExistForProduct() function 676 FormatField 256
adding commands to 495 GeneratePreviewPaneXML 267
adding content area to 496 C GetColumnName 247
adding for Navigation pane category calculated fields, using to retrieve GetColumnTokens 258
195 third-party report data 51, 53 GetSortIndex 250
adding items from command list 498 Cancel button Initialize 272
command for 195 defined 705 LinePre 272
creating 499 described 124 LoadFactBoxParameters 271
defining content for new pages 195 guidelines 124 Refresh 252
described 175 script example 124 RegisterCommands 264
displaying 500 card lists SetRange 250
illustration 175 access 244 ranges for data 250
overview 175 actions 259 reference to main table 245
scripts used for 493 adding Action Pane 259 registering 275, 307, 585
Auto-Chunk utility adding Information Pane 267 restricting rows 250
defined 705 adding to Navigation Pane 275, 307, row selection actions 272
using to create an update chunk 585 security 244
469-470 attaching tables 245 setting Information Icon value 252
using to create chunk dictionaries card list form 243 setting list type 272
456-458 chapter 243-277 sorting 250
Auto-Chunk window 457 closing 273 sublist 585
auto-complete column definitions 246, 543 table access 245
described 166 column names 247 table reference 245
for maintenance windows 166 command to open 273 tables used for 245
confirming actions 541 template form 243, 280
B confirming multi-select action is temporary table used for 244
background processing, procedure complete 579 verifying whether open 206
triggers 106 constants for list options 249 cascading style sheets, formatting online
boolean values, formatting for lists 569 custom view 545 help 434
browse buttons custom views 275 categories, for Area Pages 494
chapter 119-121 default action 266 categories for lists 205
creating 119 default view 549 category name, retrieving for Report List
defined 705 default view options 548 report 317
described 25, 119 described 204 change log reports, defined 705
global fields used 119 executing actions 266 charts, types for metrics 424
illustration 119 filling with data 250 check links, defined 705
scripts attached 120 filter tokens for 258 CheckActionAccessForRecord procedure
BuildDictSpecifidID() function 211, 536 form used 243 for card lists 265
building a chunk dictionary 456 formatting exported data 256 for transaction lists 300
building an application ID for 275, 307, 585 CheckListAccess procedure
chapter 449-454 illustration 243 for card lists 244

710 IN T E G R AT I O N G U ID E
I N D E X

CheckListAccess procedure (continued) Command_ShowAndEnable procedure CreateDefaultViewRecord() function -


for transaction lists 280 503 view 549
chunk dictionaries commands CreateListColumnsData procedure
building an update chunk 469-470 adding to Action Pane 528 for card lists 246
defined 705 adding to Microsoft Dynamics GP for transaction lists 282
described 456 menus 180 CreateListOptionsData procedure
ending scripts 458 adding to toolbars 188 for card lists 249
starting scripts 458 chapter 171-174 for transaction lists 284
testing 458-459 command forms 171 CreateListRibbonData procedure
using the Auto-Chunk utility 456-458 defining 172 for card lists 260
version numbers 457 for Action Pane actions 212, 259, 296 for transaction lists 296
Clear button for Setup Checklist 429 CreateSecurityRole() function 612
defined 705 hiding and disabling 502 CreateSecurityTask() function 613
described 124 images 172 Creating New SmartList Objects, chapter
guidelines 124 naming 172 353-377
script example 124 overview 171 criteria, for custom list view filters 276
ClearMakredRecordsEvent procedure, for scripts used for 501 cross-dictionary triggers
lists 223 security 173, 502, 503 chapter 113-115
client-side triggers, see triggers showing and enabling 503 column() function 115
Close procedure to open card lists 273 database triggers 115
for card lists 273 to open transaction lists 306 execute() function 113
for transaction lists 305 use in Microsoft Dynamics GP 171 helper functions 114
CmdBarIsVisible() function 677 Commit() function 515 registering 113
column headers, adding to a lookup Communicator responding to 113
136-137 adding actions to 443 CSS file, described 437
column() function 115 defining an action 443 currency values, formatting for lists 570
columns responding to an action 444 current product, determining 11
adding to Information Pane line items company database, retrieving name 38 custom views
section 586 composites, used for Report List 324 example 276
adding to SmartList 341, 354, 642 Compress Dictionary window 453 filters for lists 276
default values for table columns 36 Compress utility, defined 705 for lists 275, 276
for card lists 246, 543 compressing customization of lists, security operation
for transaction lists 282, 543 dictionaries for 396
names for in card list 247 described 453 Customization Status report 77
names for in transaction list 284 procedure 453-454 Customization Status window 77
removing from SmartList 654 ConfirmAction() function 541, verifying customizations, described 7
columns for SmartList, deleting 332 Action Pane actions 220 customizing forms
Columns_AddToken() function 537 constants described 27
Columns_AutoGenTokensForEnumField( for core Microsoft Dynamics GP lists scripts 27
) function 540 215 using triggers 28
command focus triggers for product IDs 10 customizing Microsoft Dynamics GP
described 93 for Setup Checklist help file name 431 forms, described 27
example 93 content areas, for Area Pages 496 customizing reports
command forms context menus, focus triggers example 89 checklist 44-46
closing 173 control area described 43, 44
defining commands 172 push buttons 123
described 171 separators for push buttons 123 D
naming 171 control field, defined 705 data entry conventions
opening 173 controls, in windows 25 chapter 163-168
security 171 conventions, in documentation 3 field groups 166
command list count-against actions 219 prompts 164
for navigation pane 177 count-for actions 219 required fields 163
for toolbar commands 189 count-neutral actions 219 tab sequence 167
command lists Create procedure 499 data types
adding to Action Pane 533 Create() function 513 impact of changing in Microsoft
for Action Pane groups 212 CreateDefaultColumn() function 543 Dynamics GP 468
command scripts, for Action Pane actions CreateDefaultCustomViewRecord() naming conventions 693
214 function 545 database names, retrieving 38
Command_HideAndDisable procedure CreateDefaultFactBox() function 546 database security 407
502 CreateDefaultViewRecord() function - database triggers
options 548 chapter 95-101

INTEGRATION GUIDE 711


IN DEX

database triggers (continued) DEX.INI file, copying from Microsoft Explorer_Get_Datatype procedure 343,
database events 95 Dynamics GP 11 356, 380
defined 705 Dexterity, setting up for development 11 Explorer_Get_DDL_Type procedure 345,
described 74, 95 disabling, triggers 77, 80 360, 381
example 34 DisassembleDictSpecificID procedure 212, Explorer_Get_Field_As_String_From_Tab
registering 75, 95 553 le procedure 344, 357, 381
registration example 95 display name, retrieving for Report List Explorer_Get_Object_Name procedure
restricting by form 96 report 317 354, 383
using ranges 96 Display procedure 500 Explorer_Get_Records_Background
working with table buffers 96 documentation, symbols and conventions procedure 368, 383
Date Restrictions, predefined action 577 3 Explorer_Get_SQL_Field_Info procedure
date values, formatting for lists 571 drill-downs, see zooms 348, 371, 385
dates drop dialogs Explorer_Get_SQL_Join_Info procedure
calendar drop-down 164 creating 220 348, 372, 386
width in windows 164 example 220 Explorer_Get_SQL_Override_Field_Nam
debugging, lists in Microsoft Dynamics for Action Pane actions 220 e procedure 350, 373, 387
GP 209 DYNSA user, described 407 Explorer_Get_SQL_Query_Fields
default columns procedure 373, 387
for card lists 246 E Explorer_Get_Table_Name procedure 342,
for transaction lists 282 Edit Launch file window, in Microsoft 356, 388
default values, for table columns 36 Dynamics GP 30, 48 Explorer_Get_User_Defined_Prompt
DEFAULTUSER task, described 394 enabling, triggers 77 procedure 388
Delete button ending scripts, for chunk dictionaries 458 Explorer_GoTo_Button procedure 351,
defined 705 errors, acting on list action errors 226 375, 389
described 125 execute() function 113 Explorer_Optimize_For_SQL procedure
guidelines 125 ExecuteAction procedure 347, 370, 389
script example 125 for card lists 266 Explorer_Process_SQL_Data procedure
delete database triggers for transaction lists 301 369, 390
described 98 ExecuteListAction procedure, for list Explorer_Remove_Column_From_Object
example 99, 100 actions 214 procedure 654
deleted resources 466 executing, list actions 220 Explorer_Remove_GoTo_Item procedure
deleted strings 465 Exists() function - Home Page 517 655
DeleteForListView() function -- Business Exists() function - list views 554 Explorer_Remove_Object procedure 656
Analyzer Reports 552 Exists() function - security role 615 Explorer_Search_Generic procedure 657
DeleteForListView() function -- Columns Exists() function - security task 616 Explorer_Set_SQL_Join_Info procedure
551 Exists() function - security task operation 661
DeleteForListView() function -- Options 617 Explorer_Set_SQL_Query_Field
550 Exists() function - security task role 619 procedure 663
DeleteSecurityForProduct() function 614 ExistsAsAction() function 556 Explorer_SQL_Search_Generic procedure
deleting, records using focus triggers 87 ExistsAsGroup() function 557 664
Destroy procedure 516 ExistsForUserID() function 678 Export To Excel, predefined action 577
Develop.cnk, see sample integrating expansion window, defined 705 Extract utility, defined 705
application expansions Extract window 450
DEVELOP.DIC creating 143-144 extracted dictionary, defined 705
see also sample integrating described 25, 143 extracting
application illustration 143 an application 449
defined 705 Expansions and Zooms, chapter 143-145 described 449
Developer Update utility, defined 705 Explorer, see SmartList installers to create a patch 487
Developing Integrations, chapter 7-12 Explorer_Add_Column_To_Object procedure 450
development dictionary procedure 642
defined 705 Explorer_Add_GoTo_Item procedure 645 F
described 9 Explorer_Add_Object procedure 647 FactBoxParameter_Add procedure 558
running in test mode 11 Explorer_Add_SubItem_To_ListView field focus triggers
development environment, setting up 11 procedure 651 described 92
development folder, creating for an Explorer_AddItem_To_ListView example 92
integration 11 procedure 648 field groups
development process for integrating Explorer_Check_Stop_Processing defined 705
applications procedure 652 described 166
checklist 9-10 Explorer_Fill_Range_DDLs_From_Field_I fields
described 9 D procedure 346, 360, 379 adding to Information Pane header
illustration 9 section 587

712 IN T E G R AT I O N G U ID E
I N D E X

fields (continued) FormatField procedure globally unique IDs, generating 476


impact of changing in Microsoft for card lists 256 Go To items
Dynamics GP 468 for transaction lists 292 adding to SmartList 350, 374, 645
naming conventions 694 formats, naming conventions 693 deleting 332
FillListOptionsDDL procedure, for card form-level notes, defined 705 processing 351, 375
lists 249, 285 forms removing from SmartList 655
filter tokens alternate forms 27 GP Utilities, defined 705
defining 259, 295 chapter 25-31 GPIcons.dll, described 172
described 258, 294 controlling access to 31 GPS_CHAR, default value 37
for list fields 258, 294, 537, 540 creating new forms 25 GPS_DATE, default value 37
filters, for custom list views 276 modifying with the Modifier 29 GPS_INT, default value 37
find, adding to a lookup 141 naming conventions 698 GPS_MONEY, default value 37
FindCommandInCmdList() function - security IDs for 395, 608 GrantAccess() function 36, 668
Action Pane 560 viewing GreatPlains.css, described 434
FindCommandInCmdList() function - in a multidictionary environment groups
toolbars 679 26, 29 adding to Action Pane 533
FindCommandInMenu() function 601 in test mode 26, 29 determining whether exists 557
FindSetupChecklistItem() function 639 forms dictionaries for Action Pane 212, 260, 296
FinishRefreshBackground procedure, for creating 30 images for 213
transaction lists 291 defined 705 predefined groups 577
focus events location 30 registering for Action Pane 264, 300,
defined 705 updating 470 583
for focus triggers, chart 83 function triggers registering for lists 217
focus triggers chapter 109-111 GuidGen tool, described 476
chapter 83-94 defined 705 GUIDs, generating 476
defined 705 described 74, 109
deleting records registering 109 H
described 87 registration example 109 help, see online help
example 87 retrieving data for reports 50 Help button
described 74, 83 functional currency, defined 705 adding to windows 436
focus events 83 functions, using to access report data 49 script example 437
multiple third-party developer issues help file name, for Setup Checklist 431
84 G help files
pulling focus from the current GatherSIP() function 683 described 437
window 85 General Ledger, commonly used source files 437
registering 75, 83 procedures 65 help processing procedure, described 435
registration example 83 GeneratePreviewPaneXML procedure helper functions, for cross-dictionary
reject script statement 84, 85 for card lists 267 triggers 114
saving records for transaction lists 302 HHC file, described 437
described 85 Get() function 518 HHK file, described 437
example 86 GetColumnName procedure HHP file, described 437
table buffers 93 for card lists 247 Home Pages
verifying table operations 85 for transaction lists 284 adding additional roles 410
force overflow, Action Pane button GetColumnTokens procedure adding items to 412
position 213 for card lists 258 adding metrics 415, 506
foreground processing, procedure triggers for transaction lists 294 adding new roles 508
105 GetListID() function 561 adding Quick Links 414, 509
form focus triggers GetMarkedRecordCount() function 562 adding reports 415, 507
described 88 GetMarkedRecordsTableIndex() function adding sections to template 511
example 88 563 adding sub-sections to template 512
form restrictions, for database triggers 96 GetMarkedRecordsTableRef() function chapter 409-424
form triggers 564 committing changes for 515
Additional menu, naming items in 81 GetSortIndex procedure creating for new role 513
chapter 79-81 for card lists 250 described 409
defined 705 for transaction lists 288 determining whether exists for user
described 74 GetSummaryStatusMsgText procedure, 517
example 80 for list actions 225 disposing of state object 516, 519
multiple third-party developer issues GetValidSystemPassword() function 406, making metrics available 423
81 620 retrieving for user 518
registering 75, 80 GetViewID() function 565 roles 409
global variables, for SmartList 331 scripts used for 505

INTEGRATION GUIDE 713


IN DEX

Home Pages (continued) Integration Basics, part 6-22 List_SetFactBoxParameter procedure 584
setting internal index for user 520 Integration Components, part 24-69 ListObjState, composite for Report List
setting role for user 521 Intercompany ID, global variable 38 325
templates 412 Inventory, commonly used procedures 66 lists
triggers for 413 Invoicing, commonly used procedures 66 acting on action errors 226
actions 203, 211
I J Business Analyzer for 270
icon resource assembly, for Microsoft joins, for SQL tables in SmartList 348, 372, card lists 204, 243
Dynamics GP 172 661 categories 205
icons, for commands 172 checking action access 217
images K clearing marked items after refresh
for Action Pane items 213 key fields, from main dictionary tables 33 223
for Area Pages 496 constants for list IDs 215
for commands 172 L creating columns 543
industries, for grouping roles 411 launch files
customization 203
Information Icon contents 8
debugging 209
clearing state value for 566 defined 706
displaying in separate window 206,
setting for list row 252, 286 described 7
580
setting state value for 568 dictionary location IDs 8
features 203
verifying state value 567 dictionary locations 8
filtering capability 203
Information Pane editing 30, 48
filters for 203
adding column to line items section for integrating applications 8
Information Pane 229
586 illustration 8
limit to number open 206
adding content to 229 information for Windows Installer
list IDs for 215, 275, 307, 561
adding field to header section 587 480
logging status for actions 223
adding line item to line items section product names 8
marked rows table
588 layout priority, for Action Pane buttons
returning index used for 563
adding to card list 267 213
returning number of rows 562
adding to for custom lists 229 license agreement, for template installer
returning reference to 564
adding to transaction list 302 481
Message Bar usage 223
adding values to line item 589 light bulb symbol 3
navigation 205
chapter 229-241 line items
opening from code 206, 580
creating XML document for 590 adding to Information Pane 588
overview 203
described 229 adding values to for Information
part 202-308
formatting data for 256, 292 Pane 589
performing actions for marked rows
header 230 LinePre procedure
222
layout 229 for card lists 272
predefined actions 203
line items 231 for transaction lists 304
refresh event 223
procedure reference 232 linking prompts to fields 165
registering actions and groups 217
saving XML document for 593 list customization, security operation for
Report List 309
information pane, security operation for 396
report lists 205
396 List Debugging Tools, described 209
retrieving list ID 561
InfoValue column, for card lists 245, 281 list fields, filter tokens for 258, 294
retrieving number of rows marked
InfoValue_ClearState() function 566 list IDs
223
InfoValue_IsStateSet() function 567 assigning to card lists 275
retrieving restriction parameters 208
InfoValue_SetState() function 568 assigning to transaction lists 307
roles for sharing 410
Initialize procedure List Overview, chapter 203-210
scripts used for 523
for card lists 272 List_FormatBoolean() function 569
search 203
for transaction lists 304 List_FormatCurrency() function 570
security IDs for 395, 608
installation files, defined 705 List_FormatDate() function 571
security operations for 396
installation scripts List_FormatInteger() function 572
transaction lists 204, 279
common tasks 455 List_FormatPhone() function 573
types of 204
defined 705 List_FormatQuantity() function 574
verifying whether open 206
described 455 List_FormatString() function 575
view IDs, returning 565
installer, see Windows Installer List_FormatTime() function 576
views 275, 554
installer project, editing 479 List_GetIDsForCoreCommand procedure
LoadListView procedure 621
installer template 577
LoadMode, adding menus to Microsoft
chapter 477-483 List_MultiSelectActionCompleteEvent
Dynamics GP 182
overview 477 procedure 579
local variables, naming conventions 700
using 477, 478 List_Open procedure 206, 580
long integer values, formatting for lists
integer values, formatting for lists 572 List_RegisterAction() function 582
572
List_RegisterGroup() function 583

714 IN T E G R AT I O N G U ID E
I N D E X

lookup controls menus in Microsoft Dynamics GP example 104


adding to windows 131 (continued) using parameters 105
described 129 overview 175 Receivables Management, commonly
illustration 129 scripts used for 595 used procedures 68
primary lookups 130 separators 181 reports, customizing 44
secondary lookups 130 submenus 181 reviewing changes 468
lookup windows trigger for creating 181 Sales Order Processing, commonly
column headers, adding to a lookup viewing menu structure 179 used procedures 68
136-137 MenusExistForProduct() function 602 security
defined 706 Message Bar checking access 398, 622
described 133 custom text for 225 excluding resources from
find, adding to a lookup 141 setting for list actions 223 security 399
illustration 133 messages security model 393
new button 142 guidelines for writing 702 System Manager, commonly used
note button 142 product names in 168 procedures 69
open button 142 Messenger address, see SIP address system password 406
push buttons, Select button 141 metrics toolbars 187
refresh button, adding to a lookup adding to Home Pages 415, 506 window components 118
137-138 chart components 416 Microsoft Dynamics GP Protocol Handler
show/hide details button, adding to creating 417 add-in example 445
a lookup 139-140 example 422 described 444
sort list, adding to a lookup 134-136 executing 420 responding to Communicator actions
view options, adding to a lookup guidelines 421 444
134-136 making available 423 responding to Lync actions 444
lookups metric chart reference 424 Visual Studio Tools add-in 444
chapter 127-142 metric ID 416 modified forms
described 25, 127 name 418 defined 706
opening existing lookup forms overview 415 described 29
128-129 OWC metrics 416 setting access to 31
using existing lookup forms 128 security 418 modified reports, setting access to 48
Lync SSRS metrics 416 Modifier
adding actions to 443 writing metric procedure 421 defined 706
defining an action 443 Microsoft Dynamics GP forms dictionary 30
responding to an action 444 Area Pages 175 using to modify forms 29
determining version 11 mouse symbol 3
M effects of triggers 78 Multicurrency Management, commonly
macros, automating builds with 454 forms used procedures 66
Main toolbar, described 175 customizing 27 multidictionary
Making Installation Files, chapter 455-459 scripts 27 defined 706
MAP file, described 437 General Ledger, commonly used described 7
margin notes 3 procedures 65 development process
Marked To Process column, for card lists Inventory, commonly used checklist 9-10
245, 281 procedures 66 described 9
menu focus triggers Invoicing, commonly used illustration 9
described 93 procedures 66 multiple-instance support
example 93 lookup forms adding to installer 482
Menu Inquiry Utility 179 opening 128 adding to patch 488
menus, Additional menu 81 using 128 described 477
menus in Microsoft Dynamics GP menus 175 multiple-third-party developer issues
adding commands 596 Multicurrency, commonly used for focus triggers 84
adding to menus 180 procedures 66 for form triggers 81
chapter 175-185 Payables Management, commonly multi-select actions
default set 176 used procedures 67 described 217
determining command existence 600 Payroll, commonly used procedures performing 222
determining whether exist 602 67
finding commands 601 procedures N
implementation 176 calling 63 name conflicts, for resources 466
LoadMode 182 commonly used procedures naming conventions
menu creation example 182 65-69 appendix 691-703
menu creation procedure 181 ignoring parameters for command forms 171
menu structure 177 described 104 for data types 693

INTEGRATION GUIDE 715


IN DEX

naming conventions (continued) notes (continued) patches (continued)


for fields 694 window-level testing 489
for formats 693 described 147 pathnames
for forms 698 procedures used to implement setting 42
for local variables 700 149 specifying for tables 41
for native pictures 700 storing 148 Pathnames window 41
for procedures 700 Payables Management, commonly used
for prompts 701 O procedures 67
for reports 699 object triggers Payroll, commonly used procedures 67
for scripts 700 see also triggers PCP file, creating for patch 488
for tables 695 part 72-115 pending focus events 85
for windows 698 OK button phone numbers, formatting for lists 573
general guidelines 691 defined 706 pictures, for commands 172
overview 691 described 125 predefined list views 275
standard abbreviations 692 guidelines 125 presence indicator
native pictures script example 125 adding fields 440
for commands 172 online help adding support to a window 440
naming conventions 700 chapter 433-438 attaching scripts 441
navigation for Setup Checklist items 431 entities supported 439
accessing lists 205 formatting 434 illustration 439
for sample integrating application 17 GreatPlains.css 434 performing actions 682
menus 175 help issues 438 registering 684
Navigation pane command lists 177 implementing a help system 434 unregistering 686
part 170-200 sample implementation 434 primary, Action Pane button position 213
toolbars 187 Setup Guide 431 primary lookup controls
using commands 171 third-party responsibilities 433 defined 706
Navigation pane using the Microsoft Dynamics GP described 130
accessing lists 205 help model 434 Print This List, predefined action 577
adding buttons to 196, 598 writing a help processing procedure printing, reports in Report List 321
adding categories to 195 435 problems updating applications 465
adding commands to 177 open button, for lookup windows 142 procedure triggers
adding lists to 275, 307, 585 operations, see security operations chapter 103-107
commands for buttons 196 options window ID, retrieving for Report defined 706
defining content 198 List report 319 described 64, 74, 103
procedures for each section 273, 306 originating currency, defined 706 disabling issues 107
shortcuts 199 OWC metrics, creating 416 enabling issues 107
Navigation Pane Categories and Area for background procedures 106
Pages, chapter 195-198 P for foreground procedures 105
new button, for lookup windows 142 Packaging Your Application, part 448-471 ignoring parameters 104
nodes, in Setup Checklist 428 parameters, for procedure triggers 103 registering 75, 103
note button, for lookup windows 142 pass-through SQL connections registration example 103
note index for record-level notes 153 in Microsoft Dynamics GP 38, 669 using original parameters, described
Note window 148, 152 managing 38 105
notes scripts used for 667 using parameters, example 106
chapter 147-157 using to set Information Icon 252 working with parameters 103
defined 706 passwords procedures
described 26 adding password protection to Adding a find to a lookup 141
record-level records 160-162 Adding a lookup control 131
accessing 152 chapter 159-162 Adding a refresh button to a lookup
adding 154-157 defined 706 137-138
described 152 described 159 Adding a show/hide details button
note index 153 prompting for system password 406, to a lookup 139-140
procedures used to implement 620 Adding a sort by to a lookup 134-136
153 using 159 Adding a zoom field 145
retrieving 153 patch project, editing 487 Adding column headers to a lookup
storing 153 patch template 136-137
setting Information Icon for list rows overview 485 Adding product information 452-453
253 using 485, 486 Adding record-level notes 154-157
window-level patches Adding window-level notes 149-151
accessing 148 chapter 485-489 Building an update chunk dictionary
adding 149-151 overview 485 469-470

716 IN T E G R AT I O N G U ID E
I N D E X

procedures (continued) prompts (continued) record-level notes (continued)


Compressing an application naming conventions 701 retrieving 153
dictionary 453-454 prompt boxes 165 storing 153
Creating an expansion window prompt standards 165 records
143-144 protocol handler, see Microsoft Dynamics adding password protection 160-162
Creating password protection 160-162 GP Protocol Handler adding records on the fly 132
Creating prompts 165 pulling focus from the current window 85 retrieving for SmartList 364, 368
Creating required fields 163-164 punctuation, guidelines 702 redisplay button, defined 706
Extracting an application 450 push buttons referential integrity
Opening an existing lookup form Cancel button defined 706
128-129 described 124 for tables, using triggers 34
Transferring alternate forms and guidelines 124 refresh, notification for lists 223
reports 451 script example 124 refresh button, adding to a lookup 137-138
Using the Auto-Chunk utility 456-458 chapter 123-126 Refresh procedure
procedures (resource) Clear button for card lists 252
calling procedures 63 described 124 for transaction lists 291
chapter 63-69 guidelines 124 RegisterCommands procedure
commonly used procedures script example 124 for card lists 264
General Ledger 65 common 123 for transaction lists 300
Inventory 66 defined 706 registering
Invoicing 66 Delete button actions for lists 217
Multicurrency Management 66 described 125 cross-dictionary triggers 113
Payables Management 67 guidelines 125 database triggers 95
Payroll 67 script example 125 focus triggers 83
Receivables Management 68 described 26 form triggers 80
Sales Order Processing 68 display settings 123 function triggers 109
System Manager 69 for lookup windows, Select button groups for lists 217
defined 706 141 procedure triggers 103
impact of changing in Microsoft Help button triggers 75
Dynamics GP 468 described 436 RegisterListNavigationCommand()
naming conventions 700 script example 437 function 585
procedure list for Microsoft OK button reject script, use with focus triggers 84, 85
Dynamics GP 65 described 125 Release procedure 519
using object triggers 64 guidelines 125 reminders, returning SmartList summary
using the Script Logger 64 script example 125 information for 364
viewing parameters 64 position 123 report destination
process server, process IDs for Report List Save button retrieving for Report List report 318
reports 321 described 126 using with template-enabled reports
product IDs guidelines 126 58
obtaining 452 script example 126 Report Destination window 59
using constants for 10 Report List
product information Q actions, described 323
adding to an application, procedure quantity values, formatting for lists 574 adding items 311
452-453 Quick Links, adding to Home Pages 414, adding reports 535
defined 706 509 adding SmartList objects 376
described 451 chapter 309-325
for Windows Installer 480 R composites used for 324
Product Information utility, defined 706 ranges, effect of database triggers 96 custom actions 323
Product Information window 452 read database triggers example 312
product names, using in strings and described 100 illustration 309
messages 168 example 100 integrating with 310
professional version, determining if rebuilding tables, defined 706 overview 309
running 11 Receivables Management, commonly printing reports 321
progress control, defined 706 used procedures 68 report series, predefined 310
prompt boxes, described 165 record-level notes report types 310
prompts accessing 152 reports
creating 165 adding 154-157 adding 312
defined 706 defined 706 data for each 311
described 164 described 147, 152 retrieving report information 316
for required fields 163 note index 153 retrieving report information 316
linking to fields 165 procedures used to implement 153 series for SmartList objects 377

INTEGRATION GUIDE 717


IN DEX

Report List (continued) restricting database triggers 96 sample report list, described 16
triggers, to retrieve report restriction parameters, for lists 208 sample report options form, described 15
information 316 Restrictions, predefined action 577 sample reports, described 17
triggers for 310 Restrictions Group, for Action Pane 577 sample reports form, described 14
viewing reports 321 reviewing changes to new versions of sample setup form, described 14
when to add reports 311 Microsoft Dynamics GP 468 sample SmartList object, described 15
report lists ribbon, see Action Pane sample transaction list, described 16
described 205 roles sample trigger form, described 13
verifying whether open 207 see also security roles Save button
report options windows, use with adding additional roles 410 described 126
template reports 59 adding for Home Pages 508 guidelines 126
report types, for Report List 310 building Home Page for 412 script example 126
Report Writer, defined 706 displaying description for 411 saving records
Report Writer (runtime) for Home Pages 409 using focus triggers
reports dictionary 47 unique ID for 411 described 85
using to modify reports 47 using for list view sharing 410 example 86
Report Writer functions rows, marked rows for list actions 222 ScBar_AddDexForm() function 628
list of used to access report data 54 runtime engine, defined 706 ScBar_AddExternalFile() function 629
using to access report data 49 rw_ReportEnd() Report Writer function 57 ScBar_AddFolder() function 630
ReportDestOptions, composite for Report rw_ReportStart() Report Writer function ScBar_AddMacro() function 631
List 325 56 ScBar_AddUrl() function 632
reporting currency, defined 706 rw_TableHeaderCurrency() Report Writer ScBar_ItemExists() function 633
reports function 54 script logger
adding to Home Pages 415, 507 rw_TableHeaderString() Report Writer defined 706
adding to Report List 311, 535 function 54 using with procedures 64
alternate reports 43 rw_TableLineCurrency() Report Writer Script Reference, part 492-680
chapter 43-61 function 55 scripts
controlling access to 48 rw_TableLineString() Report Writer for browse buttons 120
creating alternate reports 44 function 56 for sort lists 121
in Report List 310 installation scripts 455
modifying with the runtime Report S naming conventions 700
Writer 47 ”sa” user, described 407 on Microsoft Dynamics GP forms 27
naming conventions 699 Sales Order Processing, commonly used scrolling window focus triggers
Report Writer functions procedures 68 described 90
examples 50 sample card list, described 15 example 91
retrieving third-party data 49 sample data, for sample integrating secondary, Action Pane button position
scripts used for 603 application 19 213
security IDs for 395, 608 sample inquiry form, described 14 secondary lookup controls
template-enabled reports 57 sample integrating application defined 706
testing in a multidictionary accessing 18 described 130
environment 47 chapter 13-22 sections, adding to Home Pages 511
Word templates for 57 contents 13 security
reports dictionaries installing 18 adding for integrating applications
creating 47 navigation 17 394
defined 706 overview 13 checking security access 398, 622
location 47 sample card list 15 deleting for integrating applications
updating 470 sample data 19 400
Reports lookup, making template-enabled sample inquiry form 14 determining SQL Server user role 626
reports visible 57 sample maintenance form 13 “DYNSA” user 407
required fields sample report list 16 excluding resources from security 399
creating 163-164 sample report options form 15 for command forms 171
defined 706 sample reports 17 for commands 173
described 163 sample reports form 14 for metrics 418
displaying 163 sample setup form 14 for SmartList objects 354
reregistering triggers 76 sample SmartList object 15 Microsoft Dynamics GP security
resource ID, retrieving for Report List sample transaction list 16 model 393
report 316 sample trigger form 13 reports for 394
resource name guidelines 691 source code 21 “sa” user 407
resources using 13 scripts used for 607
deleted 466 Word templates for 19 SQL Server 407
name conflicts 466 sample maintenance form, described 13 system password 406

718 IN T E G R AT I O N G U ID E
I N D E X

security (continued) setting report access 48 SmartList (continued)


using to set form access 31 Setup Checklist columns
using to set report access 48 adding items 429, 636 removing columns 654
verifying security data 394 chapter 427-432 retrieving datatypes 343, 356
security IDs commands 429 retrieving list field type 345, 360
described 395, 608 finding items 639 retrieving list field values 346,
for forms 395, 608 first-level nodes 428 360
for lists 395, 608 help file name 431 retrieving values 344, 357
for reports 395, 608 help for items 431 creating a new object 353, 647
for tables 395, 608 help topic 431 described 329
security in Microsoft Dynamics GP, help topic guidelines 432 global procedures for 331
chapter 393-407 item types 428 global variables for 331
security operations, adding to tasks 396, overview 427 Go To items
608 scripts used for 635 adding 350, 374, 645
security resource types structure 428 deleting 332
adding series 401 top-level node 428 processing 351, 375
creating 400 tree 428 removing 655
displaying items in the type 402 Setup Guide integration technique 331
retrieving information for reports 404 for Setup Checklist 431 integration types 330
security roles topic guidelines 432 joins for SQL tables 348, 372, 661
adding tasks to 398, 611 setup windows, Setup Checklist 427 object name 354
creating 398, 612 Setup.msi, version information 481 objects
described 397 SetUserRole procedure 521 list of 332
elements of 397 Shared Source Licensing Program, for tables used for 332
verifying exists 615 WiX 476 operation 329
security task operations shortcuts overriding field names 350, 373
deleting 614 adding 199 overview 329
described 395 adding external files 629 part 328-390
elements of 395 adding forms 628 parts of 329
verifying exists 617 adding macros 631 procedures used with 379
security task role, verifying exists 619 adding URLs 632 reminders for favorites 364
Security Task Setup window 31, 48 chapter 199-200 removing an object 656
security tasks controlling how added 200 Report List integration 376
adding operations to 396, 608 creating folders 630 retrieving column datatypes 343, 356
adding to roles 398, 611 determining if item exists 633 retrieving column values 344, 357
creating 395, 613 example 199 retrieving list field type 345, 360
DEFAULTUSER task 394 form used 199 retrieving list field values 346, 360
described 394 on Navigation pane 199 retrieving object series 321
elements of 394 restricting 200 retrieving records for 364, 368
verifying exists 616 scripts used for 627 retrieving SQL field information 348,
Security() function 622 show/hide details button, adding to a 371
Select button, for lookup windows 141 lookup 139-140 retrieving SQL join information 348,
Select Home Page window 410 shrinking and rebuilding tables, defined 372
Send To Excel, formatting data exported 706 retrieving SQL query fields 373
from list 256, 292 single-select actions retrieving summary information for
separators described 217 364
between control area push buttons performing 222 retrieving table name 342, 356
123 SIP address scripts used for 641
in Microsoft Dynamics GP menus 181 described 439 searching procedures 657
in Microsoft Dynamics GP toolbars retrieving for an entity 683 searching procedures for SQL 664
189 SmartList security for 354
series adding a single row 362 security IDs for 395, 608
for Report List, predefined 310 adding items to list view field 362, SQL optimization 347, 370
for security resource type 401 648 SQL-optimized object query fields
for tables 41 adding new objects 353 373, 663
Series Resource utility, defined 706 adding subitems to list view field 651 stopping processing 652
SetIndex procedure 520, 623 adding to existing lists 341 testing 332
SetRange procedure columns triggers
for card lists 250 adding columns 341, 354, 642 to add columns 341
for transaction lists 289 deleting 332 to add Go To items 350
setting form access 31 overriding field names 350, 373 to create new objects 353

INTEGRATION GUIDE 719


IN DEX

SmartList (continued) sublist templates (continued)


triggers for card lists 585 importing with code 61, 604
to set SmartList Report List series for transaction lists 585 installing Word templates for sample
377 submenus, in Microsoft Dynamics GP 181 integration 19
triggers for 331 sub-sections, adding to Home Pages 512 removing with code 61, 606
user-defined prompts for columns summary, returning from a SmartList 364 retrieving for a report 58
388 SY_Notes_MSTR table 148 use with report options windows 59
SmartList Procedure Reference, chapter SY_Record_Notes_MSTR table 153 temporary tables
379-390 syImportReportTemplate() function 604 for card lists 244
Software Development Kit, defined 706 symbols in documentation 3 for transaction lists 281
sort lists syMenuMstr table, described 176 loading for card lists 252
adding to a lookup 134-136 syRemoveReportTemplate() function 606 test mode
creating 121 syReportData, composite for Report List determining if running in 11
defined 706 324 using to view windows 26
described 121 syReportList form 310 using with an integration 11
illustration 119 system database, retrieving name 38 testing
script attached 121 System Manager, commonly used forms
source code control procedures 69 in a multidictionary environment
benefits 12 system password, prompting for 406, 620 26, 29
upgrading applications 461 syUserInRole() function 626 in test mode 26, 29
use with integrating applications 12 installation process 458-459
source code for the sample integrating T reports 47
application 21 tab sequence triggers 78
spaces in names 691 defined 706 update chunks 470
spelling, guidelines 703 described 167 updated applications 469
SQL optimization guidelines 167 time values, formatting for lists 576
for SmartList 347, 370 table buffers ToggleCommandBar() function 680
retrieving SQL query fields 373 effect of database triggers 96 tokens
setting SQL query fields 663 for focus triggers 93 in messages 168
SQL Server table groups in static text 168
access privileges 407 assigning tables 41 see filter tokens
database names, retrieving 38 creating 41 Toolbars context menu
determining user roles 626 defined 706 adding toolbars to 192
“sa” user 407 use with pathnames 41 described 191
scripts used for 667 table operations, verifying with focus toolbars in Microsoft Dynamics GP
working with directly 38 triggers 85 adding commands 674
SQL Server Reporting Services tables adding to Microsoft Dynamics GP
adding a value to a report parameter assigning default values to columns toolbars 188
558 36 adding toolbars 672
passing a parameter to a report 584 assigning to table groups 41 changing display state 680
reports as home page metrics 416 chapter 33-42 chapter 187-193
using for Business Analyzer 270 converting data 469 command list 189
SQL_GetConnection() function 669 creating 33, 35 default set 187
SSRS metrics granting access privileges 36, 668 determining whether exist 678
creating 416 naming conventions 695 determining whether toolbar buttons
location on Report Server 416 pathnames 41 exist 676
stand-alone applications, triggers 76 privileges to create 35 finding commands 679
standard version, determining if running security IDs for 395, 608 finding if visible 677
11 specifying locations of, procedure 42 implementation 187
starting scripts, for chunk dictionaries 458 storing account indexes 38 overview 187
Startup procedure, used to register storing account numbers 38 predefined toolbars 188
triggers 75 using key fields 33 scripts used for 671
Startup_Main procedure, used to register using object triggers 34 separators 189
triggers 75 tags, for triggers 75 toggling 192, 680
static text, product names in 168 tasks, see security tasks toolbar creation procedure 189
status, of triggers 77 template form, for card lists 243, 280 toolbar menu item 191
string values, formatting for lists 575 template installer, features of 477 toolbar menu state 192
strings template-enabled reports 57 Toolbars context menu 191
collisions during update 465 templates trigger for creating 190
deleted 465 adding for Home Page role 508 top-level node, Setup Checklist 428
style sheets, formatting online help 434 for reports 57

720 IN T E G R AT I O N G U ID E
I N D E X

transaction lists transaction lists (continued) triggers (continued)


access 280 restricting rows 289 database triggers
actions 296 row selection actions 304 registering 75, 95
adding Action Pane 296 security 280 defined 707
adding Information Pane 302 setting Information Icon value 286 delete database triggers 98
adding to Navigation Pane 585 setting list type 304 described 73
attaching tables 281 sorting 288 disabling 77, 80
chapter 279-308 sublist 585 effects on Microsoft Dynamics GP 78
closing 305 table access 281 enabling 77, 80
column definitions 282, 543 table reference 281 field focus triggers 92
column names 284 tables used for 281 focus triggers
command to open 306 temporary table used for 281 described 74, 83
confirming actions 541 transaction list form 280 registering 75, 83
confirming multi-select action is verifying whether open 207 for retrieving third-party report data
complete 579 Transfer Dictionary Module utility, 50, 52
constants for list options 285 defined 707 for stand-alone applications 76
custom view 545 Transfer Dictionary Module window 451 form focus triggers 88
custom views 308 transferring form triggers
default action 301 alternate forms and reports described 74
default view 549 described 450 disabling 80
default view options 548 procedure 451 registering 75, 80
described 204 resources, to a new dictionary 461 function triggers
executing actions 301 trigger processing procedure described 74, 109
filling with data 288 defined 707 registering 109
filter tokens for 294 described 76 menu focus triggers 93
form used 280 example 76 multiple-third-party developer issues
formatting exported data 292 trigger registration procedure 81, 84
ID for 585 described 75 part 72-115
illustration 279 example 76 procedure triggers
list options 284 TRIGGER_GetOptionsWindowIDs, background procedures 106
loading temporary table 285 Report List trigger 319 described 74, 103
main table 281 TRIGGER_GetProcessIDs, Report List foreground procedures 105
opening 304 trigger 321 parameters for 103
options 284 TRIGGER_GetReportCategoryName, registering 75, 103
options drop-down list 285 Report List trigger 317 read database triggers 100
overview 279 TRIGGER_GetReportDestination, Report registering 75
predefined selections 285 List trigger 318 reregistering 76
procedures TRIGGER_GetReportDisplayName, scrolling window focus triggers 90
CheckActionAccessForRecord Report List trigger 317 Startup procedure 75
300 TRIGGER_GetReportResid, Report List Startup_Main procedure 75
CheckListAccess 280 trigger 316 tags 75
Close 305 TRIGGER_GetSmartListObjectSeries, trigger processing procedure 76
CreateListColumnsData 282 Report List trigger 321 trigger registration procedure 75
CreateListOptionsData 284 Trigger_RegisterDatabase() function 95 types of 74
CreateListRibbonData 296 Trigger_RegisterFocus() function 83 unregistering 76
ExecuteAction 301 Trigger_RegisterForm() function 80 update database triggers 98
FillListOptionsDDL 285 Trigger_RegisterFunction() function 109 updating third-party tables 34
FinishRefreshBackground 291 Trigger_RegisterProcedure() function 103 viewing status 77
FormatField 292 triggers window focus triggers 89
GeneratePreviewPaneXML 302 add database triggers 97 troubleshooting
GetColumnName 284 based on Microsoft Dynamics GP lists in Microsoft Dynamics GP 209
GetColumnTokens 294 procedures 64 updating applications 465
GetSortIndex 288 benefits 73
Initialize 304 command focus triggers 93 U
LinePre 304 creating 75 unchunking, defined 707
Refresh 291 cross-dictionary triggers 113 underscores in names 691
RegisterCommands 300 Customization Status report 77 Unified Communications
SetRange 289 Customization Status window 77 actions for Communicator 443
ranges for data 289 customizing forms 28 actions for Lync 443
reference to main table 281 database triggers chapter 439-446
registering 585 described 74, 95 described 439

INTEGRATION GUIDE 721


IN DEX

Unified Communications (continued) window-level notes (continued) working folder


performing presence actions 682 adding 149-151 for install project 478
presence indicator 439 described 147 for patch project 486
registering presence indicators 684 procedures used to implement 149
retrieving SIP address for an entity storing 148 X
683 windows XMLDoc_AddColumn procedure 586
scripts used for 681 components 118 XMLDoc_AddHeaderField procedure 587
unregistering presence indicators 686 field groups 166 XMLDoc_AddLineItem procedure 588
unmodified dictionary, defined 707 naming conventions 698 XMLDoc_AddLineItemValue procedure
unregistering, triggers 76 push buttons to include 123 589
update chunks, defined 707 standard controls 25 XMLDoc_Create procedure 590
update database triggers standards for prompts 165 XMLDoc_Save procedure 593
described 98 tab sequence 167
example 98 Windows help, see online help Z
updating windows in Dexterity Utilities zoom pointer, defined 707
forms dictionaries 470 Auto-Chunk 457 zooms
reports dictionaries 470 Compress Dictionary 453 creating 145
updating an application Extract 450 defined 707
alternate forms and reports 469 Product Information 452 described 26, 144
chapter 461-471 Transfer Dictionary Module 451 guidelines 145
checklist 461 windows in Microsoft Dynamics GP illustration 143, 144
deleted resources 466 Alternate/Modified Forms and
deleted strings 465 Reports 31, 49
resource name conflicts 466 Edit Launch File 30, 48
reviewing Microsoft Dynamics GP Note 148, 152
changes 468 Pathnames 41
string collisions 465 Report Destination 59
transferring third-party resources 461 Reports lookup 57
updating applications, common problems Security Task Setup 31, 48, 400
465 Select Home Page 410
User Password Setup window 159 User Password Setup 159
user roles, for SQL Server 626 Windows Installer
user-defined functions, using to access benefits 475
report data 49 components in install 479
User-defined Group 1, for Action Pane 577 creating a patch 486
User-defined Group 2, for Action Pane 577 creating an installer 478
Using Triggers, chapter 73-78 generating GUIDs for 476
installer template for WiX 477
V localizing 480
verb tenses, guidelines 703 multiple-instance support 477
verifying Action Pane actions 219 overview 475
version numbers, for chunk dictionaries part 474-489
457 patch template for WiX 485
vertical enhancements, described 7 patches 485
view options, adding to a lookup 134-136 resources for 475
viewing, reports in Report List 321 testing 482
views WiX to create installs 476
see also custom views Windows Installer SDK 475
for lists Windows Installer Services, described 475
determining whether exists 554 Windows Installer XML, see WiX
retrieving view ID 565 WiX
creating installer using template 478
W creating patch using template 486
warning symbol 3 described 476
Window Components, part 118-168 generating GUIDs for 476
window focus triggers installer template 477
context menu example 89 obtaining 476
described 89 patch template 485
example 89 using to create installers 476
window-level notes Word templates, see templates
accessing 148

722 IN T E G R AT I O N G U ID E

You might also like