MICROSOFT DYNAMICS® AX 2009COURSE 80014 DEVELOPMENT IV Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Last Revision: November 2008 The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication. This document is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. © 2008 Microsoft Corporation. All rights reserved. Microsoft Dynamics®, Microsoft® PowerPoint® Microsoft® SQL Server® and Microsoft Dynamics® AX MorphX® are trademarks or registered trademarks of Microsoft Corporation. The names of actual companies and products mentioned herein may be the trademarks of their respective owners. This course content is designed for Microsoft Dynamics® AX 2009. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Table of Contents Introduction to Development IV in Microsoft Dynamics AX 2009 0-1 Welcome ............................................................................................................ 0-1 Microsoft Dynamics Courseware Contents ........................................................ 0-2 Documentation Conventions .............................................................................. 0-3 Student Objectives ............................................................................................. 0-4 Chapter 1: Point-of-Sale Project 1-1 Objectives ........................................................................................................... 1-1 Introduction ......................................................................................................... 1-1 Overview ............................................................................................................ 1-2 Functional Design ............................................................................................... 1-3 Technical Design ................................................................................................ 1-4 Summary ............................................................................................................ 1-7 Quick Interaction: Lessons Learned ................................................................... 1-8 Chapter 2: Number Sequences 2-1 Objectives ........................................................................................................... 2-1 Introduction ......................................................................................................... 2-1 Overview ............................................................................................................ 2-2 Assign a New Number ........................................................................................ 2-4 Continuous Number Sequences......................................................................... 2-5 Format a Number ............................................................................................... 2-5 Number Pre-Allocation ....................................................................................... 2-6 Clean Up Process .............................................................................................. 2-6 Form Handler ..................................................................................................... 2-7 NumberSeqReference ........................................................................................ 2-7 Summary ............................................................................................................ 2-8 Test Your Knowledge ......................................................................................... 2-9 Lab 2.1 - Add Pay Id number sequence ........................................................... 2-10 Lab 2.2 - Use Form Handler ............................................................................. 2-12 Quick Interaction: Lessons Learned ................................................................. 2-13 Solutions ........................................................................................................... 2-14 Chapter 3: PrintJobSettings 3-1 Objectives ........................................................................................................... 3-1 Introduction ......................................................................................................... 3-1 Set Print Options ................................................................................................ 3-2 Retrieve Print Options ........................................................................................ 3-4 Use of Pack and Unpack to Store Settings ........................................................ 3-4 Use of SysPrintOptions ...................................................................................... 3-5 Summary ............................................................................................................ 3-6 Test Your Knowledge ......................................................................................... 3-7 Lab 3.1 - Suppress Scaling Message ................................................................. 3-8 Lab 3.2 - Print Job Settings ................................................................................ 3-9 Lab 3.3: Print the receipt to the correct printer ................................................. 3-10 Lab 3.4 - Bypass Print Options ......................................................................... 3-11 Quick Interaction: Lessons Learned ................................................................. 3-12 Solutions ........................................................................................................... 3-13 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement i Development IV in Microsoft Dynamics® AX2009 Chapter 4: Business Connector 4-1 Objectives ........................................................................................................... 4-1 Introduction ......................................................................................................... 4-1 Business Connector Overview ........................................................................... 4-2 Business Connector Setup and Configuration.................................................... 4-3 Business Connector Architecture ....................................................................... 4-7 Summary .......................................................................................................... 4-12 Test Your Knowledge ....................................................................................... 4-13 Lab 4.1 - Business Connector .......................................................................... 4-15 Lab 4.1 - Business Connector (Solution) .......................................................... 4-19 Quick Interaction: Lessons Learned ................................................................. 4-21 Chapter 5: CLR Interoperability 5-1 Objectives ........................................................................................................... 5-1 Introduction ......................................................................................................... 5-1 Reference CLR Assemblies in the AOT ............................................................. 5-2 Adding Assemblies to the Global Assembly Cache or Client ............................. 5-3 Leverage CLR Managed Code Within X++ Code............................................... 5-4 InteropPermission Class .................................................................................... 5-6 Web service references ...................................................................................... 5-6 Implementing a DLL ......................................................................................... 5-12 Summary .......................................................................................................... 5-15 Test Your Knowledge ....................................................................................... 5-16 Lab 5.1 - CLR Interop ....................................................................................... 5-18 Lab 5.1 - CLR Interop (Solution)....................................................................... 5-19 Lab 5.2 - Implementing DLL's........................................................................... 5-21 Lab 5.2 - Implementing DLL's (Solution) .......................................................... 5-22 Quick Interaction: Lessons Learned ................................................................. 5-23 Solutions ........................................................................................................... 5-24 Chapter 6: Ledger 6-1 Objectives ........................................................................................................... 6-1 Introduction ......................................................................................................... 6-1 Scenario ............................................................................................................. 6-2 LedgerVoucher ................................................................................................... 6-2 LedgerJournal .................................................................................................. 6-10 Summary .......................................................................................................... 6-13 Test Your Knowledge ....................................................................................... 6-14 Lab 6.1 – Create and Post a Ledger Journal.................................................... 6-16 Lab 6.2 – POS - End-of-day routine ................................................................. 6-18 Quick Interaction: Lessons Learned ................................................................. 6-20 Solutions ........................................................................................................... 6-21 Chapter 7: Trade 7-1 Objectives ........................................................................................................... 7-1 Introduction ......................................................................................................... 7-1 TableType and LineType .................................................................................... 7-2 Post and Print Document Updates ..................................................................... 7-5 Posting Transactions ........................................................................................ 7-11 ii Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement ............ 8-25 Lab 8.......................................................................................... 7-13 Trade Agreement ...................................................1 ........................................................................................................ 8-29 Quick Interaction: Lessons Learned ..................... 8-2 Inventory Dimensions ............................................................. 9-4 ProdUpd .......................................................................................................................................................................................................... 9-1 Introduction ..............Payment Posting and Invoice Update (Solution) ..........2 ........................................................................ 8-31 Chapter 9: Production 9-1 Objectives ......................................................................................... 7-16 Test Your Knowledge .... 8-1 Scenario ......................................................................................... 9-20 Solutions ............................................................... 9-19 Quick Interaction: Lessons Learned .......................... 8-1 Introduction .... 7-17 Lab 7................... 9-8 Summary ............ 9-17 Lab 9.................................................................................1 – On-hand Inventory on Sales Order Form .................... 10-1 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement iii ......... 9-1 ProdMulti .................................................................................... 9-16 Lab 9.......... 8-17 InventMovement ...............................................3 – POS ..Production (Solution) .............................................................................................................................4 – POS ...............................................................................................Settlement ...........................................................................................................................................Table of Contents Settlement ............................................................3 .................................................................................... 7-20 Lab 7............................................................................................................ 7-25 Solutions ................... 7-26 Chapter 8: Inventory 8-1 Objectives ............................................ 8-10 Lab 8.................................. 9-6 Scheduling .................................................................................................................................................... 9-15 Lab 9.................................................. 9-18 Lab 9.................. 8-24 Test Your Knowledge ..............................................Production ..... 8-2 Inventory Journals .................................................................................. 7-24 Quick Interaction: Lessons Learned ............Display on hand inventory .................................................................. 7-19 Lab 7......................................................................................... 8-27 Lab 8.............................................................................................................. 9-21 Chapter 10: Project Accounting 10-1 Objectives ........................................................................................................................................................................ 7-21 ab 7.................................................................................................................................... 8-20 Summary ............................................................................. 8-28 Lab 8..... 7-22 Lab 7.............. 8-30 Solutions ...................................Production (Solution) ............. 9-14 Test Your Knowledge ...................................................................................................Production ...... 8-18 InventUpdate .................................................................... 10-1 Introduction ........................................................................................ 7-14 Summary .... 7-23 Lab 7.................................................Trade (Solution) ...............1 ..................2 ..........................................................................................2 – Create an ABC allocation ......................... 8-4 InventSum ............................................................................................................Display inventory dimensions ...................1 ..............................................................Trade .....................................2 ...................2 ...............................................................................................................................................1 .........................................................3 (Solution) .................... 9-2 ProdStatusType .............Payment Posting and Invoice Update .................. .........................................1 .....................Enable Resubmit ................ 11-2 Workflow Installation ........................................................................................................................ 11-19 Code Walkthrough: Submitting a workflow .................................................................................................................................................................................................................. 11-2 Create a Workflow Category ......................................................................... 11-22 Lab 11.................................................. 10-10 Test Your Knowledge ..................2 ..........................................Place Invoice Proposal On Hold............. 10-12 Lab 10............. 11-27 Quick Interaction: Lessons Learned .................................... 11-5 Enable Workflow on a Form ....... 11-4 Create a Workflow Approval ............. 11-2 Create a Workflow Template ......................................................... 10-4 Invoice Proposal ...................................................................................Development IV in Microsoft Dynamics® AX2009 Scenario ............................................................. 11-1 Introduction ....................................Add Another Condition to the Submit Action ...................................................................................... 11-26 Test Your Knowledge ................................................................................................................................................................................................................................................................. 10-8 Summary ....................... 11-8 Create Event Handlers ................................................................................... 11-20 Code Walkthrough: Workflow Processor .................................................... 10-2 Design ......................................................2 ............................................................................................................................ 10-11 Lab 10............................... 10-13 Quick Interaction: Lessons Learned ............................................................................. 11-1 Scenario ....................................................................................................................................................................... 11-17 Lab 11......... 11-28 Solutions ........... 10-5 Invoice ...............................................................................................1 ..................................................................Warranty Item .................................................... 11-12 Configure a Workflow ................................................................................... 10-14 Solutions ................................................................................ 11-3 Create a Workflow Document ....................................................... 11-29 iv Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement ............................ 11-24 Summary ...................................................................................................... 10-15 Chapter 11: Workflow 11-1 Objectives ............................................................................... 10-2 Posting Transactions ......... com/Dynamics. in-depth learning through hands-on interaction. in-depth training to you in the comfort of your own home or office. Classroom Training. Online Training Online Training delivers convenient. interactions and quizzes. Online training provides immediate access to training 24 hours-a-day. From demonstrations to presentations to classroom activities.microsoft. eCourses. Choose the training type that best suits you so you can stay ahead of the competition. Whether you choose Online Training. exercises. Regularly scheduled throughout North America. Our quality training from industry experts keeps you up-to-date on your solution and helps you develop the skills necessary for fully maximizing the value of your solution. designed from a training perspective. Classroom Training Classroom Training provides serious. with at least two weeks to complete each course. and insights you can refer to again and again: Microsoft Dynamics Courseware The Microsoft Dynamics Courseware consists of detailed training manuals. It is perfect for the customer who does not have the time or budget to travel. Our newest online training option. Our wide variety of training manuals feature an abundance of tips. on your own time with information-packed training manuals. These manuals include advanced topics as well as training objectives. Training Materials Training Materials enable you to learn at your own pace. or Training Materials. there is a type of training to meet everyone's needs. you receive hands-on experience with instruction from our certified staff of experts. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 0-1 . you can be sure you will find a class convenient for you. tricks.Introduction INTRODUCTION TO DEVELOPMENT IV IN MICROSOFT DYNAMICS AX 2009 Welcome We know training is a vital component of retaining the value of your Microsoft Dynamics® AX 2009 investment. combine the efficiency of online training with the in-depth product coverage of classroom training. Look for a complete list of manuals available for purchase on the Microsoft Dynamics website: www. and providing themselves with an excellent resource for reviewing key points after class. Need a Little Help? Level 2 exercises are designed to challenge students. Challenge Yourself! Level 3 exercises are the most challenging. By outlining three key points from the chapter. do provide you with helpful hints and more information to complete the exercise.Development IV in Microsoft Dynamics® AX2009 Microsoft Dynamics Courseware Contents Test Your Skills Within the Microsoft Dynamics Training Materials you find a variety of different exercises. the student is maximizing knowledge retention. including navigation. If you need further assistance each step of the task is outlined in the level one exercise. We suggest you try the level three exercises first. Step by Step Level 1 exercises are geared towards new users who require detailed instructions and explanations to complete the exercise. 0-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . These exercises are offered in three levels to accommodate the variety of knowledge and expertise of each student. These exercises are designed for the experienced student who requires little instruction to complete the required task. however. These exercises do not provide step by step instructions. step by step. while providing some assistance. Level 1 exercises guide you through the task. if you need help completing the task look to the information in the level two exercises. Quick Interaction: Lessons Learned At the end of each chapter within the Microsoft Dynamics Training Material. This interaction is designed to provide the student with a moment to reflect on the material they have learned. you find a Quick Interaction: Lessons Learned page. Hints are used to suggest time-saving features or alternative methods for accomplishing a specific task. may be valuable to an end user. Cautions are used to remind you of a specific result of a specific action which may be undesirable. Examples bring to light business scenarios that may better explain how an application can be used to address a business problem. BEYOND THE BASICS: Advanced information found throughout the training manual is preceded by the words BEYOND THE BASICS in bold. HINT: Hints are found throughout the training manual and are preceded by the word HINT in bold. Notes are used to provide information which.Introduction Documentation Conventions The following conventions and icons are used throughout this documentation to help you quickly and effectively navigate through the information. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 0-3 . EXAMPLE: Examples are found throughout the training manual and are preceded by the word EXAMPLE in bold. while not critical. CAUTION: Cautions are found throughout the training manual and are preceded by the word CAUTION in bold. Beyond the Basics provides additional detail. that may help you to more optimally use the application. outside of standard functionality. NOTE: Notes are found throughout the training manual and are preceded by the word NOTE in bold. 3. 1. 2.Development IV in Microsoft Dynamics® AX2009 Student Objectives What do you hope to learn by participating in this course? List three main objectives below. 0-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . This lesson also describes the basic POS design which is built upon during the course. you will develop a POS module which encompasses most of the modules that are discussed. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 1-1 .Chapter 1: Point-of-Sale Project CHAPTER 1: POINT-OF-SALE PROJECT Objectives The objectives are: • • • Create the base functionality for the Point-Of-Sale (POS) module Review the functional design of the POS project Review the technical design of the POS project Introduction To practice using the knowledge and skills you learn during this course. adding functionality appropriate to the lesson being reviewed. This lesson describes functional requirements and technical design suggestions as applied to a fictitious company. Development IV in Microsoft Dynamics® AX2009 Overview The following is an example of how the POS form looks when completed.2 1-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . FIGURE 1.1 The process flow of the finished POS module is as follows: FIGURE 1. Sales Order The POS has a Register ID to distinguish each register.NET® front end that would be used at a supermarket-type register. Because this POS is for people who walk in and pay for items immediately. quantity on hand and special instructions. The POS form contains the following fields: • • • • • • • Sales Id Register Id Item Id Quantity Sales Price Line Amount Item Name Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 1-3 . and any difference between the posted amount and the counted amount to a difference account. and the buyer is also offered the option of having the receipt emailed to them in XML format. but you will use one customer for every sale. This is normally used as a template for creating a new customer for each sale. Additionally. where very little information is displayed. the time of physical movement is when an invoice is posted. but shows more information. which enables an end of day routine to be processed. meaning that inventory transactions only get posted at the time of physical movement. as this is the only order update available. use a one-time customer parameter. This illuatrates running the Microsoft Dynamics® AX business logic from an external application. It is not a supermarket-type cash register. Functional Design The POS module in this scenario is for The Light Company used in the standard Microsoft Dynamics AX demo data. do not create a customer account each time. The sales order type should be Journal. There is a basic receipt printed. Payments can be posted against each register.Chapter 1: Point-of-Sale Project An end of day process is used to post the actual money counted to a cash account. In this case. This increases performance when entering lines. Instead. which could include information such as: delivery address. there is a Microsoft® C# . Development IV in Microsoft Dynamics® AX2009 Totals and Payment The POS form also includes a total order amount. Include a Payment button that opens the Payment Lines form. it is a proforma receipt). and procedures. and uses some of the sales module code. The receipt should show: • • • • • • • Sales Id Date Item Id Qty Price Total Payment Type The payment form and the pro-forma receipt are called from buttons on the POS form. Technical Design The POS module sits on top of the standard sales module. Create the following elements: Extended Data Types Type Name POSRegisterId POSPayId Extends SysGroup Num Label Register Id Payment Id Relation POSRegisterTable. which contains the following fields: • • Payment Type Amount Include the capability to print a receipt from the sales line (for now.PayId Tables Table Name POSRegisterTable RegisterId Description POSRegisterId Description Field Name Field Type Comment 1-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . tables.RegisterId POSPayTable. SalesPrice SalesLine.Chapter 1: Point-of-Sale Project Table Name POSRegisterTrans Field Name HoldingAccount RegisterId SalesId PayId LineNum PayMode Amount Posted PostedEOD Field Type LedgerAccount POSRegisterId SalesId POSPayId LineNum CustPayMode AmountMST NoYes NoYes Comment POSTable Form Form Name POSTable Data Sources SalesTable SalesLine Design Header SalesTable. Use Tab and Grid Use Tab Location Control Comments Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 1-5 .SalesId RegisterId OrderTotal Lines SalesLine.LineAmount ItemName Register Id can be either prompted for when the form is opened or the selection is mandatory on an order and remembered for subsequent orders.SalesQty SalesLine.ItemId SalesLine. AmountMST RegisterId. POSRegisterTrans Form The header section contains two buttons . and LineAmount are calculated from the item table when an item id is entered. PayTime. SalesId.one to call the POSRegisterTrans form. and UserId are populated by the system. LineAmount is calculated when SalesPrice is updated. SalesPrice.Development IV in Microsoft Dynamics® AX2009 SalesQty. Order Total = total Line Amount of all lines on the order. PayDate. Form Name POSRegisterTrans Data Sources POSRegisterTrans Design POSRegisterTrans. Use Tab and Grid Location Control Comments Reports Element Name POSReciept Data Sources SalesTable SalesTable SalesLine POSRegisterTrans Design Header Inner join to SalesTable Inner join to SalesTable Location Control Comments 1-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . LineNum. SalesPrice and LineAmount are calculated when the quantity is updated. and one to call the POSReceipt report.PayModeId POSRegisterTrans. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 1-7 .Name SalesLine.PayId POSPayTable.AmountMST Payment POSPayTable.Chapter 1: Point-of-Sale Project Element Name Location Control SalesTable.SalesId Date RegisterId Comments Lines SalesLine.AmountMST Summary This lesson leads you through creating the base elements for the POS module that will be used throughout the entire Development IV course. 1-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 2. 3.Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-1 . and journal numbers. invoice numbers and invoice vouchers. There are many number sequences needed for the application. vouchers. for example. and all can be set up so that they have a unique format and numbering range. vouchers are used by the system for tracking and linking transactions posted at the same time.Chapter 2: Number Sequences CHAPTER 2: NUMBER SEQUENCES Objectives The objectives are: • • • • • • • • Use and create number sequences Assign a new number using a number sequence Use continuous number sequences Format a number from a number sequence Use Number Pre-Allocation Use the Clean Up Process Use the Form Handler Use the NumberSeqReference table and methods Introduction Number sequences handle the automatic allocation of ID numbers. In some instances you can define a voucher series to follow a number series. Numbers are seen and referred to by the user. The General tab provides the following functions: • • • Stops the sequence from being used Specifies that the user should enter the number rather than have the system assign it Sets the number sequence to be continuous Continuous number sequences ensure that no numbers in the sequence are lost. that number can be used later.Development IV in Microsoft Dynamics® AX2009 Overview A number sequence is created under main menu > basic > setup > number sequences > number sequence. This clean up job is either called automatically by selecting Clean up on the Clean up tab of the number sequence form. NumberSequenceGroupRef contains the number sequence references specific to a group. on the customer table. A clean up job is available to set the status appropriately. Specify the smallest and largest numbers allowed for the particular sequences. The format field controls the length of the number and is used to insert fixed characters when desired. such as when a sales order is deleted before it is saved. and also by using a number sequence group. against the journal names. Number sequences are assigned to a specific function using various parameter forms in the application. and also the next number to be used. NumberSequenceReference holds which number sequence is used for which function. 2-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . If a number is not used. NumberSequenceGroup is a list of number sequence groups. or manually by clicking the Clean up button on the number sequence form. If a number from a continuous number sequence is used and the connection is lost completely (if a machine crashes). for example. Tables The tables used for number sequences are: • • • • • NumberSequenceTable contains the definitions of each number sequence. NumberSequenceList holds numbers for continuous number sequences that have not been completed or are currently reserved. the status of that number may be unknown. NumberSeqGlobal. and is better performance-wise. NumberSeqReference is the super class used. It does not keep a record of the status or store transaction ids for later clean up. • • • • • • Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-3 . NumberSeqReference creates the link between the function and the number sequence. NumberSequenceHistory holds a log of all changes made to the number sequence. and there is a sub class for each module. NumberSeqNumCache contains the method to manipulate the cache of reserved numbers. NumberSeq_Fast is used for number sequences that are not continuous. if the session is no longer active. frees up the number for later use. handles continuous number sequences. NumberSeqDataArea is used in the clean-up process. It handles records being deleted and ensures that two users cannot use the same number. • Classes The main classes used for number sequences are: • • NumberSeq assigns numbers and vouchers. NumberSeqCleanUp looks for numbers in the list that have not been completed. in case of a system crash. looks for the session that created them. and calls Clean up when appropriate. a global instance. is available once instantiated. It is used during the clean-up process.Chapter 2: Number Sequences • NumberSequenceTTS holds the transaction id of a number before it has been completely assigned. NumberSeqFormHandler is used whenever a number sequence assigns a number in a form. It is used in with NumberSeqNumCache. and. _makeDecisionLater . This handles the case where a record is created in a form. an error message is displayed. An example of this is provided in Microsoft Dynamics® AX in the ProdTableType. These methods are identical.Development IV in Microsoft Dynamics® AX2009 Assign a New Number To assign a new number. Use one of the static methods attached to the NumberSeq class. 2-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .This finds the number sequence used for the number. false.voucher(). The method uses NumberSeq::NewGetNum() to assign a new InventTransId. a number is assigned. newGetNum is the same as newReserveNum.This signifies that the number is assigned first. SalesParamters::NumRefInvoiceVoucher(). newGetNumAndVoucherFromCode() enables the instance to return both a number and a voucher from a number sequence code (instead of a reference). _voucherSequenceReference . and may be used when posting an invoice where an invoice number and a voucher number are required. Otherwise. For the method newGetNumAndVoucher the parameters are: • • • _numberSequenceReference . but the record is never committed to the database. it does not return a number. The name of the static methods describes their functions.This is set to true so that if a number sequence has not been set up for this reference. NumberSeq = NumberSeq::NewGetNumAndVoucher( SalesParameter::NumRefInvoiceId(). then set to be used later.Insert() class method. one set is called newGet<function> and the other is newReserve<function>. false) To retrieve the number or voucher. _dontThrowOnMissingRefSetUp . There are two sets of methods.This finds the number sequence used for the voucher. you can use the num() or voucher() methods: Voucher = NumberSeq. • The following code shows an example of using the NumberSeq::NewGetNumAndVoucherMethod. you need to first instantiate the NumberSeq class. For example. ttsNotifyCommit() method. Additionally. Adding TTSBEGIN and TTSCOMMIT around the code fixes the problem. You can commit the number immediately. during the TTSCOMMIT. In a process. as the user may delete the record. Format a Number The method to format a number is called from the num() method. and cleans it up later. If you do require to format a number in your code.Chapter 2: Number Sequences Continuous Number Sequences When using a continuous number sequence. The clean up is called in the xApplication. the decision may be made later. Num would be set to "ABD".Used() and NumberSeq. so normally you do not need to call this method from your code. as this is controlled using TTS. which takes an integer number and a format as parameters. this can be done by using the NumberSeq::numInsertFormat() static method. When writing code to assign a new number. The message "System does not support setup of continuous number sequence. but not doing so inside a TTS. If you do not make the decision later. In this case.abort() to update the numbers sequence list that the number is either used or aborted. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-5 . The format is specified using a combination of characters. enter "&" for each mandatory letter. decide what to do if the number sequence has been set up as continuous. you do not need the decision to be made later.GetNumFromTable() method. to have Microsoft Dynamics AX convert the integer to letters. Num = NumberSeq::numInsertFormat(30. Any fixed characters should be entered. and sets a status of Active. the system stores numbers as they are assigned in NumberSequenceList. the system creates the number in NumberSequenceList. or place it in the list to be updated later. Any mandatory numerals can be specified using a "#". In a form. Use NumberSeq. This is caused by attempting to get a new number from a number sequence set up as continuous. Refer to the NumberSeq."&&&")." displays. The overall speed can be increased by allowing pre-allocation on the number sequence for Closing Vouchers in Inventory Parameters. It is declared in the global class. Clean Up Process Automatic clean up is done by storing a list in memory of number sequences that must be checked. which is mapped to a key of a combination of company and number sequence code.Development IV in Microsoft Dynamics® AX2009 Number Pre-Allocation Processes that use many numbers from a single number sequence can improve performance by using number pre-allocation. and checks whether they should be deleted.isProcessDead()). shows retrieving numbers from the cache. 2-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Pre-allocation uses a global instance of the class NumberSeqGlobal. For example. this pulls a set number of numbers into the memory and provides faster access. it is available until the session is closed. the numbers are only retrieved in the NumberSeq_Fast class. This function is only available for non-continuous number sequences. The getNumInternal() method.fillCache() class method. which means that once it is instantiated. You can see where it stores the reserved numbers in the NumberSeqNumCache.setClean() shows the trans id and number sequence code being stored in a list for clean up later. The clean-up process is called when the current transaction is committed. The pre-allocated numbers are stored in a list. the inventory close process uses voucher numbers if posting to the ledger. The manually started clean up process goes through either a specified number sequence or all number sequences. application. NumberSeqDataArea. Basically. It goes through this list (created in setClean()) and finds any entries that have dead sessions (NumberSeqCleanUp. looks at any records in the NumberSequenceList. Instantiate the class using the static method NewForm(). which creates records in the table NumberSequenceReference. but it is a best practice. and find the corresponding NumberSeqReference sub class. NumberSeqReference To create a new number sequence reference. The parameters are: • • • • • _NumberSequenceCode is the code of the number sequence to be used. Decide which module's parameters this number sequence reference should be included in. 3. The loadModule() method shows a number of blocks of code.formMethodDataSourceDelete(). _FieldIdNum is the field id of the field that is to use the number. _dontThrowOnMissingSetup defines whether an error message should be displayed if the number sequence has not been set up. for example. _FormDataSource is the data source on the form for the record that is to use the number. The CustTable form shows an example of how to use this class correctly. have the new data type created in the number sequence references. You must add code to call methods in the various datasource methods. _callerForm is the calling form. 2.Chapter 2: Number Sequences Form Handler To help use number sequences in forms correctly. call the NumberSequenceFormHandler class. For example: numberSeqFormHandler. Often this EDT extends num. Procedure: Create a new number sequence Creating a new number sequence is achieved by creating a new reference for the sequence. Use the following steps to create a new number sequence: 1. Create a new Extended Data Type (EDT). should be placed in the data source delete() method. This displays it in the appropriate modules parameters form. a newly created data type that needs sequential numbers assigned to it. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-7 . The names of the methods clearly define where they should go. This is not mandatory. It shows how number sequence API works and how to implement number sequence API in the code. Parameters tables show methods beginning with numRef. The reference can then be referred to using this static method. Use one of these methods as a template. o sortfield defines the sequence that the references are displayed on the Number sequence tab of the parameters form. 6. 5. There are a number of wizard fields used for default values when using the wizard to create number sequences. Create a static method that will be used to retrieve the reference. 2-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 7. Summary This lesson provides an overview of how number sequences are used in the application.Development IV in Microsoft Dynamics® AX2009 4. Copy one of these blocks and change the following fields: o DataTypeID is the type Id of the new data type. For example: salesParameters::NumRefSalesID() This returns the record in NumberSequenceReference that contains the reference for SalesId. o referenceHelp is the longer description of the reference shown in the top part of the Number sequence tab of the parameters form. This is usually done on the relevant parameters table. o referenceLabel is the description shown in the left column of the Number sequence tab on the parameters form. Chapter 2: Number Sequences Test Your Knowledge 1. when would you use newGetNumAndVoucherFromCode() and newGetNumAndVoucher()? 2. From which method would you get the number sequence reference used for a sales order number? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-9 . What does it mean that a number sequence is continuous? 3. When assigning numbers from the numberseq class. Development IV in Microsoft Dynamics® AX2009 Lab 2.1 . Add a new element POSModule. Create method "numberSeqModule" \and return enum NumberSeqModule with the value NumberSeqModule::POSModule. Modify BaseEnum NumberSeqModule: a. 2. but should be displayed in the SalesParameters form. create a new reference for the new EDT POSPayId. EnumValue = 100. e.Add Pay Id number sequence Scenario To make sure POS transactions can be traced and are unique. a new Number Sequence needs to be added for the POS module. You need the same methods . Use NumberSeqReference_Sales as a reference. The POS module should have its own sub class of NumberSeqReference. Use logisticBasic: as the configuration key. 3. Step by Step 1. Create new class NumberSeqReference_POSModule as follows: a. c. b. Challenge Yourself! In the POS Module. d. You also need to modify the methods NumberSeqReference::construct() and NumberSeqReference::ModuleList(). Use the previously created extended datatype POSPayId for the data type reference.loadModule() and numberSeqModule() .and adapt them accordingly. b. Create method "loadModule" similar to the method loadModule on the NumberSeqReference_SalesOrder class. 2. Extend numberSeqReference. 2-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Label = POS module. c. Need a Little Help? 1. 5. b. Modify the method construct to initialize the newly created class and return NumberSeqReference_POSModule(_module) if the module parameter passed into this method is equal to NumberSeqReference_POSModule::numberSeqModule()." to return an object of the type NumberSeqReference. Create new method "numberSeqModule_POS. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-11 .visible method call in the method numberSeqPostInit.setTempDate SalesParameters::numberSeqModule_POS())). 7.Chapter 2: Number Sequences 3.queryRun statement in the method NumberSequenceReference:ExecuteQuery. Create new method "numberSeqReference_POS. Add numberSeqReferencePOSModule. numberSeqReferencePOSModule. c.sameAsActive() to the numberSequenceReference_ds." to return a NumberSeqModule enum with the value found in NumberSeqReference_POSModule::numberSeqModule() similar to method numberSeqModule on salesParameters. Modify NumberSeqReference class as follows: a.load(). 8. which returns a NumberSequenceReference table with the value found in NumberSeqReference::findReference(typeId2ExtendedTypeId(t ypeid(POSPayId))). Declare variable NumberSeqReference numberSeqReferencePOSModule in the class declaration. 4. and referenceSameAsLabel. Initialize above declared variable like this: numberSeqReferencePOSModule = SalesParameters::numberSeqReference_POS(). 9. 6. Create new method numRefPOSPayId. Add following to the tmpIdRef.object method call. Add following to the method "numberSeqPreInit:" a. Modify CustParameters form as follows: a. Add SalesParameters::numberSeqModule_POS() to the this. Modify SalesParameters table as follows: a. with the value found in method NumberSeqReference::construct(SalesParameters::numberSeqM odule_POS()) similar to method numberSeqReference on salesParameters. 2 . 3. 5. Need a Little Help? Use the CustTable form as inspriration.Development IV in Microsoft Dynamics® AX2009 Lab 2. Override method validateWrite on the salesTable datasource. Challenge Yourself! Add the NumberSeqFormHandler methods to the forms POSTable and POSPayTable to create new number for SalesId and POSPayId. Modify the POSTable form as follows: 2. see the custTable form. see the custTable form. 6. 8. Step by Step 1. see the custTable form. Create new method named numberSeqFormHandler. They should be added using the form handler class. see the custTable form. Declare variable NumberSeqFormHandler numberSeqFormHandler in the class declaration method. see the custTable form.Use POS values instead of custTable values. 7.Use Form Handler Scenario The POS form should use the sales id and pay id number sequences. Override method LinkAcitve on the salesTable datasource. Override method write on the salesTable datasource. Override method delete on the salesTable datasource. 4. see the custTable form. 2-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Look for all references to numberSeqFormHandler(). Override the method created on the salesTable datasource. 2.Chapter 2: Number Sequences Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 2-13 . 3. when would you use newGetNumAndVoucherFromCode() and newGetNumAndVoucher()? MODEL ANSWER: NewGetNumAndVoucher() is used to instantiate NumberSeq from NumberSeqReference. What does it mean that a number sequence is continuous? MODEL ANSWER: A continuous number sequence ensures that all numbers in the sequence are used. NewGetNumAndVoucherFromCode() is used to instantiate NumberSeq from a NumberSeqCode. When assigning numbers from the numberseq class.Development IV in Microsoft Dynamics® AX2009 Solutions Test Your Knowledge 1.NumRefSalesId(). 2. From which method would you get the number sequence reference used for a sales order number? MODEL ANSWER: SalesParameters. 3. 2-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Chapter 3: PrintJobSettings CHAPTER 3: PRINTJOBSETTINGS Objectives The objectives are: • • • • Set Print Options Retrieve Print Options Use Pack and Unpack to Store Settings Use SysPrintOptions Introduction The PrintJobSettings class is used with report output. It can be used both to get and set these options. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-1 . This lesson explains and provides examples on how to set and retrieve print options and how to use pack and unpack to store these settings. Furthermore. and can also format all the options such that they can be easily saved and retrieved later. It is a system class that contains methods and variables to hold all the settings that determine where and how the output is handled. the class SysPrintOptions is briefly introduced. paperOrientation(PrinterOrientation) sets the orientation of the report. it does not make sense to set the Mail To option.format(printFormat) sets the file format when writing to a file or to e-mail. printJobSettings.1 THE PRINT OPTIONS SCREEN (SYSPRINTFORM) All these options. can be set within the code.setTarget(PrintMedium::Mail) sets the Send To option to E-mail recipient. where PrtnterOrientation is an ENUM.Development IV in Microsoft Dynamics® AX2009 Set Print Options When printing a report. printJobSettings. If the target is Screen. and more. 3-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . the normal print options form is shown. FIGURE 3.allPages(boolean) specifies whether to print all pages. Str contains one or more email addresses.mailTo(str) sets the 'Mail To' option. printJobSettings. where it forces the target to be a printer. For example: printJobSettings. printJobSettings. This is shown in the Cheque_US report in the init() method.fitToPage(Boolean) specifies whether the report can be shrunk to fit the page. Some examples of the other options are: • • • • • printJobSettings. Print Options methods Additional options depend on what the target is as to whether it makes sense to use them. deviceName(). Boolean enableProperties=TRUE.printJobSettings(). Boolean enablePages=TRUE. enableDevice. 1) // from copy one use this tray } return ret.copies(1). printJobSettings printJobSettings = element. int i.Chapter 3: PrintJobSettings Example using Print Options The following example shows how the prompt method in a report can be overridden to force a copy of the report to be printed in a different tray. // number of copies to print printJobSettings.addTrayPageCopy(0. ret = super(enableCopy. printJobSettings. } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-3 . // <this line may not be needed. -1. Boolean enablePrintTo=TRUE) { Boolean ret. Boolean enableDevice=TRUE. int trayCount. public Boolean prompt(Boolean enableCopy=TRUE. enablePages. if (ret) { // store the name of the printer the user selected above deviceName = printJobSettings. enablePrintTo). enableProperties. name = report name. you do not print invoices to the Screen. then a warning is given.Development IV in Microsoft Dynamics® AX2009 Retrieve Print Options As with setting the print options. where the instance of PrintJobSettings is instantiated using a container stored for each document type and user. it confirms that this is correct. in a normal live situation. 3-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Calling ReportRun.PackPrintJobSettings() to create a container with all options.unpackPrinterSettings(container) retrieves the printer options for that report from the container. For example. The system checks what target has been selected and if the user has selected the screen. A container that includes printer options can be used when instantiating PrintJobSettings which sets all the options. Use of Pack and Unpack to Store Settings All the settings the user selects or that you set within the code can be stored and retrieved.validate() class method. Review the clicked method on form ProdParmStartUp. Use PrintJobSettings. Last user-selected printer settings are stored in the Usage Data (sysLastValue) as with values stored in pack and unpack in RunBase. type = Report. printButton. during a sales update. and if the target is Screen. This can be stored in a field of type container for later retrieval. They can be seen in the Usages Data form. The code for this can be seen in the SalesFormLetter. it may be necessary to determine what the user has selected to take appropriate action. This contains an example of both packing and unpacking a print options container. buildPrinterMap(). mapIterator.setPrintJobSettings(printJobSettings). } } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-5 . or not installed on the server. static void ShowListOfPrinters(Args _args) { printJobSettings printJobSettings. This class is used by the system to control printing. sysPrintOptions sysPrintOptions. printJobSettings = SysPrintOptions::newPrintJobSettingsOnServer(). sysPrintOptions.more()) { info(mapIterator.value()). Build list of Printers The following example shows how to use SysPrintOptions to display a list of all available printers.begin(). mapIterator. map printerMap. .Chapter 3: PrintJobSettings Use of SysPrintOptions SysPrintOptions is a class that has methods written for using PrintJobSettings. mapIterator = new mapIterator(printerMap). When printing. but the printer may be local to the client. sysPrintOptions = new sysPrintOptions(). mapIterator mapIterator. Printing works differently on the server than on the client. and is not normally needed to be called by the developer. printerMap = sysPrintOptions. while (mapIterator.getPrinterMap().next(). processing is done on the Application Object Server (AOS). sysPrintOptions. SysPrintOptions can be used to circumvent these issues. Development IV in Microsoft Dynamics® AX2009 Summary This lesson describes how to use the system class PrintJobSettings in connection with report output. 3-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Also. The lesson explains and provides examples on how to set and retrieve print options and how to use pack and unpack to store these settings. the class SysPrintOptions is briefly introduced. Where does Microsoft Dynamics AX store the previously selected printer settings for a specific report? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-7 .Chapter 3: PrintJobSettings Test Your Knowledge 1. when this report is called from a class? 3. What is the syntax for setting the default printer option to e-mail in the PrintJobSetting class? 2. Which method would you use to initialize printJobSettings for a specific report. element. Isaac. A message is shown saying that the report has been scaled. the report needs to be scaled to fit onto the page. even if the report has been scaled. the systems developer.1 .Suppress Scaling Message Scenario When the sales order lines report is run with all options selected. It should go after the call to super(). Challenge Yourself! Use the printJobSettings. The report to modify is SalesLinesExtended. has been asked to stop the message from appearing.Development IV in Microsoft Dynamics® AX2009 Lab 3. Step by Step Add the following code to the init() method of the report SalesLinesExtended. 3-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .suppressScalingMessage() to stop the message from appearing.suppressScalingMessage(true).printJobSettings(). enable printer options to be set up and saved for each register. Create a new container EDT.Print Job Settings Scenario Each POS Register has a printer. To see similar functionality where printer settings are set and saved. Challenge Yourself! In the POS module.printJobSettins. 4.PrintJobSettings. 3. to store the print job settings for the register. 2. HINT: Look at the Production order Startup parameterspick list printer settings. Step by Step 1. Create a new field POSRegisterTable. Need a Little Help? 1. A function to set which printer each register uses is needed. Add a button to the POS Register table form to call this new method. 2. POSRegisterPrintJobSettings.2 .Chapter 3: PrintJobSettings Lab 3. type = POSRegisterPrintJobSettings. Create a new method on table POSRegisterTable to call the standard printer options form and store the return container in POSRegisterTable. Add a container field to the register table. look at the Production order Startup parameters. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-9 . pick list printer settings. In the receipt report. Use the method this. 2. set the printer options to the options stored against the appropriate register. set the printJobSettings from the container stored against the register table. Challenge Yourself! When the receipt is printed.PrintJobSettings(). the system should automatically pick which printer to use based which register is being used.3: Print the receipt to the correct printer Scenario When a receipt is printed. Step By Step 1. 3. Retrieve the register id from the sales order record.UnpackPrintJobSettings() to set the printer settings for the report from the container. 3-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Development IV in Microsoft Dynamics® AX2009 Lab 3. Step By Step 1. As soon as the user clicks the Receipt button. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-11 . and remove the call to super(). Use the print options selected for the register. Override the prompt method on the report.Bypass Print Options Scenario When a receipt is printed. it should print.4 . The print options form should not be displayed. Challenge Yourself! Remove the ability for the user to change the printer options on the receipt by not displaying any prompt for the report. the user should not have to select which printer to use. Return true from the method.Chapter 3: PrintJobSettings Lab 3. 3-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. 3. 2. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 3-13 .SetTarget(PrintMedium::Mail).Chapter 3: PrintJobSettings Solutions Test Your Knowledge 1. Which method would you use to initialize printJobSettings for a specific report. when this report is called from a class? MODEL ANSWER: ReportRun. Where does Microsoft Dynamics AX store the previously selected printer settings for a specific report? MODEL ANSWER: Usage Data (SysLastValue). 3.UnpackPrintJobSettings. What is the syntax for setting the default printer option to e-mail in the PrintJobSetting class? MODEL ANSWER: PrintJobSettings. 2. Development IV in Microsoft Dynamics® AX2009 3-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Set up and manage the Business Connector. Introduction When using the Microsoft Dynamics® AX 2009 Business Connector. Describe the architecture of the Business Connector. List various uses of the Business Connector. other than Microsoft Dynamics AX 2009.NET object. which enables the use of applications as front ends. This implies that the application can gain access to the data and business logic of Microsoft Dynamics AX 2009. Use the managed classes in the Business Connector. other applications can access Microsoft Dynamics AX 2009 as a . Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-1 .Chapter 4: Business Connector CHAPTER 4: BUSINESS CONNECTOR Objectives The objectives are: • • • • • • Describe the purpose of the Business Connector. Debug code through the Business Connector. which "acts-on-behalf-of" Microsoft Dynamics AX 2009 users who cannot be fully authenticated. It supports the functionality in the Enterprise Portal server. Automatically registered during installation.Development IV in Microsoft Dynamics® AX2009 Business Connector Overview The Business Connector is a Microsoft Dynamics AX 2009 component that enables external applications to interact with Application Object Server instances.NET platform and provides a set of managed classes that provide easy access to X++ functionality in Microsoft Dynamics AX 2009. The Business Connector Proxy user. and Application Integration server roles. The following are some characteristics of the Business Connector: • • • Requires Microsoft Windows® authentication. .NET Platform The Business Connector is based on the . 4-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Reporting server. The Business Connector can be installed as a stand-alone component and used to develop thirdparty applications that integrate with Microsoft Dynamics AX 2009. and can be shared between developers. Proxy The Business Connector Proxy is a Windows domain user account that is used to enable the Business Connector to "act-on-behalf" of Microsoft Dynamics AX 2009 users who cannot be fully authenticated. For more information on the proxy user. which is an integrated part of the Microsoft Windows Vista. and Windows NT 4. A configuration target field has been added to the utility to enable you to select the Business Connector Proxy. go to Control Panel > Administrative Tools > Event Viewer.Chapter 4: Business Connector Business Connector Setup and Configuration Registration The Business Connector in Microsoft Dynamics AX 2009 is registered automatically. Windows 2000. the Microsoft Dynamics AX 2009 Business Connector logs whenever it is started or stopped. and global breakpoints for X++ code running in the Business Connector or in a user session. during installation. XP and Windows 2000. Windows XP. Any unexpected events are also logged in the Application Log for further investigation by the administrator. Only Administrators and Power Users on a computer running Microsoft Dynamics AX 2009 with a Business Connector proxy user can modify the Business Connector proxy user configuration options." Debugging In Microsoft Dynamics AX 2009 it is possible to enable user breakpoints for X++ code running in the Business Connector. A global breakpoint is one that is set for a computer. All events logged by the Microsoft Dynamics AX 2009 Business Connector have a source name of "Microsoft Dynamics AX Business Connector. To open the Event Viewer in Windows Vista. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-3 . consult the Microsoft Dynamics AX 2009 Administrator Guide. In the Event Viewer. For instance. found under the Help menu. The Business Connector Proxy has unique configuration settings that can be modified.0 operating system. select the Application Log folder. The Microsoft Dynamics AX 2009 Business Connector logs specific events to the Application Log of the Event Viewer. instead of a user. Event Monitoring The Microsoft Dynamics AX 2009 Business Connector interfaces with the Event Viewer component. 5.1 MICROSOFT DYNAMICS AX 2009 CONFIGURATION UTILITY. DEVELOPER TAB 2.2 WARNING MESSAGE WHEN CLOSING CONFIGURATION TOOL 4-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . A warning message may appear explaining that debugging is enabled but not started. FIGURE 4. 6. Select the Configuration that you want to enable breakpoints for. Open the Microsoft Dynamics AX 2009 Configuration Utility. Select the Local Client setting in the Configuration target. Click OK. FIGURE 4.Enabling Breakpoints in the Business Connector Use the following procedure to enable breakpoints in the Business Connector: 1.Development IV in Microsoft Dynamics® AX2009 Procedure . 4. 3. Select Enable user breakpoints to debug code running in the Business Connector and/or Enable global breakpoints to debug code running in the Business Connector or client. 7. Debugging must also be enabled on the Application Object Server (AOS). Open the Microsoft Dynamics AX Server Configuration tool.4 MICROSOFT DYNAMICS AX SERVER CONFIGURATION UTILITY Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-5 . Make sure Debug mode is set to When Breakpoint. DEVELOPMENT TAB 8. FIGURE 4. FIGURE 4. and follow this path: Tools > Options > Developer tab.Chapter 4: Business Connector To start debugging.3 OPTIONS FORM. log on to the client. the following must be in place: • • • Debugging is enabled on Microsoft Dynamics AX 2009 AOS configuration. an instance of the Microsoft Dynamics AX 2009 debugger must be running. select Enable breakpoints to debug X++ code running on this server. Debugging is enabled on Microsoft Dynamics AX 2009 client configuration.Development IV in Microsoft Dynamics® AX2009 9. 10. when a breakpoint exists in X++ code called from .NET application to use the Microsoft Dynamics AX 2009 debugger for displaying breakpoints. launched from a Client running the same configuration. Debug mode is set to When Breakpoint in Client Options in Microsoft Dynamics AX 2009. To ensure that the Visual Studio debugger jumps to the Microsoft Dynamics AX 2009 debugger. This can be achieved by following this path in a Microsoft Dynamics AX client: Tools > Development tools > Debugger. it must be run in debug mode for the X++ breakpoints to work. An instance of the Microsoft Dynamics AX 2009 Debugger is running. on a Client running the same configuration. On the profile for the AOS instance that the Business Connector will talk to.NET code is running in Debug mode.NET code in Visual Studio. When running the . For a . 11. • • 4-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .NET code. The Visual Studio . Chapter 4: Business Connector Business Connector Architecture From a simplified architecture viewpoint.NET Business Connector consists of three layers: • • • Managed classes: Exposes public methods that can be called to interact with Microsoft Dynamics AX 2009.NET Business Connector: • • • • • • Axapta AxaptaBuffer AxaptaContainer AxaptaObject AxaptaRecord VariantWrapper These classes can be used in Visual Studio projects to interface with Microsoft Dynamics AX 2009.NET Business Connector. through the .NET BUSINESS CONNECTOR ARCHITECTURE Managed Classes The following managed classes are provided by the . Transition layer: Maps the managed classes to the corresponding interpreter functions. Each class contains a collection of methods that can be called to perform business logic in Microsoft Dynamics AX 2009. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-7 . the . FIGURE 4. Interpreter layer: Executes X++ and communicates with the AOS.5 SIMPLIFIED . AxaptaBuffer Class . An AxaptaBuffer object can be used with AxaptaContainer objects.BusinessConnectorNet namespace.The AxaptaRecord class provides functionality for reading and modifying Microsoft Dynamics AX 2009 records.Dynamics. For more information on these classes. All of these classes (except Axapta) have a corresponding NotValidException class (for example. jobs.NET languages can be found in the Developer Help in the Microsoft Dynamics AX 2009 application.dynamics. AxaptaObject Class . create Microsoft Dynamics AX 2009 record.NET Framework topic in the Developing for Microsoft Dynamics AX helpbook within the application. The following are examples of Visual Basic code in Visual Studio. (Examples using other .BusinessConnectorNet.) Subsequent boxes assume that previous variables and objects are still available (for example. and TTS commands.Dynamics.Development IV in Microsoft Dynamics® AX2009 All these classes are found in the namespace: Microsoft.The AxaptaContainer class provides the ability to read and write to and from Microsoft Dynamics AX 2009 containers. and assembly Microsoft.The Axapta class provides the ability to connect to the Microsoft Dynamics AX 2009 system. create Microsoft Dynamics AX 2009 classes. AxaptaRecord Class . which execute Microsoft Dynamics AX 2009 business logic through the Business Connector. static table methods. object axapta1).businessconnectornet. and perform other Microsoft Dynamics AX 2009 system tasks. container.dll which is located in the bin directory in the Microsoft Dynamics AX 2009 Client directory) Axapta Class . view the Microsoft Dynamics AX . AxaptaContainer Class .Dynamics. AxaptaContainerNotValidException).The AxaptaBuffer class provides the ability to add data to and retrieve data from a Microsoft Dynamics AX 2009 buffer. 4-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and buffer objects.The AxaptaObject class provides the ability to call Microsoft Dynamics AX 2009 class methods. The Axapta class also contains methods to call static class methods.BusinessConnectorNet (in microsoft. execute transactions. There are 27 exception or invalid classes available in the Microsoft. This parameter is optional. (String) The domain associated with the Windows user. This parameter is optional and is used to override the corresponding parameter in the configuration being used. (String) The company to activate. configuration) Log on as the Business Connector Proxy User to Microsoft Dynamics AX Parameter user Description (String) Name of the Windows user to use for logging on to Microsoft Dynamics AX 2009. objectServer. This parameter is optional and is used to override the corresponding parameter in the configuration being used. This parameter is optional and is used to override the corresponding parameter in the configuration being used. language.Chapter 4: Business Connector Log on to Microsoft Dynamics AX through the Business Connector Dim company As String Dim language As String Dim objectServer As String Dim configuration As String Dim axapta1 As New Axapta company ="dmo" language ="en-us" objectServer ="objectServerName" configuration ="configurationName" axapta1. domain bcProxyCredentials company language objectServer Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-9 . (String) The language to use for Microsoft Dynamics AX 2009 labels.Logon(company.NET network credential object. (String) Name of the Microsoft Dynamics AX 2009 Object Server to connect to. This parameter is optional (NetworkCredential) A . language.Development IV in Microsoft Dynamics® AX2009 Parameter configuration Description (String) Name of Microsoft Dynamics AX 2009 configuration to use while logging on. This parameter is optional. then this parameter is used to specify the path which points to an exported configuration file."proxyPassword". objectServer. configuration) 4-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . bcProxyCredentials. company. If null is specified for this parameter and Business Connector is being executed within the context of an interactive Windows account.LogonAs(username. domain. The following is a code example using the LogonAs() method: Dim company As String Dim language As String Dim objectServer As String Dim configuration As String Dim axapta1 As Axapta Dim bcProxyCredentials As New NetworkCredential("proxyUsername"."domain") Dim username As String Dim domain As String company ="dmo" language ="en-us" objectServer ="objectServerName" configuration ="configurationName" username ="proxyUsername" domain ="domain" axapta1. If Business Connector is being executed within the context of a non-interactive Windows account (such as the Business Connector Proxy AD user). Business Connector will use the default configuration (maintained by the Microsoft Dynamics AX Client Configuration Utility). CreateAxaptaObject(className) returnValue = salesLine_Net.itemId=='001'" axapta1.ExecuteStmt(statement.Call(methodName. itemId. qty) Executing SQL Statement Against the Microsoft Dynamics AX InventTable Table Dim statement As String Dim inventTableRecord As AxaptaRecord Dim tableName As String tableName ="InventTable" inventTableRecord = axapta1.Chapter 4: Business Connector Calling calcPrice Method from a Custom X++ Class Called SalesLine_Net Dim className As String Dim methodName As String Dim itemId As Object Dim qty As Object Dim returnValue As Object Dim salesLine_Net As AxaptaObject className ="salesLine_Net" methodName ="calcPrice" itemId ="001" qty ="5" salesLine_Net = axapta1. inventTableRecord) Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-11 .CreateAxaptaRecord(tableName) statement ="select * from %1 where %1. Besides the most common use of supporting the connection between SharePoint and Microsoft Dynamics AX 2009 for the Enterprise Portal. and then write and debug code on both sides of the Connector (both .Development IV in Microsoft Dynamics® AX2009 Summary The Business Connector provides a conduit between Microsoft Dynamics AX 2009 and other applications. By understanding how to effectively install and configure the Business Connector.NET and X++). 4-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . the applications developed for the business are more coordinated and effective. the Business Connector also opens up the existing Microsoft Dynamics AX 2009 business logic and data to external applications within your business scope. Chapter 4: Business Connector Test Your Knowledge 1. Do you need to register the . Describe the purpose of the Business Connector.NET connector into the Global Assembly Cache after it is installed? 3. What is the Business Connector Proxy User account used for? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-13 . 2. What is the purpose of the Managed Classes in the . in Visual Studio how would you create a new instance of the SalesFormLetter Microsoft Dynamics AX 2009 class? 4-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Using a .NET Business Connector? 6. How is debugging through the Business Connector enabled? 5.Development IV in Microsoft Dynamics® AX2009 4.NET language. Challenge Yourself! Create a front end for the POS module using a . To use this version. The second version has most of the interface built already. POSConsole_Complete is completed and needs no additional programming in C# . and to complete an order. delete last sales line.NET form that can be used in a 'supermarket' environment. • • Create the touch screen front end in a .NET. You may still view the C# code for thus console by following the steps below. as detailed below. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-15 . There are two versions available for use: The first version. run the executable POSConsole. There should also be buttons that can complete an order and delete the last line. The form should have a large display.zip.1 . can display item descriptions and prices. included in the file POSConsole. and a large number pad (so touch screens can be used).Chapter 4: Business Connector Lab 4. but you need to add the procedure to call the post invoice function.NET as the syntax for C# is similar to X++. See Chapter 1 for details.NET. It has been created using C# .zip.NET form.Business Connector Scenario This is a part of the Point-of-Sale Case Study. Create buttons to add a sales line. using the files from POSConsole_Complete. Step by Step As you may not be familiar with . which then uses the Microsoft Dynamics AX 2009 Business Connector to communicate with the installation. this form has been created for you. You still need to write the necessary code in Microsoft Dynamics AX 2009.exe. sln 2. d. Place them in a new directory called POSConsole in the Visual Studio Projects directory: o app.cs o POSConsole. which can then be found in the directory Visual Studio Projects \ POSConsole \ Bin \ Debug. CSharp_SalesOrder. f. itemId +itemId): Deletes sales line using sales id and item id.createSO(): creates a sales order and returns the sales id.completeOrder() to the method buttonComplete_Click() so the invoice posts when the Complete Order button is clicked. CSharp_SalesOrder. Class CSharp_SalesOrder which is used in conjunction with creating and deleting sales orders.deleteSalesLine(SalesId _salesId.resx o POSConsole. Use a parameter driven customer account. Open the C# . c. CSharp_SalesOrder. so this method can remain empty for now. The following files are included in POSConsole_Incomplete. Select build > build posconsole to build the executable. Create these classes and methods: 1. salesId _SalesId): Creates a sales line for the specified item.Development IV in Microsoft Dynamics® AX2009 Do as follows: In Visual Studio 2005 1. In Microsoft Dynamics AX 2009 The POS executable calls the following class methods. qty and sales id. post a payment.zip and contain the C# . 4.ico o assemblyInfo. qty _qty.NET project solution.deleteSalesOrder(SalesId _SalesId): deletes all lines and the salesTable record for the specified sales id.csproj o POSConsole.cs o POSConsole.completeOrder(SalesId _SalesId): posts an invoice for the specified sales order. a.insertSalesLine(itemId _itemId.checkItemId(itemId _itemId) :returns true if item id is valid.sln file 3. CSharp_SalesOrder. Add a call to the Microsoft Dynamics AX 2009 class method CSharp_SalesOrder. and settle the transactions are written in chapter 11. b. CSharp_SalesOrder. CSharp_SalesOrder. 4-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .NET development environment: select file > open solution and select the POSConsole. e. The routines to post an invoice. b. Class SalesOrderIntegration a. SalesOrderIntegration. Do as follows: In Visual Studio 2005 1.NET development environment: select file > open solution and select the POSConsole. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-17 . SalesOrderIntegration. Add a call to the Microsoft Dynamics AX 2009 class method CSharp_SalesOrder.csproj o POSConsole.ico o assemblyInfo.NET project solution.Chapter 4: Business Connector 2.getSalesTotal(SalesId _salesId): returns the total amount for the specified sales order. 4. qty _qty): returns the sales price for the item id and the qty specified. c. Select build > build posconsole to build the executable.zip and contain the C# .resx o POSConsole.getSalesPrice(ItemId _itemId. which can then be found in the directory Visual Studio Projects \ POSConsole \ Bin \ Debug.cs o POSConsole. SalesOrderIntegration.getItemName(ItemId _itemId): returns item name or specified item id. Open the C# .cs o POSConsole. Place them in a new directory called POSConsole in the Visual Studio Projects directory: o app.completeOrder() to the method buttonComplete_Click() so the invoice posts when the Complete Order button is clicked.sln 2. The following files are included in POSConsole_Incomplete. 4.sln file 3. f.checkItemId(itemId _itemId) :returns true if item id is valid. post a payment.deleteSalesLine(SalesId _salesId.insertSalesLine(itemId _itemId.getSalesPrice(ItemId _itemId. Class CSharp_SalesOrder which is used in conjunction with creating and deleting sales orders. qty _qty. 2. CSharp_SalesOrder. SalesOrderIntegration. The routines to post an invoice. CSharp_SalesOrder. d. salesId _SalesId): Creates a sales line for the specified item. so this method can remain empty for now. CSharp_SalesOrder. Use a parameter driven customer account. a. Class SalesOrderIntegration a. c. SalesOrderIntegration.getSalesTotal(SalesId _salesId): returns the total amount for the specified sales order. b. CSharp_SalesOrder. SalesOrderIntegration. e. Create these classes and methods: 1.deleteSalesOrder(SalesId _SalesId): deletes all lines and the salesTable record for the specified sales id. b. qty and sales id.completeOrder(SalesId _SalesId): posts an invoice for the specified sales order.Development IV in Microsoft Dynamics® AX2009 In Microsoft Dynamics AX 2009 The POS executable calls the following class methods. 4-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . itemId +itemId): Deletes sales line using sales id and item id.createSO(): creates a sales order and returns the sales id. c.getItemName(ItemId _itemId): returns item name or specified item id. CSharp_SalesOrder. and settle the transactions are written in chapter 11. qty _qty): returns the sales price for the item id and the qty specified. CSharp_SalesOrder. csproj o POSConsole.NET project solution.cs o POSConsole.zip and contain the C# .1 .NET form that could be used in a 'supermarket' environment.cs o POSConsole. which can then be found in the directory Visual Studio Projects \ POSConsole \ Bin \ Debug. but you will need to add the procedure to post the invoice.Chapter 4: Business Connector Lab 4.Business Connector (Solution) Scenario Either: Create a front end for the POS module using a . 4.completeOrder() to the method buttonComplete_Click() so the invoice posts when the Complete Order button is clicked. Open the C# . 4. This form already has most of the interface built already.ico o assemblyInfo. and a large number pad (so touch screens can be used). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-19 . Add a call to the Microsoft Dynamics AX 2009 class method CSharp_SalesOrder.NET development environment: select file > open solution and select the POSConsole.resx o POSConsole. 3. There should also be buttons that can complete an order and delete the last line. Step by Step Do as follows: In Visual Studio 2005 1. Place them in a new directory called POSConsole in the Visual Studio Projects directory: o app. The following files are included in POSConsole_Incomplete.sln file 3.sln 2. Or: You may use the front end already created for you in C#. Select build > build posconsole to build the executable. can display item descriptions and prices. The form should have a large display. Use a parameter driven customer account.checkItemId(itemId _itemId) :returns true if item id is valid. so this method can remain empty for now. SalesOrderIntegration. CSharp_SalesOrder. post a payment.deleteSalesOrder(SalesId _SalesId): deletes all lines and the salesTable record for the specified sales id.getItemName(ItemId _itemId): returns item name or specified item id.completeOrder(SalesId _SalesId): posts an invoice for the specified sales order. and settle the transactions are written in chapter 11.insertSalesLine(itemId _itemId. 4-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . f.getSalesTotal(SalesId _salesId): returns the total amount for the specified sales order. c. CSharp_SalesOrder. CSharp_SalesOrder. itemId +itemId): Deletes sales line using sales id and item id. Create these classes and methods: 1. The routines to post an invoice.getSalesPrice(ItemId _itemId. c. qty _qty): returns the sales price for the item id and the qty specified.createSO(): creates a sales order and returns the sales id.deleteSalesLine(SalesId _salesId. e. qty and sales id. 2. CSharp_SalesOrder. d. CSharp_SalesOrder.Development IV in Microsoft Dynamics® AX2009 In Microsoft Dynamics AX 2009 The POS executable calls the following class methods. b. a. qty _qty. SalesOrderIntegration. b. CSharp_SalesOrder. SalesOrderIntegration. Class SalesOrderIntegration a. salesId _SalesId): Creates a sales line for the specified item. Class CSharp_SalesOrder which is used in conjunction with creating and deleting sales orders. 3.Chapter 4: Business Connector Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 4-21 . 2. 3. in Visual Studio how would you create a new instance of the SalesFormLetter Microsoft Dynamics AX 2009 class? MODEL ANSWER: //Visual Basic Dim salesFormLetter As AxaptaObject Dim axapta1 As Axapta Dim className As String axapta1. MODEL ANSWER: The Business Connector enables external applications to interact with Microsoft Dynamics AX 2009 Application Object Server instances. How is debugging through the Business Connector enabled? MODEL ANSWER: Enable debugging on the AOS configuration. What is the Business Connector Proxy User account used for? MODEL ANSWER: It is used to enable the Business Connector to "act-onbehalf" of Microsoft Dynamics AX users who cannot be fully authenticated 4.Development IV in Microsoft Dynamics® AX2009 Solutions Test Your Knowledge 1.NET language. 5.Logon("".NET connector into the Global Assembly Cache after it is installed? MODEL ANSWER: No. Enable debugging on the Client configuration.CreateAxaptaObject(className) 4-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 6. "") className = "salesFormLetter" salesFormLetter = axapta1. Do you need to register the . Using a . What is the purpose of the Managed Classes in the . 2.NET Business Connector? MODEL ANSWER: They expose public methods that can be called to interact with Microsoft Dynamics AX. Open an instance of the Microsoft Dynamics AX debugger. "". It is registered automatically during installation. Describe the purpose of the Business Connector. Set Debug mode to When Breakpoint. "". Introduction The Common Runtime Language (CLR) Interoperability (shortened to Interop) feature enables X++ developers to add CLR assemblies to the AOT and to write X++ code that interoperates with objects in these assemblies. Add assemblies to the Global Assembly Cache. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-1 . Secure CLR Interop code. Consume external web services from X++ code. to leverage functions already available in the operating system or external applications. Understand how and where the use of DLL's is implemented in Microsoft Dynamics AX 2009. This lesson describes how to reference assemblies in Microsoft Dynamics AX 2009 and leverage them in X++ code. Write X++ code that interacts with managed code in external applications. This provides access to a vast array of prefabricated code.Chapter 5: CLR Interoperability CHAPTER 5: CLR INTEROPERABILITY Objectives The objectives are: • • • • • • Reference Common Runtime Language (CLR) assemblies in the Microsoft Dynamics® AX 2009 Application Object Tree (AOT). Select Add Reference. The assemblies often take the form of DLL files. a developer must first create a reference to the assembly in the Microsoft Dynamics AX 2009 AOT.Development IV in Microsoft Dynamics® AX2009 Reference CLR Assemblies in the AOT CLR assemblies contain managed code designed to be consumed by other applications. expand the References node. 5-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 3. Right-click AOT > References.Reference a New Assembly in the AOT Use the following procedure to reference a new assembly in the AOT: 1. To see the assemblies already referenced in the AOT. To use the managed code within an assembly in X++ code. you are not restricted to just these assemblies.1 THE REFERENCES NODE ON THE AOT Procedure . FIGURE 5. 4. The following figure illustrates the sys layer assembly references. 2. The Add Reference form appears. Click the Browse… button to select an assembly from another location. The Add reference form contains all the assemblies that have been registered in the Global Assembly Cache (GAC). However. to retain the referenced location in the AOT.Office.Interop. Be sure to install the assemblies in the same location on each machine. Microsoft® Visual Studio® .NET and other development tools provided in the .NET Framework SDK can assign strong names to an assembly. The following new assemblies are referenced in the AOT: Microsoft.Excel which are both available from the GAC list.Word and Microsoft. which contains the names and hashes of all the files that make up the assembly). 6. HINT: Refer to the MSDN on strongly named assemblies for more information.Office. The assemblies in the lower window are added to the AOT by clicking OK.Interop. and production AOS servers. 7. A strong name consists of the assembly's identity (the simple text name.Office. After selecting all the assemblies. For example: C:\Program Files\Microsoft Dynamics AX\50\Client\Bin Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-3 . Assemblies with the same strong name are expected to be identical. Adding Assemblies to the Global Assembly Cache or Client The Global Assembly Cache (GAC) is a directory in the Windows Server file system. The GAC is located in the following path: \%winnt%\assembly Install assemblies available to all clients into the GAC on each Application Object Server (AOS) servicing the clients. IMPORTANT: Code using assemblies installed on the AOS must be set to run on the server. Click the Select button to include one or more assemblies in the lower window.Word and Microsoft. version number.Interop. test.Office. The assemblies are visible in the AOT > References node. not on the client. using the corresponding private key. a public key and a digital signature. and culture information (if provided)). click OK. In this example choose Microsoft. to avoid problems that can arise when DLL files are stored in different places by each developer. The GAC enforces that all assemblies installed into it are strongly named.Chapter 5: CLR Interoperability 5. It provides a controlled central repository for all DLL files on a server. across different servers (for example. Alternatively. The recommended location for client assemblies is the bin directory on the client.Excel. Remember to install server assemblies into the GAC on the development. it is possible to install assemblies on each of the client machines. It is generated from an assembly file (the file that contains the assembly manifest. Test and Production servers). the Development.Interop. Mail.MailMessage mailMessage. first reference the assembly in the AOT.Net. attachementCollection. NOTE: CLR assemblies and their contents are case sensitive.Attachment attachment.AttachmentCollection attachementCollection. There are many .Attachment("c:\\myphoto.Net.txt"). attachment = new System. attachementCollection = mailMessage.Net.Mail. System.Mail assembly.Mail.Mail assembly. The following is an example of X++ code which leverages the code in the System.NET. 5-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . custom assemblies can be created in .get_Attachments().Development IV in Microsoft Dynamics® AX2009 Leverage CLR Managed Code Within X++ Code To use the functionality in managed code in an assembly. Alternatively.Add(attachment). One example is the System.Attachment("c:\\myfile.c om").Net.NET assemblies available in the Windows operating system. System. attachment = new System.Net.jpg").Net. to create an email with a multiple attachments: System.Mail.Mail. mailMessage = new System.MailMessage("me@contoso. which provides code to send emails.Add(attachment). Referenced assembly names can then be used in X++ code. .Net.Mail. attachementCollection.com".Net. as described in the previous section."you@contoso. .sayHello().Chapter 5: CLR Interoperability Refer to this example of a small . hw = new DemoCLR. The following X++ code example leverages the . info(s).NET assembly: //.add(18. it could be added to the References in the AOT.29). str s. int b) { return a + b. int i. } } } If this assembly was available as a DLL file. } When JobCLR() is run. Once referenced.HelloWorld hw. } public int add(int a.HelloWorld().NET code in the previous assembly: //X++ code static void JobCLR(Args _args) { SampleCLR. s = hw. info(int2str(i)). call the assemblies contents directly in X++ code. the result is two lines in the Infolog: • • Hello CLR Interop World! 47 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-5 .NET code namespace SampleCLR { public class HelloWorld { public string sayHello() { return "Hello CLR Interop World!". i = hw. Xml.assert().xml').. which is an enum. xmlDoc. and then X++ code can refer to the web reference like any other native Microsoft Dynamics AX 2009 AOT object. Calling and managing external Web services is done entirely within Microsoft Dynamics AX 2009. To illustrate how to consume a Web service.Development IV in Microsoft Dynamics® AX2009 InteropPermission Class Recall from the Writing Secure X++ Code topic in the Development III course.. This means external Web services can be consumed from X++ code in a similar way to CLR references. the following demonstrations illustrate how to call the Microsoft Live Search Web service. a reference to the Web service must first be created. } Web service references The Microsoft Dynamics AX 2009 programmability model now supports services. 5-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Xml.some xml code here. new InteropPermission(InteropKind::CLRInterop). it can be invoked from X++ and the available methods can be seen using Intellisense. When granting permission to CLR Interop classes. To consume an external Web service from X++. use the InteropKind::CLRInterop value.. After creating a reference to the Web service.. The CLR Interop classes are classified as "secured" APIs.XmlDocument xmlDoc. A web reference is created in the AOT. They have a permission class called InteropPermission. The following is an example of CLR Interop code with a permission class: public server void JobCLRPermissions(Args _args) { System. //. The new method of this class requires an InteropKind type parameter. xmlDoc = new System. that classes categorized as "secured" require a permission class to run. This feature is useful for pulling real-time information from sources published on the web.XmlDocument().Save('c:\\test. . Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-7 . In the Service description field.NET assembly that is created and the name of the directory that contains the generated Web reference files.com/webservices.asmx?wsdl. In the WSDL URL field. . 2.NET code namespace field.NET namespace such as WindowsLiveSearch. In the . 7.asmx?wsdl o http://localhost/WebServices/SalesTableservice.search. From the Tools menu select Development tools. select Application Integation Framework. This field can contain a path to the local file system.search. and then select Add service reference.msn. 5. enter the location of the service WSDL. http://soap.or In the AOT. The following screen appears: FIGURE 5.msn.com/webservices.2 ADD SERVICE REFERENCE DIALOG 3. a file share. and then click Add service reference. enter a unique name for the . This name is used as the name of the . right-click the References node. Click OK. enter a description for the Web service. The following are valid formats for the WSDL URL: o http://soap. The Web reference is generated and the proxy files are saved to the following directory: <Microsoft Dynamics AX Install Directory>Application\Appl\DynamicsAx\ServiceReferences\<Web Service Name>. In the Reference name field. or an Internet address.asmx?WSDL o c:\WebServices\SalesTableService.Chapter 5: CLR Interoperability Demonstration .Create a reference to the Web service Perform the following steps to create a reference to the Web service: 1. 6. enter a unique name for the Web service without spaces or special characters such as LiveSearch.wsdl 4. This is the namespace in which the generated proxy assembly and other files will reside. 3. Set the Name property to LiveSearchTest. searchResults = LiveSearchTestClass:: searchLive("Microsoft Dynamics AX 2009"). This method creates the source request and puts it in an array. // Display the search results. 2)). Right-click the class and select New Method. Set the RunOn property to Server. WindowsLiveSearch. } 6.assert(). navigate to the Classes node. info(conpeek(searchResults. try { new InteropPermission(InteropKind::ClrInterop). // Call the method to issue the search with the search criteria. public static WindowsLiveSearch. conpeek(searchResults.SourceRequest[] getSourceRequestArray() { WindowsLiveSearch. // This will search for string "Microsoft Dynamics AX 2009".. Right-click the new class and select Properties. In the AOT.SourceType sourceType. Replace the method with the following code in the code editor. 5. public static void main(Args _args) { Container searchResults.%1". 1))). Replace the method with the following code in the code editor. Right-click the class and select New Method. info(strfmt("Total # of hits.Consume a web service from X++ Perform the following steps to consume a Web service from X++ 1.SourceRequest sourceRequest. 5-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 2.. This adds a main method that calls the search service with a search string and displays the results in an Infolog window.Development IV in Microsoft Dynamics® AX2009 Demonstration . .SourceRequest[] array. WindowsLiveSearch. right-click and select New Class. int i. 4. WindowsLiveSearch. Replace the method with the following code in the code editor.Chapter 5: CLR Interoperability // Create the source request and designate the type // of search.SearchResponse searchResponse.SourceRequest[1]().MSNSearchPortTypeClient searchService. WindowsLiveSearch. resultsLength. new InteropPermission(InteropKind::ClrInterop). // Create the search request.SourceType::Web. searchRequestObj = new WindowsLiveSearch.SourceResponse sourceResponse. try { searchResultBuff = new TextBuffer(). resultsArray. array. // Add the source request to an array. url.SourceRequest().SourceResponse[] sourceResponseArray. This is the method that calls the Live Search Web service and returns the search results in a container. return array.SearchRequest searchRequest. WindowsLiveSearch. } catch(Exception::CLRError) { throw error(AifUtil::getClrErrorMessage()). ClrObject sourceRequestArray. array = new WindowsLiveSearch.SetValue(sourceRequest. totalHits.assert(). 0). str title. ArrayIdx idx1. sourceRequest = new WindowsLiveSearch. WindowsLiveSearch. WindowsLiveSearch. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-9 . // Replace this string with your Application ID. TextBuffer searchResultBuff. sourceType = WindowsLiveSearch. idx2. } } 7. description.Result searchResult. . Right-click the class and select New Method.SearchRequest(). int srcResponseLength. sourceRequest. public static container searchLive(str searchQuery) { #File WindowsLiveSearch.set_Source(sourceType). searchRequestObj. searchResultBuff.GetValue(idx1). resultsLength = resultsArray.get_Results(). searchResultBuff.MSNSearchPortTypeClient(). url = searchResult. and URL and appends // it to the search results.appendText(#delimiterCRLF).get_Title().GetValue(idx2). resultsArray = sourceResponse.Development IV in Microsoft Dynamics® AX2009 searchRequestObj.get_Total()). description. searchRequestObj. searchRequestObj.NET array so start at zero. searchResultBuff. searchRequest = searchRequestObj.get_Length(). searchRequestObj.get_Length().NET array so start at zero. // Gets the title. sourceRequestArray = LiveSearchTestClass::getSourceRequestArray(). searchResponse = searchService.get_Url().appendText(#delimiterCRLF).appendText(title). searchResultBuff.set_CultureInfo("en-us").get_Description().set_Requests(sourceRequestArray). //Create the service and call it. searchResultBuff.appendText("-------------------- 5-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . title = searchResult.Search(searchRequest). totalHits = ClrInterop::getAnyTypeForObject( sourceResponse. // Iterating through a .appendText(description). for(idx1=0. idx2 < resultsLength . sourceResponseArray = searchResponse.appendText(#delimiterCRLF). idx1 < srcResponseLength . idx2++) { searchResult = resultsArray. searchService = new WindowsLiveSearch.set_Query(searchQuery).get_Responses(). srcResponseLength = sourceResponseArray. idx1++) { sourceResponse = sourceResponseArray.set_AppID("YOUR_LIVESEARCH_APP_ID"). // Iterating through .appendText(url). // Iterate through the search results. searchResultBuff. description = searchResult. for(idx2=0. searchResultBuff. The search results should appear in an Infolog window as shown in the following figure. FIGURE 5. Compile the class and Run the main method. searchResultBuff.Chapter 5: CLR Interoperability -------------------------------------------").getText()]. return [totalHits. } } CodeAccessPermission::revertAssert(). // Convert the buffer to a string and add it to a container.3 INFOLOG WINDOW WITH SEARCH RESULTS Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-11 . } } You should now have a class named LiveSearchTest with three methods: • • • getSourceRequestArray main SearchLive 8. } catch(Exception::CLRError) { throw error(AifUtil::getClrErrorMessage()). searchResultBuff.appendText(#delimiterCRLF). dll. One method used to view a list of functions in a DLL is the dumpbin. Call the function.txt”). fileSize. Analyze the getFileSize() method to understand how to implement a specific function. Each DLL has one or more functions that can be called. } This method uses two other methods to obtain the desired result. passing the DLL object and the name of the function as a parameter into the new method. as documentation or definition files are often not installed with the DLL. and others. This implements useful functions from kernel32.dll. It is not always easy to find all the available functions and how to use them. Use the following line in a command prompt to obtain a list of functions in Kernel32. or which window is currently active.dll dumpbin /exports c:\windows\system32\kernel32. Set the type of all parameters that function accepts. They are often used to find information about the current environment.dll.dll and user32. • • • 5-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Set the type of the return value.NET. passing the name of the DLL as a parameter into the new method. fileSize = winAPI::FileSize(“c:\\myfile. Declare and instantiate an instance of the class DLLFunction.Development IV in Microsoft Dynamics® AX2009 Implementing a DLL A Dynamic Link Library (DLL) is a collection of small Windows programs that can be called upon to complete a particular function. MSDN describes some of the functions available in a few main Windows DLL's.dll The best example of using a DLL within Microsoft Dynamics AX 2009 is the WinAPI class. • • Declare and instantiate an instance of the class DLL.exe program. user32. For example: { int . such as the amount of free space on a disk. such as Kernel32. This is shipped with Microsoft® Visual Studio® . so keeping the new form open together with the customer form. Create a new form called CustTransGraph. Add a new Chart Object type ActiveX control to the design and change the following properties: o Name: designGraph o AutoDeclaration: Yes o Width: 750 o Height: 375 4.dll. 2. Add CustTable to the data source. where the x-axis is time.Using ChartFX DLL in a form Perform the following steps to use ChartFX DLL in a form: 1. and the z-axis is customers. This enables a high-quality graphical representation of data on forms. means a new row appears every time you highlight a new customer. Override the form's init method and add the following before super(): #MACROLIB.Chapter 5: CLR Interoperability ChartFX Another example of using DLLs in Microsoft Dynamics AX 2009 is the use of ChartFX. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-13 . the new customer's transactions are added to the graph. Declare the form variable as follows: Graphics graphData 5. the y-axis is customer balance. Example . As a result.ChartFX . Follow this example: The following example uses customer transactions in a graph. This form is dynamically linked to the CustTable. 3. 2. //Title X-Axis "Amount". qbd.AmountMST).2). //ExtStyle 7. custTrans. //Width 375. } 8. Add the following after super(): graphData = graphics::newGraphicsTitlesLayout( designGraph. 9.2. custTrans. queryRun.2. //Title Z-Axis #Bar | /*#CT_SHOWVALUES |*/ #CT_CLUSTER | #CT_3D | #CT_TOOL | #CT_SHOWZERO | #CT_LEGEND.custTrans.AccountNum)). Override the executeQuery method on the datasource custTable with the following code: public void executeQuery() { Query QueryBuildDatasource QueryRun CustTrans . //Title Y-Axis "Customer". } graphData. Add this menu item to the button group on the custTable form. Create a display menu item for the form.value(SysQuery::value(custTable. 5-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . //ActiveX control 750. qbd. queryRun = new QueryRun(query). accountNum)).addDataSource(tablenum(CustTrans)).2. //Style #CTE_STEPLINES. query = new Query(). //Height "Customer transaction". graphData. //ExtType 0). super(). //Title "Date". //Type #CS_ALL.get(tablenum(custTrans)).loadData( date2str(custTrans.TransDate. qbd = query.AccountNum.showGraph().Development IV in Microsoft Dynamics® AX2009 6.next()) { custTrans = queryRun. while (queryRun.123.addRange(fieldnum(CustTrans. This lesson demonstrated how to: • • • • Reference CLR assemblies in Microsoft Dynamics AX 2009 AOT Add to the Global Assembly Cache Write X++ code that interacts with managed code in external applications Use DLL's within X++ code.4 FORM USING A DLL FILE TO RENDER THE CONTENTS OF AN ACTIVEX CONTROL Summary The Common Runtime Language (CLR) Interoperability (shortened to Interop) feature enables X++ developers to add CLR assemblies to the AOT and to write X++ code that interoperates with objects in these assemblies. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-15 .Chapter 5: CLR Interoperability Clicking the button for a customer in the custTable form opens a form similar to the following (provided some customer transactions exist): FIGURE 5. classes. What code do you use. How do you make CLR Interop assemblies visible to Microsoft Dynamics AX 2009 X++ code? 2.Development IV in Microsoft Dynamics® AX2009 Test Your Knowledge 1. Are CLR Interop assemblies. to provide Code Access Security permission to a CLR Interop class? 5-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and methods case-sensitive when referenced in X++ code? 3. b. 6.NET code namespace _____ 3. c. What is used as the name of the . to its description. Service description a. Which class contains multiple methods.dll objects to communicate with the Windows environment? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-17 .NET assembly that is created and the name of the directory that contains the generated Web reference files.Chapter 5: CLR Interoperability 4. Which node on the AOT are Web service references found? 5. WSDL URL _____ 2. . using the kernel32.dll and user32. d. _____ 1. Where the generated proxy assembly and other files will reside. Reference name _____ 4. Identifying text for the Web service. The location of the Web service. Match the following properties of a Web service reference. com Need a Little Help? • • • Use the InteropPermission class and InteropKind::CLRInterop enum to satisfy Code Access Security. Loop through the EmplTable to retrieve all employee names and email addresses. System.com and that the SMTP server is smtp.MailMessage. Use the System. You can assume the email address of the sender is
[email protected] .Net.Net.Mail.the subject of the email.Mail. Use the System.Mail assembly. Challenge Yourself! • • • • Write a class method that uses CLR Interop code to send a personalized email to every employee in the company. and the contents of the email body.SmtpClient classes.Net.Net. The method accepts two parameters .Mail.abc. Add a line of code to address the recipient personally with "Dear <insert name here>" at the start of the email body.MailAddress and System. • 5-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .CLR Interop Scenario You are required to use CLR Interop code to send personalized mail messages to everyone in the company.Development IV in Microsoft Dynamics® AX2009 Lab 5. com and that the SMTP server is smtp.com Step by Step • • Create a new class.SmtpClient('smtp. System. .Mail. The method accepts two parameters . System. while select Name. The code inside should look like this: void sendPersonalizedEmail(SysEmailSubject _subject. SysEmailContents _contents) { System.SmtpClient smtpClient.Chapter 5: CLR Interoperability Lab 5.Net.abc. • • • • Write a class method that uses CLR Interop code to send a personalized email to every employee in the company.Mail.MailMessage msg.Mail. new InteropPermission(InteropKind::ClrInterop).Net. and a new method within it. EmplTable eT.CLR Interop (Solution) Scenario You are required to use CLR Interop code to send personalized mail messages to everyone in the company.MailAddress adrRecp.Net.the subject of the email. You can assume the email address of the sender is
[email protected](). Email from emplTable { Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-19 .Mail. adrSend. Add a line of code to address the recipient personally with "Dear <insert name here>" at the start of the email body.com'). smtpClient = new System.abc. and the contents of the email body.Net.1 . Net.Mail.MailMessage(adrSend.Net.com'). msg. adrRecp).MailAddress(emplTable.set_Body(_contents). } } 5-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Name) + _subject.Mail. msg = new System.Mail. adrSend = new System. msg. _subject = strfmt('Dear %1.MailAddress('me@abc. emplTable.Send(msg). \n'.Email).Net. smtpClient.set_Subject(_subject).Development IV in Microsoft Dynamics® AX2009 adrRecp = new System. Chapter 5: CLR Interoperability Lab 5.2 . Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-21 .Implementing DLL's Scenario Management wants a graphical way to view data. Challenge Yourself! Create a new form that shows a graph of the balance of a customer over time. Need a Little Help? Follow the ChartFX example to graph the balance of a customer over time. Create a new form that shows a graph of the balance of a customer over time. Step by Step 1. use the balance of the customer on the date of the transaction. 5-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Development IV in Microsoft Dynamics® AX2009 Lab 5.BalancePerDate() to find the balance.2 . However instead of using transaction amount. Follow the ChartFX procedure in the chapter for inspiration. Follow the step-by-step example in training manual.Implementing DLL's (Solution) Scenario Management wants a graphical way to view data. Use CustTable. Chapter 5: CLR Interoperability Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 5-23 . 2. 3. b. 2. Where the generated proxy assembly and other files will reside. They are case sensitive 3. and methods case-sensitive when referenced in X++ code? MODEL ANSWER: Yes. Reference name a 4. Match the following properties of a Web service reference. Service description a. classes. 6. The location of the Web service. using the kernel32.Development IV in Microsoft Dynamics® AX2009 Solutions Test Your Knowledge 1. to provide Code Access Security permission to a CLR Interop class? MODEL ANSWER: new InteropPermission(InteropKind) 4. b 1. 5. . c. What code do you use. How do you make CLR Interop assemblies visible to Microsoft Dynamics AX 2009 X++ code? MODEL ANSWER: You add references to the assembly files in the AOT. What is used as the name of the .dll objects to communicate with the Windows environment? MODEL ANSWER: WinAPI 5-24 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Are CLR Interop assemblies.NET assembly that is created and the name of the directory that contains the generated Web reference files. Which class contains multiple methods.NET code namespace c 3. WSDL URL d 2. to its description.dll and user32. under the References node. Which node on the AOT are Web service references found? MODEL ANSWER: The References node. Identifying text for the Web service. d. Use the LedgerVoucher class and sub-classes. Since these procedures are used regularly but rarely modified. It is also the module that has the least modifications made to it due to the commonality in accounting procedures throughout the world. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-1 . There are two methods to consider when posting transactions to the ledger: 1. it is regarded as one of the most important modules. many modifications to other modules or automation of ledger procedures may require writing code that creates ledger transactions. 2. Use a journal which is more straightforward to use. However. this lesson examines how to use both methods. which is the more direct and controllable route. but does not go into details about how these methods work.Chapter 6: Ledger CHAPTER 6: LEDGER Objectives The objectives are: • • Create ledger transactions using LedgerVoucher Create ledger transactions using a Ledger Journal Introduction All Microsoft Dynamics® AX 2009 modules interface with the General Ledger module in some way. the Systems Developer. Instantiate the LedgerVoucher class. The End method creates ledger transaction records from the temporary postings. He has been asked to evaluate the best method to achieve this and to write a program that can be used during the data migration. It checks that the posting is correct and that the voucher balances.an equal credit and debit side. Possible rounding of postings is carried out if necessary. remember that all vouchers in Microsoft Dynamics AX 2009 must balance . Each LedgerVoucherObject holds transactions in temporary storage (a list array) until the end() method is called. is developing a process to import opening ledger balances for a new company that is to be migrated to Microsoft Dynamics AX2009. Each transaction in each voucher is contained in a LedgerVoucherTransObject. LedgerVoucher When using LedgerVoucher. Each voucher in the LedgerVoucher is contained in a LedgerVoucherObject. Once these lists are completed. The LedgerVoucher class holds all the vouchers in temporary storage (a list array) until the End method is called. 6-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . The idea is to build up a list of vouchers to be posted and to build up a list of transactions within each voucher.Development IV in Microsoft Dynamics® AX2009 Scenario Isaac. The procedure is: 1. A structure is built as follows: Posting (LedgerVoucher) • Voucher (LedgerVoucherObject) o o • Trans (LedgerVoucherTransObject) Trans Voucher o o Trans Trans LedgerVoucher harnesses the posting of multiple vouchers at one time. All transactions on one voucher must be posted on the same date. the system posts them all to the General Ledger module at once. LedgerVoucherPostExPosting. Instantiation of LedgerVoucher LedgerVoucher can be instantiated as follows: LedgerVoucher::newLedgerPost(_detailSummary. _voucherSeriesCode – Number sequence code used for numbering the vouchers. LedgerVoucherPost. and voucher. _transactionLogText. The method constructs one of the sub-classes. _sysModule. loop over the transactions to instantiate LedgerVoucherTransObject classes. when the voucher has already been used. if a vendor invoice approval journal needs to bypass some checks. for example. [_transactionLogType. date. 3.Chapter 6: Ledger 2.it stamps the ledger transaction with the code that was used. _posting]). This does not automatically allocate the voucher number . _approveJournal. • • • Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-3 . LedgerVoucherPostApprove. LedgerVoucherPost is used for normal posting to the general ledger. _sysModule – System module from which transactions are made. A detailed description of these steps follows. For each voucher. Loop over the vouchers to instantiate LedgerVoucherObject classes. LedgerVoucherPostApprove is used when the final posting is approved by the user. _voucherSeriesCode. for instance. This value can also be used for posting transactions from custom modules. currency. and register these in the LedgerVoucher class. The parameters are: • _detailSummary – Value specifying either summary or details. and register these in the LedgerVoucher class. Specifying summary results in summarizing the amounts per account. LedgerVoucherPostExPosting is used in the production module to reduce the number of transactions created during production order updates. _transactionLogType – Used in the audit trail (optional). _acknowledgementDate]). (Optional) _documentNum – Use to stamp a document number onto a transaction. For all available OperationTax codes. Instantiation of LedgerVoucherObject LedgerVoucherObject can be instantiated as follows: LedgerVoucherObject::newVoucher(_voucher. _operationsTax. _approveJournal – True returns LedgerVoucherPostApprove (optional). _sysModule. _transDate – Date of transaction. Default value LedgerTransType:None. _tmpVoucherMap. _documentDate. The default value is OperationsTax::Current. This value can also be used for posting transactions from other modules. To view all available ledger transaction types.Development IV in Microsoft Dynamics® AX2009 • • • _transactionLogText – Used in the audit trail (optional). _posting – False returns LedgerVoucherPostExPosting (optional). _ledgerTransType. _correction. _documentNum. The default value is the current date. (Optional) _sysModule – System module from which transactions are made. The parameters are: • • • _voucher – Number of the voucher. (Optional) _operationsTax – Indicates the type of operation tax used when posting a transaction. [_transDate. (Optional) _correction – Indicates whether the voucher is a reversing entry (credit note). (Optional) • • • • 6-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . (Optional) _LedgerTransType – Ledger transaction type. refer to base enum LedgerTransType. look in the base enum OperationsTax details. _sourceRecId.AddVoucher(ledgerVoucherObject). _amountMST]) Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-5 . LedgerVoucherTransObject::newCreateTrans( _ledgerVoucherObject. Instantiation of LedgerVoucherTransObject There are many other constructor methods for this class used in different situations. (Optional Italy country specific functionality) Registering the LedgerVoucherObject with the LedgerVoucher A LedgerVoucherObject can be added to LedgerVoucher as follows: ledgerVoucher. _projLedger. _ExchRatesTriangulation. _exchRate _exchRateSecond. The newCreateTrans() method is most commonly used.Chapter 6: Ledger • • • _documentDate – Use to stamp a document date onto a transaction. (Optional) _tmpVoucherMap – Use during posting when it is required that all voucher numbers are continuous (Optional) _acknowledgementDate – Date when the company gains knowledge of the transaction. [_LedgerQty. _dimension. _amountCur. _markBridging. _currencyCode. _ledgerPostingType. _ledgerAccount. It has already been added to the LedgerVoucherObject. _SourceRecid – The record ID of the originating record (for example.Development IV in Microsoft Dynamics® AX2009 • • • • • • • • • • _ledgerVoucherObject – The object containing the corresponding voucher. If calculation has already been made. currency calculation will be made. ledgerVoucherTransObject. look in base enum LedgerPostingType details. then specifying the amountMST (monetary standard amount) increases performance. For all available posting types. This adds the transaction initiated in the newCreateTrans() method to the posting. _amountCur – The amount in currency (this is converted to MST in the newCreateTrans method). Registering the LedgerVoucherTransObject with the LedgerVoucher ledgerVoucher. the exchange rate in the system for the transaction date is used. _currencyCode – Currency in which transactions are made. If blank. _transTxt .addTrans(ledgerVoucherTransObject). (Optional) exchRatesTriangulation – Can override currency's setting for Euro Triangulation. _LedgerQty – The quantity. • • • • Providing the Transaction Text Add transaction text to a transaction by using the following code. if any. _ledgerPostingType – A type of posting. _dimension – The transaction dimension. (Optional) _projLedger – Use in the project module to create project-specific transactions from the ledger transactions. _ledgerAccount – The ledger account number on which transactions will be made. If blank. (Optional) _amountMST – If not specified.parmTransTxt(_transTxt).Transaction text. SalesLine). (Optional) _exchRateSecond – Use to specify an exchange rate for the secondary currency (if used). (Optional) _markBridging – No longer used. the exchange rate in the system for the transaction date is used. (Optional) _exchRate – Use to specify an exchange rate. 6-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . This was used in a journal to mark a transaction posted to a temporary bridging account. attached to the transaction. numSeq = NumberSeq::newGetNumFromCode(NumberSequenceCode). LedgerVoucherTransObject ledgerVoucherTransObject. The runJournalPost method exemplifies posting from a journal. user input or a calculation. LedgerVoucher.Create Voucher ledgerVoucher = ledgerVoucher::newLedgerPost(DetailSummary::Summary. Usually these would be obtained from parameters. // Postage amountMST amountMST amountMST . Dimension NumberSeq NumberSequenceCode 'Acco_18'.end(). These tables store balances by period and by dimension. The runSalesPost method exemplifies posting a sales order with its lines. dimension. the whole posting can be committed.Chapter 6: Ledger Finalizing the Posting When all the vouchers and transactions have been added. Example: Using LedgerVoucher The following job posts a petty cash disbursement for a payment for a stapler and some stamps. Final checks are made and the transactions are finalized. static void ExampleLedgerVoucher(Args _args) { LedgerVoucher ledgerVoucher. Also. accountNumOffsetOffice = accountNumOffsetPostage = amountPetty = 55. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-7 . //First Step . A coding example using the ledgerVoucher class is provided in the application as the TutorialLedgerVoucher class. numSeq. The accounts and amounts are set in the variable declaration. amountOffice = 50. ttsbegin. ledgerAccount // Petty cash ledgerAccount '606300'. NumberSequenceCode = accountNumPetty = '110180'. // Office Supplies ledgerAccount '606500'. LedgerBalancesTrans and LedgerBalancesDimTrans are updated. amountPostage = 5. AddVoucher(LedgerVoucherObject::newVoucher(nu mseq. 6-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . amountPetty. ledgerVoucherTransObject = LedgerVoucherTransObject::newCreateTrans( ledgerVoucher. //Create the first Transaction .NumberSequen ce) . // Ledger Account dimension. ReciID // // Amount 0. LedgerPostingType::LedgerJournal.this is the credit side of the transaction (-55) //The other two DR transactions should total to the CR otherwise it won't post.Development IV in Microsoft Dynamics® AX2009 SysModule::Ledger. // ledgerVoucherTransObject.findLedgerVoucherObject(). Sysmodule::Ledger.num(). TableId 0).parmTransTxt("Petty cash disbursement"). LedgerTransType::None)). LedgerPostingType::LedgerJournal. accountNumOffsetOffice. ledgerVoucher.findLedgerVoucherObject(). dimension. today(). //Second Step .addTrans(ledgerVoucherTransObject). CompanyInfo::standardCurrency(). //Create the second Transaction ledgerVoucherTransObject = LedgerVoucherTransObject::newCreateTrans( ledgerVoucher.Create Voucher Number ledgerVoucher. LedgerParameters::numRefLedgerExchAdjVoucher(). accountNumPetty. ledgerVoucher.Chapter 6: Ledger CompanyInfo::standardCurrency(). LedgerPostingType::LedgerJournal.used().To Balance Voucher and Close ledgerVoucher.addTrans(ledgerVoucherTransObject). accountNumOffsetPostage.findLedgerVoucherObject(). // TableId 0). // ReciID ledgerVoucherTransObject. //Last Step . ledgerVoucher.parmTransTxt("Stamps").end(). // ReciID ledgerVoucherTransObject. } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-9 . amountOffice. numseq. // TableId 0). amountPostage. dimension.addTrans(ledgerVoucherTransObject). 0. ttsCommit. // Amount 0. //Create third Transaction ledgerVoucherTransObject = LedgerVoucherTransObject::newCreateTrans( ledgerVoucher. CompanyInfo::standardCurrency().parmTransTxt("Red stapler"). The journal framework consists of a number of tables. A more detailed description of the steps involved follows. or one line per transaction. This could be one line per pair of balanced transactions. LedgerJournalName contains default data for a specific journal type. Within these groups. All error checking and posting are performed simultaneously without additional programming. When using a Journal lines table. 2. Using journals requires less work when grouping the transactions and vouchers appropriately. The steps used to create a journal are: 1. there are many types that use the same tables. and forms designed so that all journals behave similarly and have the same look and feel across modules. 6-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . There can be one or more lines per journal. LedgerJournalTable. Post the journal. Create a journal table record or use an existing one. This checks the journal before posting. and LedgerJournalTrans. and Project.Development IV in Microsoft Dynamics® AX2009 LedgerJournal Journals are the easiest way of posting in Microsoft Dynamics AX2009. In the ledger module. but differ slightly in what information they require and the end result. Ledger Journal structure The three main journal groups in Microsoft Dynamics AX2009 are Ledger. There is one record per journal. This step is left out if the journal is to be checked by the user before posting. the tables used are LedgerJournalName. classes. This is often useful during data migration. fill it in with data and call upon Microsoft Dynamics AX2009's method for posting the journal. There can be more than one LedgerJournalName per type. 3. Inventory. LedgerJournalTable is the header record for the journal. Create lines for each transaction to be posted. LedgerJournalTrans contains data used to create the individual transactions that will be posted. Journals also present the possibility of not posting immediately but allowing the user to verify what is to be posted. maps. ledgerJournalTable. ledgerJournalTable. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-11 . use a journal name record to get the default data. Parameters for this method are: • _ledgerJournalTable – Record in LedgerJournalTable representing the journal which should be posted.insert(). because transactions are assigned to one of the journals.PayJournal is a new field of type LedgerJournalNameId. for example. Notice it handles the creation of the journal number. Use a journal name of an appropriate type. which is the primary key defining the relationship between the journal table and the lines. Any errors that show up while posting are displayed by validating a journal through the journal lines form. Where SalesParameters::find(). Two fields of interest when creating journal lines are: LedgerJournalTrans.JournalNum which is mandatory. and LedgerJournalTrans. check and post the journal. Posting Journals After transactions are created in the journal. Creating Lines All transactions must be posted in the journal lines table. Fill the record with data and then insert it.JournalName = SalesParameters::find(). Fill in other mandatory fields in the journal lines table as necessary. Look at Extended Data Type (EDT) LedgerJournalNameIdApproval for an example of how to create an EDT for a journal name of a specific type. Each journal type requires different fields and field combinations to be correctly entered. LedgerJournalTrans.CurrencyCode.Name = 'Payment Journal' ledgerJournalTable. The easiest way is to create an instance of this class using newLedgerJournalTable static method and then run the class.Voucher which is the transaction voucher number.PayJournal. Look in the table method ledgerJournalTable. and the initializing from LedgerJournalName.Chapter 6: Ledger Creating the Journal To create a new journal. use the LedgerJournalCheckPost class.Insert(). ttsbegin.CurrencyCode = 'EUR'. offsetAccount = '601500'.insert(). ledgerJournalTrans. NumberSeq numberseq. ledgerJournalTable.Development IV in Microsoft Dynamics® AX2009 • _post – NoYes parameter for specifying if it checks only a journal or completes both checking and posting.ExchRate = Currency::exchRate(ledgerJournalTrans. LedgerJournalCheckPost ledgerJournalCheckPost. but with different batch numbers.initFromLedgerJournalName(). _transferErrors – NoYes parameter for transferring vouchers with errors to another journal. // Find a ledgerJournalName record select firstonly LedgerJournalName where LedgerJournalName. ledgerJournalTable.voucher().CurrencyCode). ledgerJournalTrans. LedgerJournalTable ledgerJournalTable. amountCur = 102. LedgerJournalNameId = 'GenJrn'.JournalName == LedgerJournalNameId. //Created the ledgerJournalTable ledgerJournalTable.VoucherS eries). LedgerJournalTrans ledgerJournalTrans. The default value is No. Yes indicates that all vouchers with errors are transferred into a new journal with the same name and description.Name = 'Hotel'. ledgerJournalTable. static void ExampleLedgerJournal(Args _args) { LedgerJournalName LedgerJournalName. numberseq = NumberSeq::newGetVoucherFromCode(ledgerJournalName. //Generate the transaction line ledgerJournalTrans.JournalName = LedgerJournalName.JournalNum = ledgerJournalTable. • Example: Using Ledger Journal The following is an example of creating a journal with one journal line and then posting the journal. BankAccountID = 'EUR OPER'. ledgerJournalTrans. LedgerJournalNameId BankAccountID ledgerAccount amountCur . posting is done.Voucher = numberseq.JournalName.JournalNum. Yes indicates that after checking. 6-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . ttscommit. ledgerJournalTrans.Txt = 'Room Stay'. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-13 . ledgerJournalTrans.JournalNum)).OffsetAccount = offsetAccount.AccountNum = BankAccountID.TransDate = today().Chapter 6: Ledger ledgerJournalTrans. ledgerJournalTrans.ledgerJournalTable. ledgerJournalTrans.run(). This lesson provides a basic understanding of: • • The concepts behind the two main methods of posting transactions. The best method to use depending on the situation.OffsetAccountType = LedgerJournalACType::Ledger. ledgerJournalTrans. } Summary This lesson introduces and explains two methods for posting transactions to the ledger table. Using a journal.insert(). info(strfmt('Journal Id: %1'.NoYes::Yes). ledgerJournalTrans. The two methods are: • • Using the LedgerVoucher class and sub-classes. ledgerJournalCheckPost. //Post the Journal ledgerJournalCheckPost = ledgerJournalCheckPost::newLedgerJournalTable(ledgerJournal Table.AmountCurCredit = amountCur. ledgerJournalTrans.AccountType = LedgerJournalACType::Bank. Development IV in Microsoft Dynamics® AX2009 Test Your Knowledge 1. The transaction log type and transaction log text are used in the ________ trail. 3. Which class holds a list of transactions that are going to be posted for a particular voucher? 2. Which table stores default values that initialize a LedgerJournalTable record? 6-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Chapter 6: Ledger 4. Which class posts a journal? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-15 . 2. Create a journal header. 6-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Create a line for the offset account entered by the user for the inverse of the total amount of the balances imported. Challenge Yourself! 1. Prompt for: o offset account o posting date o filename 3. 2.1 – Create and Post a Ledger Journal Scenario During data migration when implementing Microsoft Dynamics AX2009 for a new customer. Create a method to generate the journal header. 4. o Find the first journal name of type = daily. Set a class variable to store the voucher number. Read in the file and create a journal line for each account and balance. The voucher number is obtained from the number sequence attached to the journal name record. Step by Step 1. o Insert the JournalTable record.Development IV in Microsoft Dynamics® AX2009 Lab 6. o Set the journal name of the JournalTable record = journal name of JournalName record. but remember to ensure that it balances. Write a program that imports these opening balances into a journal and optionally posts it automatically. Prompt for offset account. and filename. Post the journal. Create a new class that extends RunBaseBatch. posting date. 3. 5. 4. One voucher can be used for all transactions. you need to enter opening balances for the general ledger. and the accounttype. 6. Call LedgerJournalCheckPost (use static method newLedgerJournalTable). o Set the voucher number. o For each line. Create a method to generate the journal lines. o Read the file. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-17 . o Accept the account number and amount as parameters. the amount. o Set the account number. o Create a line for the negative of the total amount of the transactions for the offset account specified in the prompt. to post the journal.Chapter 6: Ledger 5. call the method to create the journal line. the date. 2. Payments are entered into the register by clicking Payment on the POS form which opens the POSPayment form. 2. Create a method to create the journal header. 5. At any cash register. Set the journal name of the JournalTable record = journal name of JournalName record. 6-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Challenge Yourself! 1.Development IV in Microsoft Dynamics® AX2009 Lab 6. This is posted to the ledger. d. The voucher number is obtained from the number sequence attached to the journal name record. 6. an End of Day routine counts the actual cash taken. 3. In the next lesson you post the payments to the holding account and the AR sub-ledger. Total up the amount entered during that day for that register. and any difference between the counted amount and the recorded amount is posted to a specified ledger account.End-of-day routine Scenario This is a part of the Point-of-Sale Project. Set a class variable to store the voucher number. Prompt for the RegisterId of the register to process. Post the counted amount to the bank account. Post the inverse of the posted amount to the register holding account. 8. Post the difference to the register difference account.2 – POS . Flag the payment lines as having been posted at EOD. Calculate the difference between the counted amount and the posted amount. Write this routine. Create a new class that extends RunBaseBatch. 7. 4. e. Prompt for the counted cash amount. 9. Prompt for: o Register Id o Counted amount b. In a live application this would also open the cash drawer. Insert the JournalTable record. c. Find the first journal name of type = daily. Prompt for the cash or bank account and the difference account. Step by Step 1. a. b. e. Update the register transactions to reflect that they have been posted. Call LedgerJournalCheckPost (use static method newLedgerJournalTable). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-19 . the date. to post the journal. Create a journal line for the inverse of the total amount posted for that register for the register holding account. Create a method to create the journal lines.Chapter 6: Ledger 3. Set the voucher number. Find the Register table record for the specified register. Set the account number. 5. Create a journal line for the difference between the posted amount and the counted amount for the difference account specified in a parameter. g. Accept the account number and amount as parameters. d. f. 4. Create a journal line for the total counted amount for the bank account. c. the amount. and the accounttype. a. Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. 2. 3. 6-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . MODEL ANSWER: The transaction log type and transaction log text are used in the audit trail.Chapter 6: Ledger Solutions Test Your Knowledge 1. Which class posts a journal? MODEL ANSWER: LedgerJournalCheckPost Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 6-21 . 3. Which table stores default values that initialize a LedgerJournalTable record? MODEL ANSWER: LedgerJournalName 4. The transaction log type and transaction log text are used in the ________ trail. Which class holds a list of transactions that are going to be posted for a particular voucher? MODEL ANSWER: LedgerVoucherObject 2. Development IV in Microsoft Dynamics® AX2009 6-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and issuing and receiving payments. but the basic ideas are similar. Not everything is the same between the two modules. The AR and AP modules are similar in their structure regarding both data dictionary and update procedures. similar constructs and procedures also apply for AP. PurchTableType. and make good use of table maps to reduce the amount of coding needed. The trade modules revolve around buying and selling inventory. and PurchLineType Post and Print Document Updates Post Transactions Use Settlements Use Trade Agreements Introduction The most frequently modified modules in Microsoft Dynamics® AX 2009 are the Accounts Receivable (AR) and Accounts Payable (AP) modules. Recognize that what is true for SalesLine is also true for PurchLine. In this chapter. This is sometimes a rearrangement of the data available to the invoice. For instance. the element that every company modifies is the printed sales invoice. SalesLineType. company-specific data. but is more often a complete redesign that includes additional. where only AR is referenced. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-1 .Chapter 7: Trade CHAPTER 7: TRADE Objectives The objectives are: • • • • • Use SalesTableType. ValidateWrite() is called. SalesLineType is instantiated using the SalesLine. SalesLineType. View the SalesLine. and line types are posted Where postings to ledger are made FIGURE 7.SalesType. ok = ok && this.validateWrite() method: ok = super(). For most sales line types. so SalesLineType. After calling the system validation using super().SalesLineType 1.validateWrite_server(_skipCreditLimitCheck).Type() method calls SalesLineType. For a line type of ReturnItem. SalesLineType.ValidateWrite() is called.1 SALES TABLE TYPE Demonstration . After SalesLineType has been instantiated.contrstruct() which constructs the instance according to the value of SaleLine. PurchTable. 7-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . return ok. the method has been overridden.ValidateWrite() has not been overridden. The SalesLine.Development IV in Microsoft Dynamics® AX2009 TableType and LineType SalesTable. SalesLine. and PurchLine make use of the InventType construct to control: • • • • What values are acceptable What happens when any field values are modified How the different order types.Type() method. View the SalesLineType_ReturnItem.insert().calls SalesLineType.ExpectedRetQty * salesLine. Note that SalesLine.Update(). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-3 . show that they all use the inventType sub-classes.Insert() which calls SalesLineType. After calling super() to provide validation for other line types. SalesLine. For example.CreateLine(). SalesTable.returnJournal() && salesLine. The three table methods that are used: SalesTable.returnJournal()) { // Expected return quantity must not be zero ok = checkFailed("@SYS105646").InitValue(). for instance. These inventType sub-class methods are often called from the system methods on salesLine and salesTable. } if (ok && salesLine. } if (ok && salesLine. ok = checkFailed("@SYS53512").Update(). } return ok. and SalesLine. the method has one additional check to ensure that the quantity of the return line is negative.SalesQty > 0 && salesLine. This can be used when. The examples below show how a sales order and sales order line are created within code.ValidateWrite() method: ok = super(_skipCreditLimitCheck).ExpectedRetQty == 0 && salesLine. meaning that instantiating SalesTableType or SalesLineType is not necessary.Chapter 7: Trade 2.SkipUpdate == InterCompanySkipUpdate::No) { // Quantity of returned items orders must be negative.LineAmount < 0) { //The sign on Quantity and Net amount have to be the same ok = checkFailed("@SYS78848").CreateLine() calls SalesLine. creating sales orders within code.Insert(). if (salesLine. createLine(NoYes::Yes. salesLine.initFromCustTable(). NumberSeq = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId (). salesLine. salesLine.Development IV in Microsoft Dynamics® AX2009 Example: Create a Sales Order static void createSalesTable(CustAccount _custAccount) { SalesTable salesTable. // initFromInventTable NoYes::Yes.numberSequence). salesTable. // Validate NoYes::Yes. // calcInventQty NoYes::Yes.num(). // searchMarkup NoYes::Yes). salesTable. salesLine.insert(). // initFromSalesTable NoYes::Yes. . ItemId _itemId) { SalesLine salesLine.CustAccount = _custAccount.SalesId = NumberSeq. salesTable. .initValue().ItemId = _itemId. } Example: Create a Sales Line static void createSalesLine(SalesId _salesId. salesTable. NumberSeq NumberSeq. salesTable.clear(). // searchPrice } 7-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .SalesId = _salesId. the SalesFormLetter. with one record in SalesParmUpdate per update. Although there are significant differences between what is posted. a delivery note update posts the inventory movement. For example.lowestSalesStatus() shows where this is set.dialog method is called . the procedures to perform the update are similar. The table method SalesLine. The SalesStatus field shows the last sales status posted for the order. and then displays them for final adjustments before the posting takes place. When a user updates an order. To handle this parm tables are used. they are displayed using the SalesEditLines form. For instance. and SalesParmLine. They are populated when the SalesFormLetter. of the attached lines. or Invoiced. one record in SalesParmTable per sales order. FIGURE 7. SalesParmTable.2 SALESFORMLETTER Orders can be fully or partially updated. For instance. and one record in SalesParmLine per line to be updated. the update occurs. a sales order can be Open Order. Sales order updates. Delivered. For instance. but if one of the lines is still open.Chapter 7: Trade Post and Print Document Updates Sales and purchase orders go through different stages or sales statuses. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-5 . When the user makes alterations and clicks OK. The status displayed on the sales order is the lowest status. and can be updated one order at a time or in a batch of orders. Each update involves different postings. use SalesParmUpdate.ChooseLines() method uses the SalesUpdate query to select appropriate salesLines records and populates SalesParmLine accordingly. based on a class called formLetter (which extends RunBaseBatch). then the status of the order is delivered. then the order is also open. and therefore use a sub-class structure. Once the parm tables are populated. if all lines are delivered. the system populates these parm tables. based on the enum SalesStatus. next()) { SalesFormLetter.SalesId) { salesTable = salesParmTable. } if (this.queryBuild().parmC urrentBatch(). } setprefix("@SYS25781").this. if (salesParmTable.get(tablenum(SalesParmTable)).RecId). if (printout == Printout::Current || this. batchHeader.addRuntimeTask(formLetterMultiThread.SalesFormLetter 1.checkIfSalesOrderExist(salesTable)) { try { if (batchHeader) { formLetterMultiThread = FormLetterMultiThread::newFormLetter(this). infolog.num().queryBuild() builds a query based on SalesParmUpdate and SalesParmTable. 2. } salesParmTable = query.proforma()) { journalList = this.newJournalList(). if (printout == Printout::After && ! this.Development IV in Microsoft Dynamics® AX2009 Demonstration . journalList is a list of documents to be printed later.SalesId != salesTable. The query is then executed: infoLogCounter = infolog.proforma()) { journalList = this.run() method: query = this. 7-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .newJournalList().updateViewSet(this). while (query. View the SalesFormLetter.salesTable(). else this.postUpdate(). salesParmUpdate. and a check is made on the sales order. } } SalesParmTable is retrieved from the query. invoice or delivery note) and voucher are created then SalesFormLetter.insertJournal().for mLetterMultiThread. View the SalesFormLetter.UpdateNow() is called.documentStatus()).SpecQty. Order totals and tax totals are calculated: if (salesParmUpdate. if (this.allocateNumAndVoucher(). this. The UpdateNow() method is not implemented in SalesFomrLetter. SalesFormLetter. If the order is to be posted (that is. rather in its sub-classes. = this. salesParmUpdate. SalesFormLetter.SumSalesId. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-7 .SumBy. The different sub-classes UpdateNow()use a list of SalesParmLine records (created when the order totals were calculated).g. Posting number (e. voucher] = this. this.insertJournal() is called: numberSeq [number.addDependency(salesFormLetterEndMultiThread.insertProforma(). salesParmUpdate.createJournal() method: salesTotals = SalesTotals::construct( salesParmTable.initFromSalesTotals(salesTotals). 3.Proforma) this. } else { this.createJournal() is then called.createJournal(). salesParmUpdate.updateNow()) { this. 4.getNumAndVoucher().Chapter 7: Trade batchHeader.ParmId. not pro-forma).BatchDependencyStatus::FinishedOrError). initLedgerVoucher(transactionTxt). View the SalesFormLetter_PackingSlip. salesLine.UpdateNow() method: this. salesParmLine.initJournal(). recordListSalesParmLine. inventUpd_Physical. this. The physical update to inventory is slightly different depending on which update is made. The ledgerVoucher and ledgerVoucherObject classes are instantiated.initTransactionTxt().ReduceOnHand). salesParmLine.checkDiscardLine()) { CustPackingSlipJour is initialized using values from the update and from SalesTable.updPhysicalUnit(). so the updateInventory() method is overridden in SalesFormLetter_PackingSlip. this. which may be used if posting physical movement to ledger. 7-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .first(salesParmLine).updateInventory(inventMovement).updateNow(ledgerVoucher).updPhysical().Development IV in Microsoft Dynamics® AX2009 5. updateNow = inventUpd_Physical. 8. updateNowInvent = -inventUpd_Physical.clear(). The first SalesParmLine from the list is retrieved: inventMovement = InventMovement::construct(salesLine). transactionTxt = this. InventMovement is instantiated using SalesLine. Transaction text is initialized. 7.clear(). salesParmUpdate. number. while (salesParmLine) { if (! this. this.updateInventory () method: inventUpd_Physical = InventUpd_Physical::newSalesPackingSlip( _inventMovement.initRecordListInventReportDimHistory(). 6. View the SalesFormLetter_PackingSlip. 11. true).writeJournalLine() finalizes CustPackingSlipTrans and commits it to the database: salesLineType = SalesLineType::construct(salesLine). salesParmLine. salesParmLine.InventNow = updateNowInvent. Return to SalesFormLetter_PackingSlip.. this.updateSalesLine(inventMovement. 9.updateNow)). salesParmLine.DeliverNow = updateNow.writeProjTrans(inventMovement). SalesFormLetter_PackingSlip. .UpdateNow(): if (salesParmLine.writeJournalLine(). If the quantity is reduced.setLineAmount(salesLine).RecId. salesParmLine..DeliverNow .doUpdate().RemainAfter += salesParmLine. salesLineType.transIdSum()). and is then used to return the actual quantity updated. salesParmLine.DeliverNow != updateNow || salesParmLine. info(strfmt("@SYS26397". salesLine. this.setRemainAfterInvent(). The quantity may be reduced due to insufficient inventory. } 10. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-9 .updateNow.Chapter 7: Trade InventUpd_Physical posts the physical movement of the inventory.update(). qtyReduced = true. the user is informed and the parm table record is updated to ensure that later updates are correct. salesParmLine.InventNow != updateNowInvent) { salesParmLine = SalesParmLine::findRecId(salesParmLine. salesParmUpdate. } CustPackingSlipJour.SumSalesId. the totals are recalculated and the tax is adjusted: this. the sales order has been created and will be invoiced.postMarkupTable(). In this case. } 13. If the document is to be printed.writeRecordListInventReportDimHistory(). this. The following is an example of using SalesFormLetter.documentStatus()).Proforma) this.tax(salesTotals.len() > 0) { if (printFormletter) { this. this. this. it is called using printJournal(). 7-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .SpecQty.Development IV in Microsoft Dynamics® AX2009 12. If the quantity is reduced. this. journalList). custPckSlpJour.SumBy. this. salesTotals.writeJournal().printJournal() contains code that calls the report. salesParmUpdate.tax()).PrintJournal() method: if (journalList. View the SalesFormLetter_PackingSlip.updateSalesShippingStat(salesParmTable). The status of the SalesLine record is updated (which may also update the SalesTable record): if (qtyReduced) { salesTotals = SalesTotals::construct(salesTable. 14. salesParmUpdate.printJournal().sendAsXML(). SalesFormLetter_PackingSlip.printJournal(this. salesParmUpdate.run() method: if (printout == Printout::After && ! salesParmUpdate.ParmId. 15.calc(). The sub-classes override this method so that the specific report can be called. Return to the SalesFormLetter.WriteJournal() finalizes CustPackingSlipJour and commits it to the database. NoYes::No. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-11 . The process is similar to posting ledger transactions using the ledgerVoucher. This can be manually created or created within code.createCustTrans() shows where the invoice posting creates the customer transaction. customer and vendor transactions can be posted by using a CustVendVoucher object. . AmountMst _amountMST. //Transaction date SalesUpdate::All.Chapter 7: Trade Example: Posting an Invoice static void createInvoice(SalesTable _salesTable) { SalesFormLetter salesFormLetter. CustVendVoucher custVoucher.update( _salesTable. The following example illustrates how a customer transaction could be posted. salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice). . LedgerVoucherObject ledgerVoucherObject. LedgerVoucherTransObject ledgerVoucherTransObject. as with a normal daily journal. LedgerAccount _ledgerAccount) { CustTrans custTrans. You must still create transactions in another account to balance the posting. CustAccount _custAccount. LedgerVoucher ledgerVoucher. salesFormLetter. one of the LedgerVoucherTransObject instances is replaced with a CustVendVoucher instance which handles posting to both the AR sub-ledger and the AR ledger account. //Should document be printed Posting Transactions Customer and vendor transactions can be posted using a ledger journal. //Which qty should be used AccountOrder::None. SalesFormLetter_Invoice. Similar to ledger transactions. but here. but still uses the same LedgerVoucher object. //SalesTable record to be posted systemDateGet(). Example: Posting a Customer Transaction static void createTransActions( NumberSequenceCode _numberSequenceCode. This creates the transaction in the sub-ledger and the AR or AP account. //Is document a proforma NoYes::No). NumberSeq numberSeq. The sales revenue transaction is created elsewhere in the update. ledgerVoucher. -_amountMST. ledgerVoucher = LedgerVoucher::newLedgerPost( DetailSummary::Detail.Currency. _ledgerAccount. LedgerPostingType::CustPayment). ledgerVoucher. ledgerVoucher.voucher().NumberSequen ce).addTrans(ledgerVoucherTransObject). LedgerTransTxt::CustPaymentCust. 0). custVoucher.NumberSequen ce). ledgerVoucherTransObject.AddVoucher(ledgerVoucherObject). ledgerVoucherObject = LedgerVoucherObject::newVoucher( numberSeq. ledgerVoucher. CustTable::find(_custAccount). CustTable::find(_custAccount). CustTable::find(_custAccount).Dimension.end(). _custAccount. custVoucher. SystemDateGet().Currency.post(CustTrans). SysModule::Cust. numberSeq = NumberSeq::newGetVoucherFromCode( NumberSequenceTable::find(_numberSequenceCode).parmTransTxt("Sales Transaction"). } 7-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . ttscommit. ''. LedgerTransType::Payment). _amountMST. ledgerVoucherTransObject = LedgerVoucherTransObject::newCreateTrans( ledgerVoucherObject. LedgerPostingType::CustPayment.parmTransTxt('Customer Transaction'). CustTable::find(_custAccount). SysModule::Cust.Dimension. custVoucher = CustVendVoucher::construct( SysModule::Cust. NumberSequenceTable::find(_numberSequenceCode).Development IV in Microsoft Dynamics® AX2009 ttsbegin. The CustSettlement and VendSettlement tables hold each settlement that has taken place and stores the recIds of the transactions that are settled against each other.Chapter 7: Trade Settlement When customer or vendor invoices are paid the payment transactions and the invoice transactions must be settled against each other to close the transaction. use the SpecTrans table. The class Specification can be used to handle creation of SpecTrans records and also to handle marked transactions. Settlement takes place in the CustVendSettle class. Additionally. This stores the RecId's of the transactions to be settled. } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-13 . a method. CustTrans _custTrans2) { CustTable custTable.markForSettlement(custTrans2). and using transaction markings. and the settle amount. . This method handles settlement using a FIFO principle (oldest invoice gets settled first). CustTrans::settleTransact(custTable). CustTable = CustTable::find(CustTrans1. with most of the work done in CustVendSettle.SettleNow().AccountNum). custTrans1. Example: Settling Two Customer Transactions static void createSettlement(CustTrans _custTrans1. markForSettlement() on CustTrans and VendTrans can simplify the process further. To mark transactions for settlement. accountRelation(accountCode. 7-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . They are applicable to: • • • • • • Single items Single customers Groups of items Groups of customers All items All customers This means that a single item/customer combination can have multiple prices. View the PriceDisc. so the calculation is modified regularly. Companies often have unique and imaginative pricing structures. There are different methods for calculating the price: • • • A line discount A multi-line discount A total discount Note that prices cannot be set up for groups of items or all items.findPriceAgreement() method: while (idx < 9) { itemCode accountCode = idx mod 3.PriceDisc This demonstration shows the calculation for the item price: 1. accountRelation = this. _priceGroupId). The trade agreement calculation searches through all combinations of item/customer/group/all in a particular order and finds the lowest price. itemRelation = itemCode == 0 ? itemId : ''. The Find Next field that can be cleared to stop the calculation from looking for any further prices once it has found one.Development IV in Microsoft Dynamics® AX2009 Trade Agreement Trade agreements are flexible in the way they can be set up. To set up complicated pricing structures. Demonstration . = idx div 3. it is important to understand the logic behind the calculation. accountCode.FromDate || ! priceDiscTable. and groups to view. then itemCode = 1. priceParameters)) { if (PriceDisc::validateRelation(accountCode. if (PriceDiscTable::activation(relation.Chapter 7: Trade The idx variable controls which combination of items.ToDate || ! priceDiscTable. which means as it loops itemcode = 0.ToDate) { Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-15 . itemRelation )) { 3.AccountCode == accountCode && priceDiscTable. accountRelation) && PriceDisc::validateRelation(itemCode.ItemCode == itemCode && priceDiscTable.FromDate) && (discDate <= priceDiscTable. itemCode.AccountRelation == accountRelation && priceDiscTable. 0 = table. accountCode = 0. while select priceDiscTable index PriceDiscIdx // equals order by QuantityAmount where priceDiscTable.ItemRelation == itemRelation && priceDiscTable.Currency == currency && priceDiscTable. The item relation and account relation are set according to the item code and account code. The system counts idx from 0 to 9. customers. the itemCode = 1 or 2 is meaningless. accountCode = 0. 1 = group and 2 = all. Look in PriceDisc.InventDimId == _inventDimId && (discDate >= priceDiscTable. and validation is performed on the values. 2. The trade agreement activation is checked to see if this combination is allowed. accountCode = 0.UnitId == unitID && priceDiscTable. For both itemCode and accountCode.Relation == relation && priceDiscTable. accountCode = 1 etc. Since the system is calculating the price. then itemCode = 2. then itemCode = 0.FindLineDisc() and note the item relation is set in the same way as the account relation. markup().SearchAgain) { idx = 9. priceDiscTable.price(). the loop ends. and if this price is less than any previously found price. priceDiscTable. then continue. The trade agreement table is searched for the item\customer combination and includes the from.CalendarDays. break. To view the priceDisc class. posting transactions. and if there is a price or a miscellaneous charge amount.QuantityAmount <= absQty) { if (priceDiscTable.calcPriceAmount(absQty) || ! priceExist) { 5. 7-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Data on the price is stored for later retrieval when the final price is located. the some of the most commonly used development concepts in the Accounts Receivable and Accounts Payable modules have been introduced.DeliveryTime. if (priceDiscTable.data(). Summary In this lesson. priceUnit price markup deliveryDays calendarDays actualPriceTable priceExist = = = = = = = priceDiscTable. priceDiscTable. } If the price set to not search for more prices. refer to the setPriceAgreement. Concepts such as document updates.date. and developing modifications with them is now possible.calcPriceAmount(absQty) < this. 6. true. using settlements and searching trade agreements should now be familiar. if (! priceDiscTable.and to. Also included is the inventDimId found using active dimensions (as discussed in Chapter 6). If the quantity calculated on the line is greater than any quantity break set up on the trade agreement. priceDiscTable. priceDiscTable.Development IV in Microsoft Dynamics® AX2009 4.priceUnit(). Chapter 7: Trade Test Your Knowledge 1. What is the name of the class used when posting vendor transactions that handle both posting to the AP sub-ledger and the AP ledger account? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-17 . True or False: SalesLineType is a sub-class of SalesTableType. 2. In which method in SalesFormLetter are the records in SalesParmLine created? 3. Development IV in Microsoft Dynamics® AX2009 4. What is 8 div 3? (answer without writing a program to test it!) 7-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 2.Chapter 7: Trade Lab 7.Trade Scenario This is a part of the Point-of-Sale Case Study. and offset to the register holding account. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-19 . Need a Little Help? 1. Loop over all POSRegisterTrans records linked to the sales order. Create a new class and retrieve the sales order id from the caller. 3. create a journal line for each. that have not previously been posted to the ledger. 5. Create a new journal header. 4. See Chapter 1 for details. Challenge Yourself! Create a process that can post a payment transaction for the payment entered into the POS screen. Flag the payment lines as having been posted to the register. The journal lines should post customer account.1 . e. Create a method to create a LedgerJournalTrans record.Development IV in Microsoft Dynamics® AX2009 Lab 7.Trade (Solution) Scenario Create a process that can post a payment transaction for the payment entered into the POS screen. b. d. Create a method to create a LedgerJournalTable record. POSPostPayment: a. o Voucher comes from a class variable. Get a payment id from a number sequence and stamp each payment transaction. c. o Use a LedgerJournalName record of type Daily. 7-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Override the new method and set a class variable to hold the sales id of the order being processed. amount and payment reference as parameters. Loop through all unposted register transaction records and call the method to create a journal line for each payment line. Step by Step 1. Create a method post the payment lines. Use this id as the payment reference on the journal line. Create a new class. f.1 . Account. o Accept LedgerJournalAccountType. Challenge Yourself! When the OK button on the payment lines screen is clicked. See Chapter 1 for details. L Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-21 . DocumentStatus::Invoice. the payment posting routine should be called.Chapter 7: Trade Lab 7.Update(). Call SalesFormLetter. Create a new class. 2. Need a Little Help? 1.Payment Posting and Invoice Update Scenario This is a part of the Point-of-Sale Case Study. Call the payment posting class and the invoice posting class when the Post button is clicked. POSPostInvoice that posts an invoice. 4. This should be followed by the standard invoice update.2 . 3. Instantiate SalesFormLetter. POSPostInvoice. o Call SalesFormLetter.Development IV in Microsoft Dynamics® AX2009 ab 7.Payment Posting and Invoice Update (Solution) Scenario When the OK button on the payment lines screen is clicked. DocumetnStatus::Invoice.Update().2 . the payment posting routine should be called. Create a new class. This should be followed by the standard invoice update. Step by Step 1. which posts an invoice: o Instantiate SalesFormLetter. 7-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . o Call the payment posting class and the invoice posting class when the Post button is clicked. See Chapter 1 for details. Challenge Yourself! (Optional) Create a Campaign Price flag on the trade agreements that is only selected if a similar flag on the sales order header on the POS screen has been selected. Find the invoice and payment transactions and mark them against each other for settlement using CustTrans. This should happen whether automatic settlement is enabled or not.3 . Instantiate the PriceDisc class using the CampaignPrice flag from SalesTable.Chapter 7: Trade Lab 7. Modify the select statement in priceDisc. Need a Little Help? (Optional 1. Need a Little Help? 1. and should settle against each other no matter what other transactions are open for the customer. Challenge Yourself! When posting an invoice and payment from the POS. 2. 2. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-23 .FindPriceAgreement to look for prices with the CampaignFlag equal to a class variable that is set when the class is instantiated.Settlement Scenario This is a part of the Point-of-Sale Case Study.markForSettlement(). Post the settlement using CustTrans::SettleTransact(). they should be settled against each other. Ensure that this happens. It should only be selected if it is the lowest price available to the customer. they should be settled against each other. o Find the payment customer transaction associated with the order (you can use the payment id). This should happen whether automatic settlement is enabled or not. Set this variable in the new method from a parameter. and should settle against each other no matter what other transactions are open for the customer. Create a new class POSSettlement: o Find the invoice customer transaction associated with the sales order. CampaignPrice. Display the field on forms PriceDiscTable. Create a new class variable. 4. Add a new field CampaignPrice. c. o Mark each transaction to be settled against each other. type = NoYes. 7-24 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . EnumType = NoYes. 2. and Sales Table. 3.markForSettlement(custTable). Modify static method newFromSalesPurchLine() to look at the flag on SalesTable and pass as a parameter in the new() method. to tables SalesTable and PriceDiscTable. o Hint: Use CustTrans::settleTransact(custTable). In the PriceDisc class: a. o Hint: Use CustTransInvoice. o Post the settlement. Step by Step (Optional) 1. Create a new enum EDT.3 (Solution) Scenario When posting an invoice and payment from the POS. 5. POSCampaignPrice.markForSettlement(custTable). o CustTransPayment. Ensure that this happens. b. Step by Step 1. Modify the select statement in the findPriceAgreement method to only find campaign prices when this variable is set.Development IV in Microsoft Dynamics® AX2009 Lab 7. 3. 2.Chapter 7: Trade Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 7-25 . True or False: SalesLineType is a sub-class of SalesTableType. What is 8 div 3? (answer without writing a program to test it!) MODEL ANSWER: Two 7-26 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . What is the name of the class used when posting vendor transactions that handle both posting to the AP sub-ledger and the AP ledger account? MODEL ANSWER: CustVendVoucher 4. MODEL ANSWER: False 2.CreateParmLine() 3. In which method in SalesFormLetter are the records in SalesParmLine created? MODEL ANSWER: SalesFormLetter.Development IV in Microsoft Dynamics® AX2009 Solutions Test Your Knowledge 1. A significant part of the inventory module is its inventory dimensions. modifications to the inventory system can be significant with regard to the work required. Unlike the ledger module. This lesson discusses both creating and posting inventory transactions. and using the data correctly after it has been posted. This lesson introduces some of the classes used to manipulate inventory data. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-1 .Chapter 8: Inventory CHAPTER 8: INVENTORY Objectives The objectives are: • • • • • Create and post inventory journals Use inventory dimensions Use InventSum Use InventMovement Use InventUpdate Introduction Similar to Ledger. Inventory is closely linked to many modules within Microsoft Dynamics® AX and is a vital module to understand. Although they may seem complicated to use. there are useful classes and methods written that help you achieve excellent results. the Systems Developer. Set the journal type according to the posting you require. To be able to do this he must understand how the inventory system works in Microsoft Dynamics AX. Inventory Journals Inventory Journals are similar to Ledger Journals and can be created in a similar way. the tables used are InventJournalName. such as profit\loss and transfer. A detailed description of these steps follows. Procedure: Creating an Inventory Journal Use the following steps to create an inventory journal: 1. This step is omitted if the journal is checked by the user before posting. Tables In the inentory module. 2. Create lines for each transaction to be posted. There can be more than one InventJournalName per type. InventJournalName contains the default data for a specific journal type. based on the visible inventory dimensions.Development IV in Microsoft Dynamics® AX2009 Scenario Isaac. 3. InventJournalTable is the header record for the journal. Post the journal. Create a journal table record or use an existing one. There can be one or more lines per journal. There is one record per journal. has been asked to add a field on the sales order that shows the current on-hand inventory of an item. This checks the journal before posting. InventJournalTrans contains data used to create the individual transactions that will be posted. InventJournalTable. Application elements are similar in design but are physically different elements. and InventJournalTrans. 8-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . InventJournalTable. The journal name is commonly set either from a parameter or by prompting the user to enter it in a dialog. You must fill the record with data and then insert it.InitFromInventJournalName(InventJournalN ame).insert().JournalId which is mandatory.Voucher which is the transaction voucher number Other fields in the transaction table are mandatory according to the journal types and should be filled as necessary. Look in the InventJournalTable. Posting Journals After transactions are created in the journal. InventJournalTable.Insert() table method. and then manually opening the journal in the journal forms. Post indicates that after checking to post to the journal.MovementJournalNameId). which is the primary key defining the relationship between the journal table and the lines. Run validate and post highlights errors. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-3 . test the code by letting it create a journal. Parameters for this method are: _journalCheckPostType – Check or post parameter for specifying whether to check a journal only or check and post.Name = 'Movement Journal'. _InventJournalTable – Record in InventJournalTable representing the journal to receive the posting. because transactions are assigned to one of the journals InventJournalTrans.Chapter 8: Inventory Creating the Journal Header To create a new journal. Use a journal name of an appropriate type. Create an instance of this class using newJournalCheckPost static method and then run the class. Creating Lines All transactions must be posted in the journal lines table. While developing. xInventJournalName = InventJournalName::find( InventParameters::find(). check and post the journal using the InventJournalCheckPost class. use a journal name record to get the default data. InventJournalTable. There are two important fields to be filled every time you insert a new record: • • InventJournalTrans. Note that it handles the creation of the journal number. or configuration) There are a finite number of combinations of inventory dimensions.Development IV in Microsoft Dynamics® AX2009 The following example shows how to post an inventory journal. InventDimParm flags which dimensions to use in different situations. rather than every dimension. The InventDim. pallet. This table is a temporary table created according to which dimensions are in use. batch number. versatile. or serial number) Item dimension (color. and efficient way to track variations in inventory movements. There is one record per inventory dimension per dimension group. size.run(). InventDimSetup sets up each dimension group. InventDimGroup groups items by inventory dimensions used. This offers many possibilities when grouping and summing data. and each combination can be assigned an ID number. They define whether an item is tracked by: • • Storage dimension. 8-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and creates it if it does not exist. } Inventory Dimensions Inventory dimensions are a powerful. Tables Available tables are defined as follows: InventDim holds every combination of inventory dimensions used in the system and the corresponding inventDimId. _InventJournalTable) CheckPost. (warehouse. location.findOrCreate() method looks for a particular combination. Void PostJournal(InventJournalTable _InventJournalTable) { InventJournalCheckPost CheckPost. CheckPost = InventJournalCheckPost::newJournalCheckPost( journalCheckPostType::Post. Any reference to a particular combination of dimensions can be referred to by the ID number. This example illustrates how InventDimSearch is used to create an InventDimParm record. Procedure: Creating InventDimParm To create the correct InventDimParm record. 2.financialInvent(_dimGroupId)).initFinancialInvent(). else _inventDimParm. The method being analyzed is InventDimParm. View the InventDimSearch::financialInvent() method: static void financialInvent(InventDimGroupId _dimGroupId.CalcCostValue() method to determine which dimensions to use when calculating cost value. The flags on the InventDimParm record need to be set according to the situation in which it will be used. the system needs to look at the dimension group for an item. in the InventTrans. InventDimSearch::financialInvent(_dimGroupId.initFinancialInvent() is used.clear(). this). InventDimSearch creates a list of InventDimSetup records in a list and iterates through it.inventDimGlobal().dimSearc hBase(). InventDimParm. InventDimOnHand finds current inventory levels for specific dimensions. for example.InitFinancialInvent() method: void initFinancialInvent(InventDimGroupId _dimGroupId) { . InventDimParm _inventDimParm) { if (_dimGroupId) _inventDimParm.Chapter 8: Inventory Classes The available classes include: InventDimGlobal is a global class that holds a cache of dimension field ids and names. View the InventDimParm.data(classfactory. } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-5 . } A static method on InventDimSearch is called. 1. This is used mainly by InventDimSearch. This method will set the flags for each inventory dimension that financial inventory option checked. In this method. The first time it is accessed.dimFinancialInvent()) { inventDimParmFinancialInvent.financialInvent() public InventDimParm financialInvent(InventDimGroupId _groupId) { if (!_groupId) return null. 5. View InventDimSeachBase. and the value is an InventDimParm record holding the values for each inventory dimension.lookup(_groupId). } 8-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Note the use of the global cache for inventory dimension setup data. If not. the map is checked to see if the values have already been created for this group. Inventory dimensions are made inactive through the application configuration keys. The key is the group id. then it will call the method to initialize these values.(y) = NoYes::Yes. return financialInvent. if (_dimSearch. conFinancialInventFields += _dimSearch.first(_dimGroupId)) do { After initializing the various maps that are used. if (!financialInvent. 3. InventDimSearch. This iterates through a list of the inventory dimensions that are active.dimFieldId().first() is called.dimActive() && _dimSearch. the InventDmParm record is set to the values returned by the method InventDimSearchBase. Many setup options are examined. } financialInvent is a map that contains the setup data for each group for the financial inventory. and if both are true. and placed in the global cache. The following code shows where the flags for the dimension being active and to post financial inventory are examined. all the possible lookups for that specific inventory dimension group are found and stored in maps.Development IV in Microsoft Dynamics® AX2009 If a dimension group is specified.exists(_groupId)) this. then the InventDimParm flag for this dimension is set to Yes. View InventDimSearchBase.initInventDimCache(_groupId).financialInvent().initInventDimCache() if (_dimSearch. 4. Additionally the field id which is used to refer to which dimension this is for is stored in a container. Chapter 8: Inventory 6.insert(_dimGroupId. For sales prices. colour. Searches for a match of only item dimensions (size. Example: Using InventDimParm This example shows how to use InventDim and InventDimParm. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-7 . the system: 1. for example. inventDimParmFinancialInvent). The method being analyzed is PriceDisc.findPrice(). as shown Select main menu>inventory management>items>general tab FIGURE 8. Searches for a match of the dimensions on the sales line to the dimensions on the price. Also create sales prices for the different dimensions. financialInvent. configuration). The InventDimParm record is then stored in the map to make further lookups quicker due to not having to go to the database to retrieve the data. The Use in sales price search flag means that when looking for a price for the item. This method is used. 2. Use an item with a dimension group containing dimensions set to Use in price search.1 ITEM NUMBER Prices are created for sizes allowed for this item. when setting the sales price on a sales line. Development IV in Microsoft Dynamics® AX2009 3. Searches for a price with blank dimensions. 4. It ignores dimensions altogether. When entered into sales lines, the price is calculated using the size set on the line: Procedure - Using InventDimParm The PriceDisc class is instantiated in the SalesPurchLine.setPriceAgreement() method. SalesPurchLine is a table map. The itemId and inventDim record of the sales line is passed into the class at this point. 1. View the PriceDisc.FindPrice() method. Look for the following code: switch (moduleType) { case ModuleInventPurchSales::Purch: inventDimAllActivated.copyActivatePurchPriceAll(inventTable .DimGroupId, inventDim); break; case ModuleInventPurchSales::Sales: inventDimAllActivated.copyActivateSalesPriceAll(inventTable .DimGroupId, inventDim); break; default: inventDimAllActivated.copyItemDim(inventTable.DimGroupId, inventDim); } For moduleType = sales, calls inventDimParmAll.copyActivateSalesPriceAll() (InventDimParmAll is instance of InventDimParm). 2. View the InventDimParm.copyActivateSalesPriceAll() method: container dimFields = InventDimSearch::activateSalesPriceAllFields(_dimGroupId); ; len = conlen(dimFields); for (h=1;h<=len;h++) { x = conpeek(dimFields, h); this.(x) = _fromInventDim.(x); } The static method to initialize or retrieve the cached InventDimParm record for this group, that has the flags set for all dimensions that has the Sales Price option set, is called. The return value is used to determine which fields to use from the InventDim record that is referenced on the sales line. 8-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 8: Inventory 3. Return to the PriceDisc.findPrice() method: inventDimItemDimActivated.copyItemDim(inventTable.DimGroupI d, inventDimAllActivated); InventDimItemDimActivated is copied from the InventDimAllActivated but only copies the fields that are item dimensions (color, size, or configuration). Two InventDim records remain; one holding all values of dimensions only applicable to the sales price search, and another holding values of item dimensions applicable to the sales price search. findAll = !InventDim::isInventDimEqual(inventDimAllActivated, inventDimItemDimActivated); findItemDim = !InventDim::isInventDimEqual(inventDimItemDimActivated,inve ntDimNoneActivated); findAll is set if InventDimAllActiviated = InventDimItemDimActivated. findItemDim is set if InventDimItemDimActivated is blank. inventDimAllActivated = findAll ? InventDim::findDim(inventDimAllActivated) : inventDimAllActivated; inventDimItemDimActivated = findItemDim ? InventDim::findDim(inventDimItemDimActivated) : inventDimItemDimActivated; If findAll = true, an existing InventDim record is searched for and placed in InventDimAllActivated. If findItemDim = true, an existing InventDim record is searched for and placed in InventDimItemDimActivated. return ((findAll && inventDimAllActivated.RecId && this.findPriceAgreement(_priceGroupId, inventDimAllActivated.InventDimId)) || (findItemDim && inventDimItemDimActivated.RecId && this.findPriceAgreement(_priceGroupId, inventDimItemDimActivated.InventDimId)) || this.findPriceAgreement(_priceGroupId, InventDim::inventDimIdBlank()) || (_useItemPrice && this.findItemPrice())); Search for a price with the inventory dimension id for the InventDimAllActivated record. All inventory dimensions match if the found method returns true. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-9 Development IV in Microsoft Dynamics® AX2009 Then, search for a price with the item dimension. If a price is found, the method returns true. Then, search for a price with blank item dimensions. If a price is found, the method returns true. Finally, search for a price ignoring dimensions all together. If a price is found, the method returns true. InventSum InventSum can be regarded as one of the most important tables in Microsoft Dynamics AX. It is used to store current values of on-hand inventory. Any function that creates an inventory transaction, including creating, updating or deleting a sales line, purchase order line, inventory journal line or production order, will cause an update to InventSum. Due to the high number of processes that can update InventSum, optimistic locking of InventSum is not appropriate. It is likely that a process that has retrieved an InventSum record, is then going to update it. View the properties of the table and note that the Occ property is set to No. Instead, any changes to InventSum, are temporarily stored in another table, InventSumDelta, and are only applied to InventSum when the current transaction is committed. This ensures that InventSum records are locked for only a short amount of time. Tables Tables that are associated with InventSum operations are as follows: InventSum contains current inventory levels per item per inventory dimension combination. InventSumDelta contains information about on-hand changes that are not yet committed to the database. InventTrans automatically updates InventSum whenever a record is created, updated, or deleted. Classes There are many classes used to retrieve data from InventSum. Some examples are as follows: InventOnHand contains calculations for finding inventory levels for different inventory dimensions. InventSumDate calculates the inventory level on a particular date. 8-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 8: Inventory Invent Macros There are some useful macros available when using InventSum: #InventDimExistsJoin joins any other table, commonly InventSum, to InventDim when related to InventDim through InventDimId. It uses InventDimParm to flag the dimensions included in the join. The exists join improves performance and should only be used if the joined InventDim record will not be used later in the code. #InventDimSelect selects records in InventDim according to the flags in InventDimParm. This is used with a join to another table, commonly InventSum. Demonstration - Code Walkthrough - Updating InventSum The following walkthrough demonstrates how the system updates InventSum: 1. View the InventTrans.Insert() method: if (InventSum::mustInventTransBeUpdated(this)) { inventSum.initFromInventTrans(this); inventSum.updateInventTrans(this,NoYes::Yes); } inventSum::mustInventTransBeUpdated() returns true if fields relevant to the update of InventSum have been modified. inventSum.initFromInventTrans() sets inventSum.itemId and inventSum.inventDimId from inventTrans. inventSum.updateInventTrans() is called passing the InventTrans record. 2. View the InventSum.updateInventTrans() method: if (plus) inventSum.addInventTransOnSum(inventTrans); else inventSum.subInventTransOnSum(inventTrans); This method is called from the inventTrans.insert(), inventTrans.update() and inventTrans.delete(). When it is called from inventTrans.insert() and inventTrans.update(), the plus parameter is set to true. When it is called from inventTrans.delete(), the plus parameter is set to false. This controls whether the values in inventTrans are added or subtracted from InventSum. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-11 break. The inventUpdateOnHand class is a class held in the global cache.inventUpdateOnhandGlobal(). case StatusIssue::Deducted: this. case StatusIssue::QuotationIssue: this.AddInventTransOnSum() method: switch(inventTrans.StatusIssue) { case StatusIssue::Sold: this.addInv entSumDelta(inventSumDelta. This is due to the frequency with which it is contructed.Qty. break.Development IV in Microsoft Dynamics® AX2009 3. The inventUpdateOnHand.ttsNotifyPreCommit() this.OnOrder -= inventTrans.inventUpdateOnHand() method sets the current ttsId on the InventSumDelta record and then inserts the record in the database.initFromInventSum(inventSum). break.initFromInventTrans(inventTrans). 5. Return to the inventSum. break.ReservPhysical-= inventTrans.Qty.Qty. break. View the InventSum. appl. View the method application. This method is called during a ttsCommit by the system classes that commit a transaction to the database.inventTrans).PostedQty += inventTrans. default: } According to the status of the InventTrans record. inventSumDelta. case StatusIssue::Picked: this. break.QuotationIssue-= inventTrans.updateInventTrans method: inventSumDelta.inventUpdateOnhandGlobal(). break.Qty.Qty. case StatusIssue::ReservPhysical: this. case StatusIssue::ReservOrdered: this. specific fields in InventSum are updated.Picked -= inventTrans.Deducted -= inventTrans.ttsNotifyPreCommit().Qty.inventUpdateOnhand().ReservOrdered-= inventTrans.Qty. case StatusIssue::OnOrder: this. 4. The inventSumDelta record is updated using data from inventTrans and inventSum. 8-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Chapter 8: Inventory 6. View the method InventUpdateOnHandGlobal.ttsNotifyPreCommit(). The method changes company in the case that some of the transaction has been performed in another company. In each company it calls the following code. inventUpdateOnhandMap.lookup(newExt).ttsNotifyPreCommit() This finds the global instance of the class InventUpdateOnHand and calls the ttsNotifyPreCommit() method. 7. View the method InventUpdateOnHand.ttsNotifyPreCommit(). The two method calls to note called from here are as follows: 8. View the method InventUpdateOnHand.insertInventSum() while select ItemId, InventDimId from inventSumDelta group by ItemId, InventDimId where inventSumDelta.ttsId == this.tTSId() && inventSumDelta.IsAggregated == NoYes::No notexists join inventSum where inventSum.ItemId inventSumDelta.ItemId && inventSum.InventDimId inventSumDelta.InventDimId == == All records in InventSumDelta that were created in the current transaction and do not have a related InventSum record, are retrieved. An InventSum record created based on the InventSumDelta record and is added to a recordInsertList. When all records have been added to the list, the records are committed to the database. 9. View the method InventUpdateOnHand.updateInventSum(). If only one record is to be updated from InventSumDelta to InventSum, the updateInventSumSimple() method is called. This method adds the InventSumDelta record values to InventSum. If more than one update is needed, the updateInventSumAdvance() method is called. if (inventSumDeltaCnt == 1) this.updateInventSumSimple(); else this.updateInventSumAdvanced(); Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-13 Development IV in Microsoft Dynamics® AX2009 10. View the method InventUpdateOnHand.UpdateInventSumAdvanced(). This method calls the method InventUpudateOnHand.sqlupdateStr(). This method builds a direct SQL statement that will add all InventSumDelta records to the corresponding InventSum records in one call to the database. This ensures that the performance of the write operation to the database is maximized and the InventSum records are locked for as short a time as possible. container con = this.sqlUpdateStr(); Integer i; str statement; SqlStatementExecutePermission permission; ; //Call updates in a cycle for all generated statements for (i=1;i<=conlen(con);i++) { statement = any2str(conpeek(con,i)); permission = new SqlStatementExecutePermission(statement); permission.assert(); //BP Deviation documented new Connection().createStatement().executeUpdate(statement); permission = null; } When building the SQL statement string, the system uses the field groups called DeltaFields on InventSum and InventSumDelta to determine which fields need to be updated. If you need to add more fields to InventSum, and therefore InventSumDelta, you do not need to alter the SQL statement. Simply add the fields to the field groups and the code will handle the update for you. Demonstration - Code Walkthrough - Using InventOnHand The following demonstrates how to use InventOnHand: 1. View the static method InventOnHand::newInventDim(): InventOnhand inventOnhand = new InventOnhand(); ; inventOnhand.parmInventDim(_inventDim); inventOnhand.parmInventDimParm(_inventDimParm); inventOnhand.parmItemId(_itemId); return inventOnhand; The class is instantiated and InventDim, InventDimParm, and ItemId class variables are set from the parameters. There are other constructor methods available, all of which set different parameters to calculate the InventSum record. 8-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 8: Inventory 2. View the InventOnHand.ReservePhysical() method: this.setInventSum(); return inventSum.ReservPhysical; The method returns the value of InventSum.ReservPhysical; however, this value is first calculated with InventOnHand.setInventSum(). 3. View the InventOnHand.setInventSum() method: if (sumRead) return; this.findSumJoin(); sumRead = true; If the calculation has not already been made, InventOnHand.findSumJoin() is called. 4. View the InventOnHand.findSumJoin() method: if (inventDimId) { inventSum = InventSum::find(itemId,inventDimId); } else if (inventDimParm.ItemIdFlag) { inventSum = InventSum::findSum(itemId, inventDimCriteria, inventDimParm, InventSumFields::All); } If an InventDimId is specified the InventSum record is found. If inventory values for a specific itemId are needed, InventSum::findSum() is called. 5. View the InventSum::findSum() method: if (_inventDimParm.InventSerialIdFlag && _inventDimCriteria.InventSerialId) { switch (_sumFields) { Different select statements are used because of performance differences between the dimensions. For example, when a serial number dimension is enabled, the serial number is unique to an item, whereas a warehouse dimension is used by all items. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-15 Development IV in Microsoft Dynamics® AX2009 The method selects InventSum, summing the relevant fields (financial, physical, or all). The join to InventDim ensures all relevant records in InventSum are summed. 6. Return to the InventOnHand.FindSumJoin() method: Again, different select statements are used depending on what data is required. If only the Pallet Id is required, the select statement is different from when any other dimensions are required. After the InventSum agregrated record has been calculated, the InventSumDelta records need to be included. The addInventSumDelta() method is called. this.addInventSumDelta(); 7. View the InventOnHand.addInventSumDelta() method. if (!itemId || InventUpdateOnhandGlobal::mustAddInventSumDeltaOnhand(itemI d)) inventSum.addInventSumDelta(this.findSumJoinDelta()); If the item has records in InventSumDelta, the inventSum.addInventSumDelta method is called. This method adds an InventSumDelta record to InventSum. The InventSumDelta record is found in the InventOnHand.findSumJoinDelta() method. 8. View InventOnHand.findSumJoinDelta() method. if (inventDimId) { inventSumDelta = InventSumDelta::findSumDeltaDimId(itemId,inventDimId,Invent SumFields::All); } else if (inventDimParm.ItemIdFlag) { inventSumDelta = InventSumDelta::findSumDelta(itemId,inventDimCriteria,inven tDimParm,InventSumFields::All); } Similar to the InventOnHandFindSumJoin() method, this method retrieves an agregated InventSumDelta record based on the dimensions required. 8-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 8: Inventory Lab 8.availPhysical(). display inventQty availPhysical(SalesLine { InventOnhand InventOnhand. _salesLine.inventDimSetupObject(). InventDimFormSetup.availPhysical() returns available quantity. has been asked to display the current on hand inventory levels on the Sales Order form. Add field to sales line using the display method. element.parmDimParmVisibleGrid() for InventDimParm.1 – On-hand Inventory on Sales Order Form Scenario Issac. Create a display method on the SalesLine datasource in SalesTable form.inventDim(). 5. Use inventDimFormSetup. InventOnhand = InventOnhand::newParameters(_salesLine. InventOnHand.parmDimParmVisibleGrid()). Step by Step 1.parmDimParmVisibleGrid returns the InventDimParm for the visible inventory dimensions. 4. Instantiate using newParameters static method. Use the InventOnHand class. . return inventOnHand. the systems developer. There should be a single field displaying the physically available quantity and it should automtically adjust if the user modifies the dimensions that are displayed.AvailPhysical() returns the quantity available. 2. Challenge Yourself! Create a display method on the SalesLine data source to return the physcally avaiable inventory based on the current inventory dimensions that are displayed.ItemId. InventOnHand. 6. } _SalesLine) Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-17 . 2. 3. Note the following 1. The quantity displayed should be based on the item id and any inventory dimensions that are shown in the grid. For instance. SalesLines.ItemId. Demonstration . for example.Code Walkthrough . can be used in the construct method of the class.modified()method calls the static method InventMovement::bufferSetTransQtyUnit(salesLine). It is similar to a data carrier used by other classes when updating inventory data. InventJournalTrans. PurchLines. 8-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and the appropriate sub-class is instantiated accordingly. The following figure shows the hierarchy tree for the InventMovementClass FIGURE 8. On the SalesTable form. the quantity field is set according to certain parameters.Development IV in Microsoft Dynamics® AX2009 InventMovement Use the InventMovement class and subclasses to check and prepare data to update inventory transactions.2 INVENTMOVEMENT STRUCTURE Any lines that can have inventory transactions attached. the SalesLine_ds. View the InventMovement::bufferSetTransQtyUnit() method: InventMovement movement = InventMovement::construct(buffer). InventMovement is instantiated using SalesLine passed in through the buffer parameter. it is used to find if and where to post to Ledger. 1. The sub-classes control how the updates differ.InventMovement When a sales line item is modified. qty = decround(qty. return movement.JournalType. qty = decround(movement. movement.setTransQty(qty).transQtyUnit(). movement. such as SalesPickingListJournalLine have their own methods written for instantiating InventMovement.transQtyUnit(). call InventMovement::ConstructNoThrow directly.transUnitId()methods. Return to the InventMovement::bufferSetTransQtyUnit() method: qty = UnitConvert::qty(movement. If you do no want to throw an error. View the InventMovement::Construct() method: InventMovement movement = InventMovement::constructNoThrow(buffer. like InventJournalTrans.itemId() ).transQtyUnit().tr ansUnitId())). View the InventMovement:ConstructNoThrow() method: case tablenum(SalesLine) InventMov_Sales(buffer). 3. Others.inventUnitId().itemId()) ).subType. In this example the table is SalesLines. so InventMov_Sales is instantiated.and so on. movement. Using this method enables the same methods to be used throughout the application when creating and updating inventory transactions. such as InventJournalTrans. movement. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-19 . Note that theses methods return the value of a field from the SalesLine record used to instantiate the class. When instantiating the class. movement.Chapter 8: Inventory 2. you can throw an error if the class cannot be instantiated. Some tables.Unit::decimals(movement.inventTable(). if (!movement) throw error("@SYS20765"). movement. : return new Note this method tests the table id of the record that it was called with and instantiates the relevant sub-class of InventMovement. can instantiate different sub-classes depending on values of certain fields. 4.childBuffer ). The quantity is set according to the values returned from the movement.transUnitId().InventTable::inventDecimals(movement.setTransQtyUnit(qty). The following figure shows the hierarchy tree for InventMovement: FIGURE 8. The following figure shows the Issue Status: FIGURE 8.3 INVENT UPDATE STRUCTURE The class and subclasses are related to the base enums for inventory receipts and issues.4 ISSUE STATUS 8-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Development IV in Microsoft Dynamics® AX2009 InventUpdate InventUpdate is the class that creates and updates inventory transactions and is always used in conjunction with InventMovement. The following procedure demonstrate how to use InventUpdate: 1.updateInventory() posts the financial movement of a sales line.5 RECEIPT STATUS The class and subclasses are instantiated directly. number. The value of the inventory posts to the inventory account and the inventory transaction is stamped with a financial date. View the SalesFormLetter_Invoice. others have static methods that can be used in certain circumstances.InventUpdate SalesFormLetter_Invoice. Once the class has been instantiated. The sub classes are used for different types of required updates. the inventory is received or shipped. InventUpd_Reservation reserves an outflow against an inflow. rather than using a constructor on the super class. in other words. localSalesParmLine.updateInventory() method: inventUpd_Financial = InventUpd_Financial::newSalesInvoice(_inventMovement.Chapter 8: Inventory The following figure shows the Receipt Status: FIGURE 8. calling updateNow() posts the required update. ledgerVoucher. for example. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-21 . Some of the sub-classes should be instantiated using the new() method. InventUpd_Physical posts the physical movement of the inventory. salesParmSubLine. InventUpd_Estimated creates the initial transaction when. Demonstration: Code Walkthrough . a salesLine is created. 2.remainPhysical() || physicalUnit || remainPhysicalUnit != movement. InventUpd_Financial is instantiated using InventMovement.mustBeReceived()) { throw error("@SYS117599"). this.parmCostAmountCur().UpdateNow() method.UpdateNow() posts the transaction. physicalUnit.updFinancial().Development IV in Microsoft Dynamics® AX2009 salesParmUpdate.lastTransDate(). this is done first. if (physical || remainPhysical != movement. InventUpdFinancial. Number. ledgerVoucher. this. which has previously been instantiated with SalesLine. If the transaction has not physically posted. 8-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . localUpdateNow += inventUpd_Financial. physical.updPhysicalUnit(). which contains the voucher number for posting the ledger transactions.0 && movement. View the InventUpdFinancial.updateNow(). } if (financial < 0.mustBeDeducted()) { throw error("@SYS117598"). Currency::mstAmount(this. LedgerVoucher.updFinancialUnit(). localUpdateNowInvent += inventUpd_Financial. } inventUpd_Physical = InventUpd_Physical::newInventUpdFinancial(movement.remainPhysicalUnit()) { if (financial > 0.parmCurrencyCode(). and SalesParmLine which holds the quantity and amounts to update.0 && movement. inventUpd_Financial. which is the invoice number. localInvoiceUpdatedOnly += inventUpd_Financial.ReduceOnHand). updateInventTransPosting(ledgerVoucher. } } Create a reference to the posting in InventTransPosting: this.parmExchRate(). ledgerVoucher.lastVoucher()). this. ledgerVoucher. Some checking is then performed using inventMovement. this.lastVoucher()).RemainSalesFinancial are updated to reflect the values that have been posted. Calculate the cost value of the transaction and post to the general ledger: costAmountMST = movement.updateInventTransPosting(ledgerVoucher. Some values. Create a reference to the posting in InventTransPosting: this.lastTransDate() .lastTransDate() . } else { if (financial > 0) { this.updateFinancialIssue(costAmountMST).parmExchRateSecondary())). such as SalesLine.updateFinancialReceipt(costAmountMST). Some values. such as SalesLine.Chapter 8: Inventory this.RemainSalesFinancial are updated to reflect the values that have been posted. this). if (financial < 0) { this. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-23 .parmExchRatesTriangulation().updateLedgerFinancial(ledgerVoucher. The second parameter determines the additional quantity to be reserved.Development IV in Microsoft Dynamics® AX2009 InventUpd_Reservation To reserve incoming inventory against an outflow. . InventQty _reserveQty) { InventUpd_Reservation reservation. movement = InventMovement::construct(_salesLine). You can unreserve by specifying a positive amount. Inventory is closely linked to many modules within Microsoft Dynamics AX. This lesson demonstrate both creating and posting inventory transactions. use the InventUpd_Rservation class: void SalesReserveQty(SalesLine _salesLine. Summary Similar to Ledger. reserveQty. It is not possible to reserve more than what is ordered from the sales order line. this lesson introduces some of the classes used to manipulate inventory data. InventMovement movement. In addition. and using the data correctly after it has been posted. the quantity should be negative. To reserve more against an outflow.updateNow(). Modifications to the inventory system can be significant with regard to work required. reservation = InventUpd_Reservation::newMovement(movement. 8-24 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . true) reservation. } The InventUpd_Reservation class is instantiated using InventMovement. In which method is an InventDim record created? 3.Chapter 8: Inventory Test Your Knowledge 1. Which class is used to create inventory transactions? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-25 . Is the InventDimParm table a temporary table? 2. True or false: An InventDimId is always unique to an itemId. 8-26 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Why has the Inventory Multi-transaction Tracking system been introduced? 5.Development IV in Microsoft Dynamics® AX2009 4. Step by Step 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-27 . 4. 6. Reserving a negative quantity removes the reservation.Chapter 8: Inventory Lab 8. 2. Add open lines to a RecordSortedList while looping. After all open lines are unreserved. then createdDate. The classification should be copied to the sales table and sales line. Ensure SalesTable. Attempting to reserve the total quantity on a line reserves any that are available to be reserved. 4. Add new field. Use InventTransIdSum to find the quantity reserved.ReservationClassificaition.ReservationClassificaition. Challenge Yourself! 1. or available quantity. EnumType = ABC. type = ReservationClassifcation to CustTable. ReservationClassification.2 – Create an ABC allocation Scenario Isaac. SalesTable and SalesLine. 3. Remove any reservations on the lines by reserving a negative quantity of what is already reserved. 2. 10. 9. The RecordSortedList should sort by ReservationClassifcation. iterate through the list and attempt to reserve the sales quantity for each line. Create new Enum EDT. Ensure SalesLine. and then reserve according to the classification. 3. 8. has been asked by the Sales department to create a job that will allocate inventory based on an ABC classification set on the customer. The batch job should reallocate any reserved inventory to the sales lines based on classification. Use InventTransIdSum to find the existing reserved quantity. System reserves remaining quantity. Write a routine that unreserves all open orders. To achieve this he should add a Reservation ABC classification field to the customer table. Find all open sales order lines. Display all new fields on relevant forms.ReservationClassification is initialized from CustTable. 5. Create a new class to reserve items according to classification.ReservationClassification is initialized from SalesTable. the systems developer. 7. 8-28 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Display inventory dimensions Scenario Add inventory dimensions to the POS form. Add inventDimSetupObject form method to return instance of InventDimCtrl_Frm_Mov. Use the InventDimCtrl_Frm_Mov as used by sales table form. Look for all references to InventDimSetupObject. 1. Add the Dimension Display button so that the user can adjust what dimensions are displayed. Add a method UpdateDesign. Adda call to UpdateDesign to init method. Step by Step Inspiration for the following may be drawn from the SalesTable form. Set the number of columns in the grid according to the number of fields already displayed + number of invent dim fields displayed. 5. 6.Development IV in Microsoft Dynamics® AX2009 Lab 8. Challenge Yourself! Use the SalesTable form as inspiration.3 – POS . Use same functionality as in SalesTable form. 4. Declare a form instance of InventDimCtrl_Frm_Mov. 3. 2. Add menu item button to call action item InventDimParmFixed. 3. 5. display inventory on hand for dimensions that are displayed.Display on hand inventory Scenario In the POS form. Add field to sales line using display method. Step by Step 1.AvailPhysical() returns the quantity available. 2. Use the InventOnHand class.parmDimParmVisibleGrid() for InventDimParm. Challenge Yourself! 1. InventOnHand. Use inventDimFormSetup. Add a display method to display an inventQty on SalesLine datasource: 2. 4.Chapter 8: Inventory Lab 8. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-29 .4 – POS .availPhysical() returns the available quantity. 6. Instantiate using newParameters static method.parmDimParmVisibleGrid returns the InventDimParm for the visible inventory dimensions. InventOnHand. InventDimFormSetup. Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. 2. 3. 8-30 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Which class is used to create inventory transactions? MODEL ANSWER: InventUpdate 4. MODEL ANSWER: False Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 8-31 . Why has the Inventory Multi-transaction Tracking system been introduced? MODEL ANSWER: To solve deadlocking in InventSum 5. In which method is an InventDim record created? MODEL ANSWER: InventDim::FindOrCreate() 3. True or false: An InventDimId is always unique to an itemId. Is the InventDimParm table a temporary table? MODEL ANSWER: Yes 2.Chapter 8: Inventory Solutions Test Your Knowledge 1. Development IV in Microsoft Dynamics® AX2009 8-32 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 9: Production CHAPTER 9: PRODUCTION Objectives The objectives are: • • • • Use the ProdMulti classes. Use the ProdStatusType classes. Use the ProdUpd classes. Schedule production orders. Introduction Production orders in Microsoft Dynamics® AX 2009 can have many components and resources. One production order can be linked to many others through subBOMs and reference production orders. The Production module is designed to set up items that are produced, indicate how they are produced, what components they are made up of, how long it takes, and so on, and then to let the system calculate: • • • When they can be made What resources to use How much it will cost This is done by updating the production order status at each stage of the process. The status update process is an important part of the production module and is often modified to include parameters unique to a company's production line. The key to modifying the update process is knowing the function of the many classes involved. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-1 Development IV in Microsoft Dynamics® AX2009 ProdMulti Production orders can be updated either one at a time, or multiple orders at once. The RunBaseMultParm structure enables the use of different parm tables and different updates to run, all using the same structure. FIGURE 9.1 THE RUNBASEMULTPARM STRUCTURE Demonstration: Code Walkthrough - ProdMulti An update to a production order can be called from either the Production table form or from main menu > periodic > update. Both places call the same menu items, which run the appropriate ProdMulti class. For instance, updating to Estimated calls ProdMultiCostEstimation::main(). 1. View the ProdMultiCostEstimation::main() method: prodMultiCostEstimation = ProdMultiCostEstimation::construct(args); RunBaseMultiParm::initFromForm(prodMultiCostEstimation,args ); ProdMultiCostEstimation is instantiated, and then passed into the static method RunBaseMultiParm::initFromForm(), along with args. 9-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 9: Production 2. View the RunBaseMultiParm::initFromForm() method: FormDataSource fdS; Common common; ParmBuffer parmBuffer = runBaseMultiParm.defaultParmBuffer(); ParmUpdate parmUpdate = runBaseMultiParm.defaultParmUpdate(); ; RunBaseMultiParm::initParm(runBaseMultiParm); //sets the parm id parmBuffer is a table map that is mapped to the different parm tables. RunBaseMultiParm.defaultParmBuffer() is overridden in the sub-classes and returns the appropriate parm table. RunBaseMultiParm::initParm() retrieves saved data (sysLastValue) and sets the ParmId used in the update. if (args && args.dataset() && args.record().dataSource()) { //init specific update tables fdS = args.record().dataSource(); for (common=fdS.getFirst(true) ? fdS.getFirst(true) : args.record();common;common=fdS.getNext()) { parmBuffer.Linenum++; runBaseMultiParm.insert(common,parmBuffer); } } All selected records in the form data source are added to the appropriate parm table. If the update has been called from the main menu, there is no data source and no records are found. 3. Return to the ProdMultiCostEstimation::main() method: if (! prodMultiCostEstimation.prompt()) return; prodMultiCostEstimation.run(); The prompt displays the form where the user can change the settings to update the order. There is also a function to select more records, which must be used when the update is called from the main menu. The run() method is then called. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-3 Development IV in Microsoft Dynamics® AX2009 4. View the ProdMultiCostEstimation.run() method: while (curParmCostEstimation) { try { prodTable = this.initProdTable(curParmCostEstimation.ProdId); prodTable.status().runCostEstimation(curParmCostEstimation, false,prodPurch,this); } All records in the parm table are looped over. The ProdStatusType sub-class is instantiated using the status of the prodTable record, then the update is called. ProdStatusType Production order updates are controlled using the ProdStatusType class and subclasses. FIGURE 9.2 THE PRODSTATUSTYPE CLASS Each stage of the update process must take place. If the current status of an order is Estimated, and you try to update it to Report as Finished, then it must be Scheduled, Released, and Started before it can be reported as Finished. Before each update is run it checks to see if the previous status has already been processed. If not, then it runs that update. It also handles what updates can take place to a production order. For instance, a production order with status Finished, cannot be Estimated. Demonstration: Code Walkthrough - ProdStatusType Update a production order with a status of Released to a status of Report as Finished. The update to the status is called by ProdMultiReportFinished, which is discussed in the next section. 9-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement Chapter 9: Production The following steps demonstrate the use of ProdStatusType: 1. View ProdMultiReportFinish.Run(): try { this.initProdTable(prodParmReportFinished.ProdId).status(). runReportFinished(prodParmReportFinished,false,this,sysSign ); } ProdMultiReportFinish.Run() instantiates the ProdStatusType_Released subclass using the status of the production order, and calls ProdStatusType_Released.runReportFinished(). 2. View ProdStatusType_Released.runReportFinished(): if (!ask) { ProdUpdReportFinished::runPreviousJob(prodParmReportFinishe d,_multi); prodTable.type().runReportFinished(prodParmReportFinished,_ multi,_sysSign); } return true; ask is set to true only when the method is called to ask whether the update is allowed, not to run the update. ProdUpdReportFinished::RunPreviousJob runs the update to status Started. 3. View ProdUpdReportFinished::RunPreviousJob: ProdParmStartUp prodParmStartUp = ProdUpdStartUp::initParmBufferFromRepFin(prodParmReportFini shed); ; prodParmStartUp.insert(); ProdTable::find(prodParmStartUp.ProdId).status().runStartUp (prodParmStartUp,false,null,_multi); A record in ProdParmStartUp is created using the ProdParmReportFinished record that is used for the update to Report as Finished. ProdStatusType_Released sub-class is instantiated using the status of the production order and calls ProdStatusType_Released.runStartUp(). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-5 Development IV in Microsoft Dynamics® AX2009 4. View the ProdStatusType_Released.runStartUp() method: if (!ask) prodTable.type().runStartUp(prodParmStartUp,_multi); return true; Since the status previous to Started is released, and this order is already released, there is no need to run the previous job. Once the update to status Started has taken place, it returns to ProdStatusType_Released.runReportFinished(), then runs the update to Report as Finished. ProdUpd The update to the production order is taken handled by the ProdUpd class. FIGURE 9.3 THE PRODUPD CLASS When a production order is updated, there are two events that can occur. • • The status is updated to the new status. Journals can be created and posted to consume items and operations as required, depending on the settings on the update, the production parameters, and the item itself. For instance, updating to Started may post the BOM journal and consume all items in the BOM at this point. 9-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement prodTable. and then run.run(). View the ProdUpdStartUp. The following steps demonstrate the use of ProdUpd: 1.StartedUpQty. ProdUpdStartUp. View the ProdStatusType_Released.setParameters().ProdUpd ProdStatusType.RunStartUp() method: ProdUpdStartUp prodStartUp = ProdUpdStartUp::newParmBuffer(prodParmStartUp).startUpUpdateRouteJobs(this).run() method: try { ttsbegin. It is called when component dimensions are used in the calculation of item consumption. viewCacheProdRoute = null.RunStartUp() runs the update to Startup status.setParameters() retrieves ProdTable and initializes BomCalc. ProdUpdStartUp. .validate()) throw Exception::Error.updateBomConsumption() creates the BOM consumption journal. 2. this. this.ProdId.Status. if (! this.status(). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-7 .updateRouteConsumption().updateProduction(). this. prodTable. and prodTable. ProdUpdStartUp is instantiated using the parm table.StUpDate.true). this.updateProduction updates to prodTable. If the update is set to post the BOM consumption. viewCacheProdRoute activates cache on all prodRoute records for the current production order. ProdUpdStartUp. viewCacheProdRoute = ProdRoute::viewCacheProdId(prodTable. it also posts the journal. prodStartUp.Chapter 9: Production Demonstration: Code Walkthrough .updateBOMConsumption(). ProdMultiSchedulingJob selects the production orders. the system indicates separate operations and.ProdId. Any references (production orders created due to this production order) are also updated. the data is stored in temporary tables and arrays. and the parm table record is updated to show it has been posted. TransactionLog::create(TransactionLogType::ProdStartUp. initializes the ProdParmScheduling records.Development IV in Microsoft Dynamics® AX2009 The production route is updated and the route journal is created and posted. While scheduling a specific production. If limited material and capacity are used. 9-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . strfmt("@SYS76498". Demonstration: Code Walkthrough . and allows the user to set the scheduling direction and sort order. as this covers both operation and job scheduling. The scheduling direction and scheduling date must also be considered. There are a number of factors that determine when an operation or job can be scheduled. This instance shows scheduling by job. Each production order is split into route operations and held in WrkCtrRouteData. then all the materials and work centers must be available. prodTable.startupReferences(). This temporary data is handled by classes that have the postfix Data. separates the jobs. production orders to be scheduled are placed into the WrkCtrMasterData data storage class.updateJobJournal(ParmJobStatus::Executed). Scheduling Production orders are scheduled using a sequence specified by the user according to what is currently available with respect to material and work center capacity. ttscommit. routes. "@SYS77138")). this. To handle all the factors involved in an efficient manner. When all the temporary data has been created. and productions to give starting and ending dates and times. if job scheduling. this. for example. the time to carry out each job or operation can be calculated. Scheduling can be done by operation or by job. operations.Scheduling ProdUpdScheduling controls the update of production orders to scheduled status. which can be applied back up through the tree of jobs. ProdId)). but wkCtrScheduleJobs.run() method: try { ttsbegin. (wrkCtrScheduleJobs is instantiated as an instance of wrkCtrScheduleJob_Detail in ProdUpdScheduling_Job. The load method creates records in the TmpSchedMasterData temporary table that refer to each production order to be scheduled. wrkCtrScheduleJob. wrkCtrScheduleJob = new WrkCtrScheduleJobs_Detail(wrkCtrParmSchedule. View the ProdUpdScheduling_Job. View the ProdUpdScheduling. try { ttsbegin. View the wkCtrScheduleJobs. Some of the classes to be used are instantiated. 3.run()is not overridden).run() is called. if (!this. and super() is called.Chapter 9: Production The following steps demonstrate the use of ProdUpdScheduling: 1. wrkCtrParmSchedule = WrkCtrParmSchedule::newProdParmScheduling(prodParmSchedulin g).load().validate()) throw Exception::Error. This includes any child or parent production orders if the Schedule References option was selected in the Scheduling Update form. masterData.run() method: setprefix(ProdMultiSchedulingJob::description()). wrkCtrMasterData has been instantiated as wrkCtrMasterData_Prod.run(). wrkCtrMasterData = new WrkCtrMasterData_Prod(). 2. super().runMaster()) { Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-9 . After some initial validation.run(). if (! this.run() method: setprefix(#PrefixField(ProdParmScheduling.wrkCtrMasterDa ta). wkCtrScheduleJobs. rec_Iteration() == this.runMaster() runs the scheduling.rec_FromTime()).check()) throw error("@SYS18447").masterDirection(parmSchedule.masterSchedDate(masterData. this.masterDirection() == SchedDirection::Forward) { this. this. if (this. the last production is scheduled first. If the scheduling direction is forward. this. setMasterStartDateTime initializes the scheduled start and end date and time to the schedule date and time. The scheduling direction dictates the sequence that the production orders are retrieved. else doNext = masterData.rec_FromDate()).masterDirection() == SchedDirection::Forward) doNext = masterData.first(). routeData = masterData.rec_FromTime()).masterIteration()) { setprefix(masterData. this. only one production order is in the temporary table. 9-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and the class array variables are populated with the data from ProdRoute records attached to the production order.prefixNumId()).Development IV in Microsoft Dynamics® AX2009 wrkCtrScheduleJobs. further checks are made.runMaster(): this.schedDirection()). wrkCtrRouteData is instantiated. while (doNext) { if (masterData.newRouteData(). View wrkCtrScheduleJobs.rec_FromDate()).masterIteration(1). Note that if references are not scheduled. while (doFirst) { if (this. if (! masterData. this. 4. If the production order level is the level currently being scheduled.last().setMasterStartDateTime().routeSchedTime(masterData.routeSchedDate(masterData.masterSchedTime(masterData. this. View the wrkCtrJobLinkData_ProdJob.routeSchedDate(masterData.routeDirection() == SchedDirection::Forward) doNext = routeData.ProdId masterData. 6. View the wrkCtrScheduleJobs. The data in wkrCtrRouteData is looped and initial dates are set.runRoute()) return false.load() is called. else doNext = routeData. this.Chapter 9: Production } else { this.runJobLink() is called. View the wrkCtrScheduleJob.rec_ToDate()).masterSchedDate(masterData. wrkCtrScheduleJob.runJobLink()) return false.last(). JobLinkData. 5.load().load() method: while select forupdate _prodRouteJob index ProdOprIdx where _prodRouteJob.rec_NumId() && _prodRouteJob.routeSchedTime(masterData. if (!this. if (! this. 7.rec_OprNum() == == Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-11 .runRoute() method: while (doFirst) { if (this. RunRoute is called.first().rec_ToTime()).masterSchedTime(masterData.rec_ToTime()).rec_ToDate()).runJobLink() method: jobLinkData. this.OprNum routeData. } The scheduling date on the master and route data is set according to the scheduling direction. 1. _prodRouteJob.PropertyId. _prodJobType.insert(_prodRouteJob.routeGroup()).Locked ).OprPriority._prodRoute. _calcTime. _prodRoute. this. _prodRouteJob. The time needed for each job is calculated. _prodRouteJob. _currentJobIdx = jobData._ calcTime).WrkCtrId. _prodJobType.scheduleCapacity(_prodRoute.JobType.scheduleWorkTime(_prodRoute.JobId. _prodRouteJob.JobStatus >= ProdJobStatus::Completed ? 0 : _jobTime. _prodRoute. _calcTime = _prodJobType. _prodRoute. _currentLinkIdx.Development IV in Microsoft Dynamics® AX2009 Jobs attached to the current route are selected. _prodRouteJob. including the calculated time is stored using wrkCtrJobData.routeGroup()).WrkCtrLoadPct.calcJobSchedJobTime(_prodRouteJob.RecId. _prodRoute. _jobTime = _prodJobType. _prodRouteJob.calcWrkCtrHours(masterData.bomCalcData(). 9-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .rec_JobLastIdx(). _prodRoute) * 3600. _prodRouteJob. Job data. rec_ToDate().rec_ToTime(jobLinkData.rec_ToDate() && endTime < jobLinkData. endTime = jobLinkData.first(oprNum)) { routeData. Each operation in the route has the start and end date set according to start and end date of the jobs attached to it.savePosition().update(). routeData. oprNum = routeData.runJobLink(): oprNum = routeData.rec_OprNum(). 9.rec_FromTime()).rec_ToDate()).next(oprNum)) { if (endDate < jobLinkData.rec_FromTime(jobLinkData.update() is called.routeSchedOk()) { routeData. while (oprNum) { if (jobLinkData.rec_ToDate().Chapter 9: Production 8.rec_ToTime(). while (jobLinkData.rec_FromDate(jobLinkData.rec_ToTime()). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-13 . This method using JobLinkData.rec_ToTime().rec_ToDate() || (endDate == jobLinkData. routeData.update() and JobData.rec_EndTime(endTime). } } routeData.runRoute() method: if (this. routeData. endDate = jobLinkData.update() commits the data to the database. Each operation in the route is retrieved and routeDate.rec_ToTime())) { endDate = jobLinkData. Return to the wrkCtrSchedule.rec_FromDate()). Return to wrkCtrScheduleJobs.rec_ToDate(jobLinkData. routeData. endTime = jobLinkData.rec_EndDate(endDate). while (oprNum) { routeData.rec_OprNum(). Development IV in Microsoft Dynamics® AX2009 Summary Production orders in Microsoft Dynamics AX 2009 can have many components and resources. and so on. indicate how they are produced. 9-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . The production module is designed to set up items that are produced. what components they are made up of. Greater productivity can be achieved by automating these and other business processes. how long it takes. and then to let the system perform the calculations. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-15 . Which class controls whether a production order can be updated from one status to another? 3. WrkCtrRouteData is a data storage class which holds all ____________ that are in a route. Which parm table is used when updating the status from Scheduled to Released? 2.Chapter 9: Production Test Your Knowledge 1. which is copied to the BOM journal and printed on the production order picking list. 2. Chapter 1.1 . ProdBOM is initialized from ProdTable in ProdBOM. 9-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .initFromProdTable(). Need a Little Help? 1.Production Scenario This is part of the POS Case Study. Challenge Yourself! Add a free text field Special Instructions to the production order.Development IV in Microsoft Dynamics® AX2009 Lab 9. Add the Special Instructions field to the sales lines. Make sure this field is copied to the production order when the production order is created directly from the sales line (sales table form > sales lines > inquiries > production). and through master planning. Make sure ProdBOM. ProdBOM and ProdJournalBOM. which is copied to the BOM journal and printed on the production order picking list. 2. Step by Step 1. 5.1 . 4.Instruction.Instruction is initialized from ProdBOM. Add ProdTable. type = ProdInstruction. 3. Create a new string EDT. Add new field Instructions to tables ProdTable.Instrucation. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-17 .Chapter 9: Production Lab 9. Ensure ProdJournalBOM.Instruction is initialized from ProdTable.Production (Solution) Scenario Add a free text field Special Instructions to the production order. ProdInstructions.Instrution field to ProdPickList report. InitFromReqPO(). ProdTable is initialized from SalesLine in ProdTable.Development IV in Microsoft Dynamics® AX2009 Lab 9. Need a Little Help? 1. When firming an order from a planned order. and through master planning. 2. This is for creating a production order directly from a sales line. Make sure this field is copied to the production order when the production order is created both directly from the sales line (sales table form > sales lines > inquiries > production). view ProdTable. 9-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Production Scenario Challenge Yourself! Add the Special Instructions field to sales lines. 3. ReqCalc.initFromSalesLine().InitFromReqPO().initTransFromInventTrans(). In the requirement calculation. view RecCalc.covCreatePlannedOrder() and ReqTrans.2 . Instructions from SalesLine in ProdTable.Instructions in ReqCalc. 6.Instructions using InventTransId to look up the sales line in ReqCalc.InitFromReqPO(). Set ReqTrans.Instructions in ReqTrans. Step by Step 1. 5. Set ReqPO. 2. To set the field in ProdTable when firming the order.Instructions from ReqPO.Production (Solution) Scenario Add the Special Instructions field to sales lines.Instructions from ReqTrans.Chapter 9: Production Lab 9. ReqTrans and ReqPO. 3. 4.Instructions from ReqPO in ProdTable.2 .InitFromSalesLine(). Add new field Instructions to tables SalesTable. Ensure this field is copied to the production order when the production order is created both directly from the sales line (sales table form > sales lines > inquiries > production).Instructions from SalesLine. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-19 .covCreatePlannedOrder().initTransFromInventTrans(). set ProdTable. and through master planning. type = ProdInstruction.InitFromReqPO(). Set ReqTrans. To set the field in ProdTable when creating a production order directly from a sales order. set ProdTable. 9-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 3. 2.Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three Key Points you have learned from this chapter 1. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 9-21 . Which parm table is used when updating the status from Scheduled to Released? MODEL ANSWER: ProdParmRelease 2. WrkCtrRouteData is a data storage class which holds all ____________ that are in a route. Which class controls whether a production order can be updated from one status to another? MODEL ANSWER: ProdStatusType 3. MODEL ANSWER: WrkCtrRouteData is a data storage class that holds all operations that are in a route.Chapter 9: Production Solutions Test Your Knowledge 1. Development IV in Microsoft Dynamics® AX2009 9-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and invoices customers for costs incurred. how transactions are created and posted. which calculates running costs. and how invoices are created. total costs of the project.Chapter 10: Project Accounting CHAPTER 10: PROJECT ACCOUNTING Objectives The objectives are: • • • • Know the structure and design of the project module Post transactions to the project module Make modifications to the project invoice proposal procedure Make modifications to the project invoice procedure Introduction The Project module is used to estimate and record costs and revenue transactions against individual projects. This lesson describes how the project module is designed. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-1 . ProjProposalCost. an invoice proposal can be created. ProjInvoiceOnAcc: Contain pre-arranged invoice amounts. project transactions are recorded in five tables. ProjOnAccTrans. the System Developer. other work is carried out under warranty. ProjInvoiceRevenue: Contain transactions related to revenue created by the project. ProjProposalJour: When an invoice proposal is created.Development IV in Microsoft Dynamics® AX2009 Scenario The Servicing department has asked Isaac. The system creates a suggested invoice based on user defined criteria. ProjProposalOnAcc. Some work is billable. Design Transactions posted against projects can be one of five different types: Hour (Employee). ProjProposalRevenue. ProjInvoiceJour: Each invoice created has a header record in ProjInvoiceJour. The project module in Contoso is used to track time and costs used while installing and servicing home theatre equipment. Rather than use a Type field on one table and many redundant fields. and invoice at the same time. ProjEmplTrans. and On Account. 10-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . ProjInvoiceCost: Contain transactions related to costs incurred by the project. ProjInvoiceItem: Contain transactions related to item consumption by the project. Cost. Invoice projects allows you to create multiple projects for one customer. Each project has one record in ProjTable. Once transactions are posted against projects. ProjProposalEmpl. ProjInvoiceEmpl: Contain transactions related to hours spent working on a project by an employee. they are stored in another set of five tables. ProjProposalItem. ProjInvoiceTable: At least one invoice project is created for each customer. ProjItemTrans. to make some modifications to the project module. ProjRevenueTrans. ProjTable: This is the main table for projects. When transactions are invoiced. Revenue. CustTable: Each invoice project is attached to a customer for invoicing and payment. Different transactions are stored in five different tables. the header record is held in ProjProposalJour. Item. ProjCostTrans. ProjForecastOnAcc: Contain forecast transactions for the project. This table is used as it is considered during master planning calculations.invoiced() method returns true if the cost transaction has already been invoiced. the ProjTransCostTrans. ForecastSales. ProjForecastEmpl. ProjTrans Class The ProjTrans super class and its sub-classes control the creation and posting of transactions. Note that ForecastSales is the same table that is used for item forecasts in the Inventory and Sales modules. and each subclasse has a sub-class for all the stages in a project. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-3 . These tables are used when calculating totals for the projects. ProjTransBudget: Contains a summary of all transactions of each type. ProjForecastRevenue. FIGURE 10. ProjTrans has a sub-class for each transaction type.1 PROJTRANS CLASS STRUCTURE For instance. ProjTransPosting.Chapter 10: Project Accounting ProjForecastCost. the transaction has already been invoiced. Project journals are handled similar to inventory and ledger journals.Trans table. they create ProjCostTrans or ProjItemTrans records. Cost transactions use a ledger journal.RecId ? true : false. When invoiced. and hours and revenue transactions use a project journal. You must use a journal name from an existing ProjJournalName record to create a journal header in ProjJournalTable. } If a ProjInvoiceCost record exists with a matching transaction id. Use ProjJournalCheckPost to post the journal.invoiced() method: //BP Deviation Documented display boolean invoiced() { return ProjInvoiceCost::find(this. All transaction types are created in a Proj. Posting Transactions When posting transactions against a project.transId()). journals are used.Development IV in Microsoft Dynamics® AX2009 View the ProjTransCostTrans. item consumption transactions use an inventory journal. 10-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . On Account transactions are created directly in the ProjOnAccTrans table. ledger transactions are attached to the On Account transaction records... and then add lines in ProjJournalTrans. When ledger or inventory journals are posted and ProjId is marked on the line. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-5 . #AviFormLetter).setText("@SYS26577"). When ProjInvoiceChoose is run.next()) { this. progress. Invoice proposals are created using the ProjInvoiceChoose super class and sub classes. This proposal is populated according to selections made by the user. From and To dates specified by the user are also entered into the query. clicking Create Invoice instantiates ProjInvoiceChooseNormal which extends ProjInvoiceChoose. this. The initQuery() method updates the query according to selections made by the user. This query is executed to retrieve any un-invoiced transactions and populate the ProjProposal transaction tables.assignTables() is called.initQuery(). followed by run(). If a transaction type is to be excluded the corresponding datasource is disabled in the query.ProjInvoiceChoose On the Invoice Proposal form. the user is prompted to select which type of transactions are to be invoiced and can also delimit the transactions using the query. while (queryRun.run() method: this. The progress bar is initialized.progressInit("@SYS54552". The prompt is called.Chapter 10: Project Accounting Invoice Proposal Project invoices are created by using an invoice proposal. 1. Code Walkthrough . View the ProjInvoiceChoose. progressTotal. which can be modified if necessary and then posted. ProjInvoiceChooseNormal. For each transaction found.assignTables(). On account transactions use a specific sub-class. changed(tablenum(ProjRevenueTrans))) this.ProjId.parmProjEmplTrans().Development IV in Microsoft Dynamics® AX2009 2.parmProjEmplTra ns().run() then calls ProjInvoiceChooseNormal. ProjInvoiceChoose.changed(tablenum(ProjTable))) { pProjTable = queryRun.get(tablenum(ProjTable)). View the ProjInvoiceChooseNormal. } if (queryEmpl && queryRun.doProposal(). 4.parmProjEmplTrans() && this. if the record has changed.this. View the ProjInvoiceChoose. if (queryCost && queryRun.doEmpl().parmProjEmplTrans(). if ((queryRevenue || querySubscription) && queryRun. Records returned by the query are placed in appropriate table variables. this.changed(tablenum(ProjEmplTrans))) this. this. a method populates the ProjProposal transaction tables. 3. the transaction can be added to this proposal.doEmpl() method: if(this.setProjProposalJour(this. View the ProjInvoiceChooseNormal.TransDate)).this.parmProjEmplTrans().CurrencyI d). pProjInvoiceTable = ProjInvoiceTable::find(pProjTable.progressUpdate(strfmt("@SYS26810".canBeInvoiced()) { If a transaction record exists and has not been invoiced.get(tablenum(ProjRevenueTrans)). 10-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .doRevenue(). For each transaction type.doCost().doProposal() method: if (queryEmpl & queryRun.changed(tablenum(ProjEmplTrans))) pProjEmplTrans = queryRun.assignTables() method: if(queryRun. if (queryRevenue || querySubscription) pProjRevenueTrans = queryRun.changed(tablenum(ProjCostTrans))) this.get(tablenum(ProjEmplTrans)).ProjInvoiceProjId). validateWrite()) { projProposalEmpl.InvoiceAccount ) == NoYes::Yes && pProjInvoiceTable.parmProjEmplT rans()). The projProposalEmpl record is initialized from the ProjEmplTrans record and the invoice proposal header. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-7 .parmProjProposalJour().ProposalId = this. projProposalEmpl. if (CustTable::isCustDKPublic(pProjInvoiceTable.ProposalId.eInvoiceAccountCode = pProjInvoiceTable. projProposalEmpl = ProjProposalEmpl::initProposaleFromTrans(this.eInvoiceLineSpec == NoYes::Yes) { projProposalEmpl.Chapter 10: Project Accounting An invoice proposal header is created and the progress bar is updated. After validation.insert().eInvoiceAccountCode. } if (projProposalEmpl. the projProposalEmpl record is committed to the database. recordListProjProposalCost = projProposalTotals. projProposalTotals.run() method: if(projProposalJour) { try { if (batchHeader) { formLetterMultiThread = FormLetterMultiThread::newFormLetter(this). this. parmId). recordListProjProposalRevenue = projProposalTotals. View the ProjFormLetter.recordListProjProposalRevenue().recordListProjProposalEmpl(). projProposalTotals = new ProjProposalTotals(projProposalJour.form LetterMultiThread. Code Walkthrough – ProjFormLetter 1. some tasks are created to improve performance.tax()).calc(). 10-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .addDependency(projFormLetterEndMultiThread.this. batchHeader. batchHeader. so projProposalJour must exist.tax(projProposalTotals. recordListProjProposalEmpl = projProposalTotals.InvoiceDate.addRuntimeTask(formLetterMultiThread. otherwise the createJournal() method is called 2. The structure for these classes is similar to the FormLetter classes used in Accounts Receivable (AR) and Accounts Payable (AP).BatchDependencyStatus::FinishedOrError).Development IV in Microsoft Dynamics® AX2009 Invoice Invoicing takes place in the ProjFormLetter class and the ProjFormLetter_Invoice sub-class. View the ProjFormLetter. If the job is running in batch.recordListProjProposalcost(). } else { this. } } Invoices are created from Invoice proposals.createJournal() method: projProposalJour.RecId).createJournal().InvoiceDate = projInvoiceParmTable.parmC urrentBatch(). ttscommit. projProposalJour).insertJournal().initTransactionTxt(creditNote ? LedgerTransTxt::ProjectCreditNoteLedger : LedgerTransTxt::ProjectInvoiceLedger. this.transactionLogType(). If the invoice is to be posted. this.insertJournal() method: if (this.recordListProjProposalItem_Project().updateNow()) { TransactionLog::create(this. true). and the invoice journal are initialized.createPayment().this. this. this. this.createProjInvoiceItem(). 3.createProjInvoiceSalesLine().getProjProposalJour(projInvoiceParmTable. which is overridden in the subclass. ProjFormLetter.Chapter 10: Project Accounting recordListProjProposalItem = projProposalTotals. if (proforma) this. this. this.UpdateNow() method: this. this. View the ProjFormLetter_Invoice.createProjInvoiceEmpl().initLedgerVoucher(). 4.createProjInvoiceRevenue().createProjInvoiceOnAcc().createProjInvoiceCost(). recordListProjProposalOnAcc = projProposalTotals. Ledger voucher. Totals are calculated and the project transactions are put into lists which can be used by the invoicing process. this. else this.recordListProjProposalOnAcc().insertProforma(). projProposalJour = this. } The bulk of the work is done in updateNow(). View the ProjFormLetter. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-9 .insertJournal() is called. transaction texts.tranS actionLogTxt()).initMarkup(). Summary This lesson discusses how to design the project module.Development IV in Microsoft Dynamics® AX2009 Invoice transactions are created and the necessary ledger and inventory postings are handled.SalesOrderbalance projInvoiceJour.postTax(). this. projProposalJour.parmDeleteFullyInvoiced(true).createCashDisc(). How to make modifications to the project invoice proposal procedure.createCustTrans(). salesFormLetter.LineProperty ProjLinePropertyCode::Invoiced.end().CashDiscCode && TaxParameters::canApplyCashDiscOnInvoice_ES()) { this. 10-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and how to create invoices. this. how to create and post transactions. if (projInvoiceJour. How to make modifications to the project invoice procedure. this. salesFormLetter. From this you should learn: • • • • About the structure and design of the project module. How to post transactions to the project module. The invoice journal is finalized and final postings are made. } ledgerVoucher. projProposalJour. projProposalJour.update().LedgerVoucher.postMarkupTable().SalesOrderbalance.deleteFullyInvoiced().postInvoiceRoundOff(). = = = this.LedgerVoucher projInvoiceJour. this.postEndDisc(). projProposalJour. 2.calc()? Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-11 . When posting a project invoice. True or False: A project is linked to the customer table through ProjTable.CustAccount.Chapter 10: Project Accounting Test Your Knowledge 1. In which class would you find a method that returns whether an employee hours transaction has already been invoiced? 3.projProposalTotals. which method calls the project totals calculation method . WarrantyItemId = ProjJournalTrans. type = ProjWarrantyItemId to table ProjJournalTrans and ProjEmplTrans. Set ProjEmplTrans.Development IV in Microsoft Dynamics® AX2009 Lab 10. ProjWarrantyItemId. and ensure this item id is also copied to the appropriate project transactions when the journal is posted. type = itemId to the journal lines used for employee time entry. Add a new field. 10-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 2. It is required that the employee record in which item the repair work is carried out. WarrantyItemId. and requires employees to record time against a single project.Warranty Item Scenario The Contoso Company offers repairs to the items that they sell. Create a new string EDT. called Warranty Repairs. Challenge Yourself! Add a WarrantyItemId field.1 . 3. Step by Step 1.WarrantyItemId in static table method ProjEmplTrans::InitTransFromJournal(). has been asked to create a function that will enable Invoice Proposals to be placed "On Hold".Chapter 10: Project Accounting Lab 10. ProjTransOnAccTrans. and a new invoice proposal can be created that may include transactions that were included on the OnHold proposal. 2. Add a new NoYes field. believes that there might be an error. OnHold. the Project Manager. then the invoice cannot be posted. to return false if a proposal transaction exists. OnHold to ProjProposalJour. ProjTransRevenueTrans. Display this field on form ProjInvociceProposal. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-13 . ProjTransEmplTrans. ProjTransCostTrans. but is on hold. 3. The invoice proposal will be put on hold while transactions are investigated in the case that the Prakash. If this field is set. In the classes. the Systems Developer. Step by Step 1.2 . modify the method proposal(). type = NoYes. This requires a new field. ProjTransItemTrans.Place Invoice Proposal On Hold Scenario Isaac. Challenge Yourself! Enable an invoice proposal to be put on hold. 3. 10-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three Key Points you have learned from this chapter 1. 2. projProposalTotals.Chapter 10: Project Accounting Solutions Test Your Knowledge 1. In which class would you find a method that returns whether an employee hours transaction has already been invoiced? MODEL ANSWER: ProjTransEmplTrans 3.calc()? MODEL ANSWER: CreateJournal Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 10-15 . True or False: A project is linked to the customer table through ProjTable. MODEL ANSWER: False 2.CustAccount. which method calls the project totals calculation method . When posting a project invoice. Development IV in Microsoft Dynamics® AX2009 10-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Chapter 11: Workflow CHAPTER 11: WORKFLOW Objectives The objectives are: • • • • • • • • • • Identify the components required prior to using workflow Specify which application module a workflow is applicable to using a workflow category Create a new workflow template Link tables to workflows using a workflow document Define what happens when the workflow is approved or denied. For example. that allows flexible task and approval routes for documents created by users. a purchase requisition may need to be approved by a number of different employees according to the requisition's total amount. for which you will need to use skills developed from this class and the Morph X development class. and configuration that may be set up by a user. Apply a workflow to a form Create Event Handlers and apply them to a workflow Configure a workflow Submit a record for workflow processing Use the workflow processor Introduction Workflow is a module in Microsoft Dynamics® AX 2009. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-1 . and each employee has to approve it before the next employee in the approval route. A Workflow in Microsoft Dynamics AX uses a combination of AOT elements created by IT. This lesson introduces the development side of creating an workflow. • • Workflow website. packed or invoiced. the systems developer. • NOTE: This course does not cover the installation of the workflow system components. For more information about workflow installation. Expand the Workflow node 3. Modules are defined by the SysModule enum. There are two accounts used . Right-click on the newly created workflow category and select Properties 5. Demonstration: Creating a Workflow Category This demonstration shows you how to create a category that allows the workflow to be configured from the Projects module. Workflow accounts. Until it is approved. 4. the sales order cannot be picked. however you need to be aware of the requirements. the sales order should be submitted to the Accounts Receivable (AR) manager. A new workflow category called Workflow Category1 will be created. This is an IIS website that controls the flow of the workflows.a system account used to provide access to the workflow tables. has been asked to create a new workflow that will be used to approve a new sales order for a customer that has reached their credit limit. Microsoft Dynamics AX workflow server component. Right-click on the Workflow Category node and select New Workflow Category. Change the name property to SalesCreditLimitApproval 11-2 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . and an execution account that is used to execute business logic. 1. Workflow Installation A number of the workflow system components are required to be installed before you can begin to create and configure workflows in Microsoft Dynamics AX. refer to the Administrator Guide. This is the workflow engine and is installed using the Microsoft Dynamics AX installation files.Development IV in Microsoft Dynamics® AX2009 Scenario Isaac. Open the AOT 2. They will either approve or deny the sales order. Create a Workflow Category A workflow category defines the module in which the workflow will be available. The requirement is that when a new sales order is entered that takes the customer over their credit limit. The website and the accounts are required to run this installation. Change the Module property to Cust. 4. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-3 . FIGURE 11. and many configurations can be based on the same template. Demonstration: Creating a Workflow Template This demonstration creates a workflow template and binds it to the workflow category created in the previous demonstration. 2. 3. 1. Right-click on the newly created workflow category and select Save. Open the AOT. The template defines which actions are allowed and which are required. 8. Change the label property to Sales credit limit approval. A new workflow template named WorkflowTemplate1 will be created. Right-click on the Workflow Templates node and select New Workflow Template.1 Create a Workflow Template A workflow template brings all the different elements of the workflow together. 7. Expand the Workflow node. Right-click on the newly created workflow template and select Properties.Chapter 11: Workflow 6. Workflow configurations are created based on a template. Change the label property to Sales credit limit approval. Right-click on the newly created workflow template and select Save. 4. 6. 1. Rename the query to SalesCreditLimitApproval.2 Create a Workflow Document A workflow document defines what data is affected by the workflow. 6.Development IV in Microsoft Dynamics® AX2009 5. Expand Data Dictionary > Tables. 8. Change the name property to SalesCreditLimitApproval. 7. Demonstration: Creating a Workflow Document A query defines what tables are used to determine that a workflow can be initiated. 11-4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . This is done by using a query. Expand the newly created query. Open another AOT window. Open the AOT. 5. 2. 3. FIGURE 11. Right-click on the Query node and select New Query. It can define one or more tables and all or selected fields on that table. Change the category property to SalesCreditLimitApproval. Use a class to bind that query to the workflow template. 1. 18. Expand the workflow node. In the document property. 9. returned or a change may be requested. The Workflow Approval element determines which of these outcomes is allowed and what happens in the event of each outcome. Each outcome can trigger specific code by specifying a menu item for each item. 17. Copy the following code in to the method. Right click on the SalesCreditLimitApproval query and select Save. class ProjTimeApproval extends workFlowDocument { } QueryName getQueryName() { return queryStr(SalesCreditLimitApproval). Drag the SalesTable table to the Data Sources node of the SalesCreditLimitApproval query. It may be approved. Change the Document property to SalesCreditLimitApproval. 5. 10. 12. 8. Change the Name property to SalesCreditLimitApproval. Press F8 to save the method 16. 3. Right-click on the workflow template and select Properties. 11. Right-click on the newly created approval and select properties. 14. Demonstration: Creating a Workflow Approval This demonstration creates a workflow approval and specifies how the approval route can be defined. right-click on the Classes node and select New Class. Copy the following code into the ClassDeclaration. 15. Open the AOT. Find the table SalesTable. 7. Right-click on the workflow template and select Save.Chapter 11: Workflow 7. } Create a Workflow Approval An approval route may contain a number of outcomes. Change the ParticipantProvider property to WorkflowUserGroupParticipantProvider. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-5 . 4. 19. 6. Right-click on approvals and select New Approval. Find the SalesCreditLimitApproval workflow template in the AOT. In the AOT. rejected. 2. Right-click on the class and select override method > getQueryName. enter SalesCreditLimitApproval. Press F8 to save the method 13. Change the Name property to SalesCreditLimitApprove. 10. 9. therefore call the same class from two different menu items. In more complex workflows it may be necessary to override or copy and modify this class rather than use it directly. Right-click on the newly created Action item and select Properties. 2. You are not required to do anything but set the workflow to either Approved or Denied. or other providers can be used in their place.3 Demonstration: Creating Approval Outcomes Use a standard class that acts as an engine for all approval outcomes. 3.Development IV in Microsoft Dynamics® AX2009 8. Change the DocumentMenuItem to SalesTable. 4. 11-6 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . These providers are standard application classes but can be overridden and modified. 5. Open the AOT. The two menu items simply allow you to use two different labels. Expand Menu Items. Right-click on Action and select New Menu Item. The Providers specify classes that enable rules to be defined for the workflow. Change the HierarchyProvider to WorkflowLimitHierarchyProvider. 1. FIGURE 11. Change the DueDateProvider to WorkflowWorkCalendarDueDateProvider. 17. Change the Name property to SalesCreditLimitReject. Change the Object property to WorkflowWorkItemActionManager. Change the Label property to Approve. 10.Chapter 11: Workflow 6. 13. 20. 12. Right-click on the Reject node and select Properties. 16. Change the Object property to WorkflowWorkItemActionManager. Right-click on Action and select New Menu Item. Right-click on the newly created Action item and select Properties. Right-click on the Approve node and select Properties. Right-click on the Deny node and select Properties. 11. Change the ObjectType property to Class. 25. Change the ActionMenuItem property to SalesCreditLimitApprove. 9. 23. Change the ActionMenuItem property to SalesCreditLimitReject. expand Workflow > Approvals > SalesCreditLimitApproval > Outcomes. 21. 18. Right-click on the SalesCreditLimitReject menu item and select Save. Change the Enabled property to No. 7.4 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-7 . 22. In the AOT. Right-click on the SalesCreditLimitApprove menu item and select Save. FIGURE 11. 15. 19. 14. 8. Change the Enabled property to No Right-click on the SalesCreditLimitApproval approval node and select Save. Change the ObjectType property to Class. Right-click on the RequestChange node and select Properties. Change the Label property to Reject. 26. 24. Rejected.Development IV in Microsoft Dynamics® AX2009 Demonstration: Attaching an Approval to a Template The approval needs to be attached to the template. Change the Name property to CreditLimitApprovalStatus. 5. This demonstration shows how to enable workflow on the Project Hours journal form. Open the AOT. Find SalesCreditLimitApproval. 6. 4. 11. One of these conditions must be that it has not already been submitted. Expand Workflow > Approvals. Open the AOT. Right-click on Base Enums and select New Rename the new enum to SalesCreditLimitApprovalStatus Add four elements to the Enum called NotSubmitted. 8. Demonstration: Add a WorkflowState Field Any form that uses the same table in the datasource as is specified in a workflow document is able to use that document for workflow. 11-8 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Enable Workflow on a Form Now that the workflow template is defined. Right-click on Fields and select New > Enum. 5. 4. 10. 2. 3. 3. To test this condition. You can specify conditions under which a workflow is eligible for submission. 7. Right-click on the SalesCreditLimitApproval workflow template and select save. 2. Open another AOT window. 1. Expand Data Dictionary. you can specify which forms will use this template. Submitted. Right-click on the SalesTable node and select Save. Change the EnumType property to SalesCreditLimitApprovalStatus. 6. Right-click on the newly created field and select Properties. Expand Workflow > Workflow Templates > SalesCreditLimitApproval. Expand Tables > SalesTable. Approved. This demonstration shows you how to attach an approval to a template. Drag the SalesCreditLimitApproval approval to the Required Elements node of the SalesCreditLimitApproval template. 7. 9. 1. use a new field on the SalesTable table. 7. 9. boolean canSubmitToWorkflow() { amountMST creditBalance.Chapter 11: Workflow Demonstration: Enable Workflow on the Form Workflow on the form is enabled using properties on the design node.amountRemainSalesFinancial() + this.CreditMax custTable. This demonstration shows you how to enable workflow on a form. Expand Forms > SalesTable > Designs. Open the AOT. 5. if (!custTable. Copy the second method in the following code into the method.CreditLimitApprovalStatus == SalesCreditLimitApprovalStatus::NotSubmitted) return false. } 1. Save the changes made to the table. creditBalance = custTable.amountRemainSalesPhysical() < creditBalance) return false. 6.balanceMST(). if (!this. return true. if (this. Expand Tables > SalesTable. Change the WorkflowDatasource property to SalesTable. and by overiding a form method.CreditMax) return false. custTable custTable.canSubmitToWorkflow().custTable_InvoiceAccount(). } public boolean canSubmitToWorkflow() { return salesTable. . 8. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-9 . 10. Create a new method and add the first method in the following code. 4. Right-click on the form Methods node and select Override Method > canSubmitToWorkflow. 2. custTable = this. 3. Right-click on the design node and select Properties. Change the WorkflowEnabled property to Yes. Press F8 to save and compile the code. Open another AOT and expand Menu Items. WorkflowCorrelationId workflowCorrelationId.record(). Open the AOT and create a new class. . recId recId = args. Change the SubmitToWorkFlowMenuItem property to SalesCreditLimitSubmit. // Initial note is the information that users enter when they // submit the document for workflow. Demonstration: Create a Submit to Workflow Class To submit a document to workflow. 2. 10. 1. WorkflowComment note ="".Development IV in Microsoft Dynamics® AX2009 The canSubmitToWorkflow method returns true if the ProjJournalTable record has not already been submitted and the total hours entered in the transactions is greater than 40. 4. 11. // Opens the submit to workflow dialog. Right-click on the SalesCreditLimitSubmit menu item and select Save. SalesTable SalesTable. 5.caller(). Right-click on the newly created Actions node and select Properties. 6. call standard code to prompt the user for a comment and to process the submisson. 11-10 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .getActiveWork flowConfiguration()). Locate the workflow template node in the AOT. Change the Label property to Submit. Right-click and select Properties. class SalesCreditLimitSubmit { } void submit(Args args) { // Variable declaration. 8. // Hardcoded template name WorkflowTemplateName workflowTemplateName = workflowtemplatestr(SalesCreditLimitApproval). workflowSubmitDialog = WorkflowSubmitDialog::construct(args. 9. 3. Drag the SalesCreditLimitSubmit class to the Actions node. WorkflowSubmitDialog workflowSubmitDialog.RecId. This demonstration shows you how to create a submit to workflow class. Copy the following code in to the classDeclaration. submit method and the main method. 7. } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-11 . . note = workflowSubmitDialog. SalesTable.record().submit(_args). NoYes::No). ttscommit.Chapter 11: Workflow workflowSubmitDialog. try { ttsbegin. note."). SalesCreditLimitSubmit. if (workflowSubmitDialog. // Send an Infolog message. } catch(exception::Error) { info("Error on workflow activation. } public static void main(Args _args) { SalesCreditLimitSubmit SalesCreditLimitSubmit = new SalesCreditLimitSubmit(). } } args.RecId. recId. workflowCorrelationId = Workflow::activateFromWorkflowTemplate(workflowTemplateName . // Get comments from the submit to workflow dialog. SalesTable = args.parmWorkflowComment(). info("Submitted to workflow.parmIsClosedOK()) { recId = args.record().updateWorkFlowControls().").caller().CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::Submitted.run(). Use this event handler to perform any clean up operations needed. This event raises when the workflow instance ends after it is canceled. Use this event handler to identify when a configuration has changed. 2. WorkflowCanceledEventHandler WorkflowConfigDataChangeEventHandler Demonstration: Add Workflow Level Event Handlers This demonstration shows you how to add workflow level event handlers. this event handler would raise if the configuration was deleted or updated. The interfaces at the workflow level are as follows: Event WorkflowStartedEventHandler WorkflowCompletedEventHandler Description This event raises when the workflow instance starts. This event raises when the workflow configuration data changes. Add the following ClassDeclaration and methods. for example when anyone approves or rejects a step in the approval. This event raises when the workflow instance ends after it is completed. or at an element level. For example. if you create an association between the application data and a workflow configuration. Open the properties form for the SalesCreditLimitApproval workflow template. Event handlers are implemented by creating a class that implements one or more of the EventHandler interfaces. Create a new class. 1. 11-12 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . for example when the workflow is started or completed. They can be implemented at the workflow level.Development IV in Microsoft Dynamics® AX2009 Create Event Handlers Event handlers are used to execute business logic at specific events in the workflow. } ttscommit. WorkflowCanceledEventHandler. SalesTable.RecId == _workflowEventArgs.Chapter 11: Workflow 3. CompletedEventHandler and CanceledEventHandler properties to SalesCreditLimitEventHandler class SalesCreditLimitEventHandler WorkflowStartedEventHandler.parmWorkflowContext(). select forupdate SalesTable where SalesTable. } Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-13 .parmRecId(). if (salesTable. ttsbegin. . WorkflowCompletedEventHandler { } implements public void cancelled(WorkflowEventArgs _workflowEventArgs) { SalesTable SalesTable.parmWorkflowContext().update(). SalesTable.RecId == _workflowEventArgs. Set StartedEventHandler.CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::NotSubmitted.CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::Approved. SalesTable.update(). . ttsbegin. } public void completed(WorkflowEventArgs _workflowEventArgs) { SalesTable SalesTable. ttscommit.parmRecId().CreditLimitApprovalStatus == SalesCreditLimitApprovalStatus::Submitted) { SalesTable. select forupdate SalesTable where SalesTable. } 11-14 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .parmRecId(). SalesTable.update(). SalesTable.CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::Submitted.RecId == _workflowEventArgs. SalesTable.parmWorkflowContext().parmRecId(). SalesTable. . . select forupdate SalesTable where SalesTable.parmWorkflowContext(). ttscommit.Development IV in Microsoft Dynamics® AX2009 public void returned(WorkflowEventArgs _workflowEventArgs) { SalesTable SalesTable.update(). ttsbegin.RecId == _workflowEventArgs. } public void started(WorkflowEventArgs _workflowEventArgs) { SalesTable SalesTable. ttscommit.CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::Rejected. ttsbegin. select forupdate SalesTable where SalesTable. This event raises when the task or approval is completed. you can use this event to transition the workflow document state from PendingApproval to RequestChange. This event raises when the task or approval is canceled. This event raises when an approver requests a change to the task or approval. you can use this event to transition the workflow document state from the current state to Canceled. For approvals. This event raises when the task or approval is returned to the originator. WorkflowElementCanceledEventHandler WorkflowElementCompletedEventHandler WorkflowElementReturnedEventHandler WorkflowElemChangeRequestedEventHandler Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-15 . For approvals.Chapter 11: Workflow Element Level Event Handlers The interfaces at the workflow element level are as follows: Event WorkflowElementStartedEventHandler Description This event raises when the task or approval starts. you can use this event to transition the workflow document state from Submitted to PendingApproval. For approvals. For approvals. For approvals. you can use this event to transition the workflow document state from PendingApproval to Approved. you can use this event to transition the workflow document state from the current state to RequestChange. 2. SalesTable. WorkflowElementStartedEventHandler { } public void returned(WorkflowEventArgs _workflowEventArgs) { SalesTable SalesTable. } 11-16 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 3. 4. WorkflowElementReturnedEventHandler. Find the SalesCreditLimitApproval Workflow Approval element Expand the node and open the properties for the Reject node. ttsbegin.RecId == _workflowEventArgs. 1.parmWorkflowContext(). SalesTable.update(). select forupdate SalesTable where SalesTable. Set the EventHandler property to SalesCreditLimitElementHandler class SalesCreditLimitElementHandler implements WorkflowElementCompletedEventHandler.Development IV in Microsoft Dynamics® AX2009 Demonstration: Add Element Level Event Handlers This demonstration shows you how to add element level event handlers. WorkflowElementCanceledEventHandler.parmRecId(). ttscommit. . Create a class and add the following ClassDeclaration and methods.CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::Rejected. WorkflowElemChangeRequestedEventHandler. Demonstration: Configuring a Workflow This demonstration shows you how to configure a workflow from the main menu. Click Set as default. 10. 4. 2. 3. 4. Open the AOT. Click Start. Right-click on this form and select Open. 7. expand SalesCreditLineApproval. Select Sales credit limit approval and click Create configuration. Click the submit button and enter a comment. 9. Click the Choose button. enter "Please approve" and then click OK. 6. 12. The workflow is now ready for use. Click the Overview tab. 7. 2. 9. 11. 6.Chapter 11: Workflow Configure a Workflow Now that you have created a template and enabled it on a form. enter a user in the Select users field and then click OK. 8. 5. 8. and click on Step 1. Open the main menu and select Accounts Receivable > Setup > Workflow configurations. On the configuration form click Set as active. Expand the Forms node. 13. Click New. 3. Select a customer from the customer table and set a credit limit. click on Assignment tab. Demonstration: Test the Workflow This demonstration shows you how to can test the workflow by creating a timesheet 1. 1. Enter "Credit limit approval" as the name. Select User based. Under Step details. Create a new sales order and create lines such that the balance of the customer plus the total amount on the lines is greater than the credit limit. you can configure it for use. Find the form Tutorial_WorkFlowProcessor. 5. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-17 . Click the Details tab. Close the approval form. Click Create Instruction. The workflow submit button and dialog should appear. 12. 11. 15. Open the Tutorial_WorkflowProcessor form again and click Start.Development IV in Microsoft Dynamics® AX2009 10. When the form says that it has zero records in queue. 11-18 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . Logon as the user who should approve the sales order 13. 16. You will see that the document is waiting for approval by the person you assigned to approve it. wait for it to complete and click Stop. click Stop and go back to the sales table form. Select Actions > History. The workflow has now been approved. 14. Open the sales order form. Click the workflow Actions button and select Approve. CreditLimitApprovalStatus == SalesCreditLimitApprovalStatus::Approved) return true.CreditLimitApprovalStatus == SalesCreditLimitApprovalStatus::Rejected || this. If the credit limit has not been reached. . boolean canPostCreditLimit() { amountMST creditBalance.custTable_InvoiceAccount().amountRemainSalesFinancial() + this. return false. if (this. Add the following method CanPostCreditLimit to the salesTable table.amountRemainSalesPhysical() < creditBalance) return true.1 . Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-19 .Add Another Condition to the Submit Action Scenario Isaac has been asked to ensure that.CreditLimitApprovalStatus == SalesCreditLimitApprovalStatus::Submitted) return false. packing or invoicing until the workflow has been approved. custTable custTable.Chapter 11: Workflow Lab 11. Step by Step 1. if (this.CreditMax custTable. Challenge Yourself! Add conditions to the posting functions on the sales order form that will prevent posting to picking. if (!custTable. custTable = this.CreditMax) return true. the sales order cannot be posted until the workflow has been approved.balanceMST(). creditBalance = custTable. once a credit limit has been reached. then the postings should be allowed. canPackingSlipBeUpdated() and canInvoiceBeUpdated() in the salesTableType class. Add the following code to the methods canPickingListBeUpdate(). 2. if (this. } boolean canPackingslipBeUpdated() { . 1. workflowSubmitDialog. ok = ok && salesTable.canPostCreditLimit(). the main() method in the submit to workflow class is called.run()....canPostCreditLimit(). ok = ok && salesTable..getActiveWork flowConfiguration()).. ok = ok && salesTable.. return ok.caller()..Development IV in Microsoft Dynamics® AX2009 } boolean canPickingListBeUpdated() { . return ok.main() method created in the Create A Submit to Workflow Class demonstration. return ok....canPostCreditLimit(). View the ProjTimeApprovalsSTWF. } boolean canInvoiceBeUpdated() { .. } Code Walkthrough: Submitting a workflow When a record is submitted to workflow... 11-20 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement ... The user is prompted for a comment while submitting the workflow workflowSubmitDialog = WorkflowSubmitDialog::construct(args. WorkFlowState = true. _initialNote.main() method ProjJournalTable. tableId. _recId. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-21 . View the method Workflow::activateFromWorkflowTemplate() tableId = Workflow::getDocumentTableId(_workflowTemplateName). _activatingFromWeb). } 3.parmWorkflowComment(). 2. configTable. _recId. The journal is marked as submitted. correlationId). configTable = Workflow::findWorkflowConfigToActivateForTemplate(_workflow TemplateName. The SysWorkFlowEventDispatcher class creates records that will be read by the Workflow Processor class to determine which actions should be executed in the next step of the workflow.record(). tableId). _workflowCorrelationId = Workflow::activateFromWorkflowTemplate(_workflowTemplateNam e. try { SysWorkflowEventDispatcher::onWorkflowSubmit(workflowContex t. ProjJournalTable = args. // Activate the workflow. try { ttsbegin. workflowContext = WorkflowContext::newRootWorkflowContext(curext(). // Get comments from the submit to workflow dialog. _submittingUser.ConfigurationId. which runs the submit process. _recId.Chapter 11: Workflow The record is retrieved from the calling form and the recId is passed to the static method Workflow::activateFromWorkflowTemplate(). The workFlowContext class holds all the relevant data for the workflow submission. NoYes::No). Return to the ProjTimeApprovalsSTWF. The tableId that the workflow is to be performed on is retrieved from the query specified in the workflow document class. _initialNote = workflowSubmitDialog. _initialNote. DueDateTime < DateTimeUtil::getSystemDateTime() { WorkflowWorkItem::escalateWorkItem(SysWorkflowWorkItemConte xt::newWorkflowWorkItemContextFromWorkItem(workflowWorkItem Table)).parmWorkflowActivityInstanceKey().Development IV in Microsoft Dynamics® AX2009 Code Walkthrough: Workflow Processor All workflows are processed through a batch process. based on the configuration. View the method SysWorkflowEventDispatcher::onWorkItemEscalation() workItemTable = WorkflowWorkItemTable::findPendingActivityInstanceId(_workI temContext. true). 11-22 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . The workItemTable record is retrieved.parmWorkflowAc tivityInstanceId(). View the method WorkflowWorkItem::escalateWorkItem() try { workItemId = SysWorkflowEventDispatcher::onWorkItemEscalation(_workItemC ontext). This is the next pending activity on the workflow.Status == WorkflowWorkItemStatus::Delegated) && workflowWorkItemTable. cntWorkItems++. The WorkflowWorkItem::escalateWorkItem() is called 2. 1. } All records due for processing are retrieved. use the form Tutorial_WorkflowProcessor. To view a simulation of how the workflows are processed.Type == WorkflowWorkItemType::WorkItem && (workflowWorkItemTable. View the form method doMessageProcessing on the form Tutorial_WorkflowProcessor.Status == WorkflowWorkItemStatus::Pending || workflowWorkItemTable. } 3. while select workflowWorkItemTable where workflowWorkItemTable. workItemTable. workItemTable.EscalationType) { case WorkflowEscalationType::Action: workItemInstanceId = workItemTable.EscalationAction.Id.UserId. stepTable.Originator. workflowTable. // always set the autoescalate user to the workflow originator "@SYS110277").Chapter 11: Workflow The action to be performed is examined switch (stepTable. The next step is completed. workItemTable. Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-23 .Status = SysWorkflowEventDispatcher::completeWorkItem( _workItemContext. Enable Resubmit Scenario Issac is required to ensure the workflow can be resubmitted after it has been rejected. it should be able to be resubmitted. } } void resubmit(Args args) { // Variable declaration. set the ResubmitMenuItem property to SalesCreditLimitResubmit public static void main(Args _args) { SalesCreditLimitSubmit SalesCreditLimitSubmit = new SalesCreditLimitSubmit().submit(_args). // Hardcoded template name WorkflowTemplateName _workflowTemplateName = workflowtemplatestr(SalesCreditLimitApproval).2 . On the SalesCreditLimitApproval approval element. WorkflowCorrelationId _workflowCorrelationId. 3. the Object property to SalesCreditLimitSubmit and the Label property to Resubmit.Development IV in Microsoft Dynamics® AX2009 Lab 11. 11-24 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .menuItemName() == menuitemactionstr(SalesCreditLimitSubmit)) { SalesCreditLimitSubmit. } else { SalesCreditLimitSubmit. if (_args. Challenge Yourself! When a workflow is rejected.RecId. Step by Step 1. . recId _recId = args.record(). Modify the Submit to Workflow class so that it can resubmit the workflow after a rejection Use the PurchReqWorkflow class as inspriration.resubmit(_args). Create a new action menu item called SalesCreditLimitResubmit 2. Set the ObjectTypePropety to class. Modify the Main method on the SalesCreditLimitSubmit class and add a new method Resubmit as follows: 4. parmIsClosedOK()) { _recId = args.record(). // Get comments from the submit to workflow dialog. SalesTable SalesTable. .getActiveWorkflowWorkItem(). // Opens the submit to workflow dialog.record(). WorkflowWorkItemActionType::Resubmit.caller(). WorkflowWorkItemActionDialog WorkflowWorkItemActionDialog. info("Resubmitted to workflow. workflowWorkItemActionDialog.run(). MenuItemType::Action)). _initialNote. WorkflowWorkItemActionType::Resubmit. new MenuFunction(menuitemactionstr(PurchReqReSubmit). try { ttsbegin.RecId. SalesTable. if (WorkflowWorkItemActionDialog.parmWorkflowComment().CreditLimitApprovalStatus = SalesCreditLimitApprovalStatus::Submitted. _initialNote = workflowWorkItemActionDialog. false). Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-25 . curUserId()."). WorkflowWorkItemActionManager::dispatchWorkItemAction( args.menuItemName().caller(). SalesTable = args.Chapter 11: Workflow // Initial note is the information that users enter when they // submit the document for workflow. args.getActiveWorkflowWorkItem(). // Send an Infolog message. WorkflowComment _initialNote ="". workflowWorkItemActionDialog = WorkflowWorkItemActionDialog::construct( args. Development IV in Microsoft Dynamics® AX2009 ttscommit. 11-26 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . } Summary The workflow module is a highly configurable and flexible module. by using Morph X and some standard code templates. } catch(exception::Error) { info("Error on workflow activation. it can be configured for any part of the Microsoft Dynamics AX application. This lesson explores some of the possibilities the workflow framework offers. However.").updateWorkFlowControls().caller(). } } args. and explores some of the different ways it can be used to cover most workflow requirements. Which two properties on a form data source need to be modified to allow the form to use a workflow? ( ) WorkflowTemplate ( ) WorkflowEnabled ( ) WorkflowDocument ( ) WorkflowDatasource Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-27 . Which type of AOT element needs to be created to specify which tables will be affected by a workflow? ( ) Extended data type ( ) Class ( ) Form ( ) Query 3. Which application element is used to define to which module a workflow is applicable? ( ) Workflow template ( ) Workflow category ( ) A field in the workflow configuration ( ) SalesTable 2. What are they? ( ) Participant provider ( ) DueDate provider ( ) Hierarchy provider ( ) Internet provider 4.Chapter 11: Workflow Test Your Knowledge 1. There are three types of providers that define what rules the workflow can follow. Development IV in Microsoft Dynamics® AX2009 Quick Interaction: Lessons Learned Take a moment and write down three key points you have learned from this chapter 1. 3. 11-28 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement . 2. What are they? (√) Participant provider (√) DueDate provider (√) Hierarchy provider ( ) Internet provider 4.Chapter 11: Workflow Solutions Test Your Knowledge 1. Which two properties on a form data source need to be modified to allow the form to use a workflow? ( ) WorkflowTemplate (√) WorkflowEnabled ( ) WorkflowDocument (√) WorkflowDatasource Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement 11-29 . Which application element is used to define to which module a workflow is applicable? ( ) Workflow template (•) Workflow category ( ) A field in the workflow configuration ( ) SalesTable 2. Which type of AOT element needs to be created to specify which tables will be affected by a workflow? ( ) Extended data type ( ) Class ( ) Form (•) Query 3. There are three types of providers that define what rules the workflow can follow. Development IV in Microsoft Dynamics® AX2009 11-30 Microsoft Official Training Materials for Microsoft Dynamics ® Your use of this content is subject to your current services agreement .