How to implement Runbase form in AX
Today I had a requirement that allow users to run Outlook synchronization process in batch rather sync it manually using out of the box functionality. Let’s have a look on existing functionality and then extend it to achieve the requirement of running it in batch. Existing functionality in AX Home> Periodic > Synchronize [AOT form name is smmOutlookSyncrhonization] As you can see someone has to manually sync outlook emails to AX acvitities or viceversa. Extended functionality in AX Let’s implement this functionality in batch so users can set recurrence the Sync. Create a new class; class SyncOutLookEmails_RunbaseForm extends RunBaseBatch { // Packed TransDate testDate; // I am using this variable for own testing purpose #define.CurrentVersion(2) #define.Version1(2) #localmacro.CurrentList testDate #endmacro } public Object dialog() { DialogRunbase dialog = Dialog::newFormnameRunbase(formstr(smmOutlookSyncrhonization),this); ; return dialog; } public boolean getFromDialog() { boolean ret; ret = super(); return ret; } protected void new() { super(); } public container pack() { return [#CurrentVersion,#CurrentList]; } public boolean runsImpersonated() { return true; } public boolean showQueryValues() { return true; } public boolean unpack(container _packedClass) { boolean ret; Version version = RunBase::getVersion(_packedClass); ; switch (version) { case #CurrentVersion: [version, #CurrentList] = _packedClass; ret = true; break; default: ret = false; break; } return ret; } server static SyncOutLookEmails_RunbaseForm construct() { return new SyncOutLookEmails_RunbaseForm(); } server static void main(Args args) { SyncOutLookEmails_RunbaseForm syncOutLookEmails_RunbaseForm = SyncOutLookEmails_RunbaseForm::construct(); if (syncOutLookEmails_RunbaseForm.prompt()) syncOutLookEmails_RunbaseForm.run(); } Run this class by pressing F5, Ooopsss!!! it throws an error A DialogStartGrp group is missing from the form smmOutlookSyncrhonization. In this group dialog controls are added. This requires to add a group on the form and this has to have under a tab/tab page, let’s do this; How the current form looks in AOT How it should look like to use it for batch class, created above. Added new Tab Added new Tab page Added dialogStartGrp under tab page Moved exisiting groups under tab page Set caption “General” to tab page. It requires few more methods at form level to make it working in batch public class FormRun extends ObjectRun { HcmWorker hcmWorker; OutlookUserSetup outlookUserSetup; TransDate synchronizeFromDate; TransDate synchronizeToDate; SyncOutLookEmails_RunbaseForm syncOutLookEmails_RunbaseForm; } public void init() { synchronizeFromDate = systemdateget(); synchronizeToDate = systemdateget(); syncOutLookEmails_RunbaseForm = element.args().caller().runbase(); super(); if (!smmAxaptaOutlookMapping::isOutlookMappingSetupCompleted()) { smmAxaptaOutlookMapping::createDefaultSetup(); } // Find worker connected to the current logged ion hcmWorker = HcmWorker::find(HcmWorker::userId2Worker(curuserid())); if (hcmWorker) { outlookUserSetup = OutlookUserSetup::findByWorker(hcmWorker.RecId); // Calculate synchronization period based on the employee setup parameters activityFromDate.dateValue(systemdateget() – outlookUserSetup.SmmSynchronizeDaysBack); activityToDate.dateValue(systemdateget() + outlookUserSetup.SmmSynchronizeDaysForward); } else { // No employee is mapped to the current user. Set mapping in Employee option form. error(“@SYS80637”); element.close(); } } void closeOk() { DialogRunbase dialog = element.args().caller(); ; dialog.updateServer(); if (syncOutLookEmails_RunbaseForm.checkCloseDialog()) super(); } //AOSRunMode::Client RunBase runBase() { return syncOutLookEmails_RunbaseForm; } Run class again by pressing F5 Target achieved!!! You can run the form with batch Happy Dax!ng !!!
AX 7 Development introduction exam available now
Exam MB6-890 https://www.microsoft.com/en-us/learning/exam-mb6-890.aspx
Sales quotation GST through X++
X++ code to achieve this; static void SalesTax_Per_SalesQuotation(Args _args) { SalesQuotationTable salesQuotationTable; SalesQuotationTotals salesQuotationTotals; container cont; salesQuotationTotals = SalesQuotationTotals::construct(SalesQuotationTable::find(“QUOT000022”)); salesQuotationTotals.calc(); cont = salesQuotationTotals.displayFieldsCurrency(salesQuotationTotals.currencyCode()); info(strFmt(“Sales quotation total GST: %1”, conpeek(cont, TradeTotals::posTaxTotal()))); }
GST/TAX at sales order and sales line level through X++
Sales order GST: Total GST of Sales order can be seen from following screen in AX 2012 X++ code to achieve this; static void SalesTax_Per_SalesOrder(Args _args) { TaxTmpWorkTransForm taxTmpWorkTransForm; SalesTotals salesTotals; TaxSales taxSales; SalesLine salesLine; container cont; salesTotals = SalesTotals::construct(SalesTable::find(“SAOR000770”)); salesTotals.calc(); cont = salesTotals.displayFieldsCurrency(salesTotals.currencyCode()); info(strFmt(“Sales order total GST: %1”, conpeek(cont, TradeTotals::posTaxTotal()))); } X++ code to achieve this; This code will print GST against each sales line for selected/passed sales order static void SalesTax_Per_SalesLine(Args _args) { TaxTmpWorkTransForm taxTmpWorkTransForm; SalesTotals salesTotals; TaxSales taxSales; SalesLine salesLine; salesTotals = SalesTotals::construct(SalesTable::find(“SAOR000770”)); salesTotals.calc(); taxSales = salesTotals.tax(); taxTmpWorkTransForm = TaxTmpWorkTransForm::construct(); taxTmpWorkTransForm.parmTaxObject(taxSales); While select SalesLine where salesLine.SalesId == ‘SAOR000770’ { taxTmpWorkTransForm.updateTaxShowTaxesSourceSingleLine(tableNum(SalesLine), salesLine.RecId, true); info(strFmt(‘%1’,taxTmpWorkTransForm.parmTaxAmountCurTotal())); } }
How to get Next RecId through X++
Below piece of code can be used to retrieve next record Id from the table. static void getNextRecId(Args _args) { //Table that stores record ids details for tables SystemSequences systemSequences; //Class that handles Record id generation SystemSequence systemSequence = new SystemSequence(); ; info(strFmt(“%1”, tableNum(SalesTable))); systemSequence.suspendRecIds(tableNum(SalesTable)); info(strFmt(“Next record id: %1”, systemSequence.reserveValues(1,tableNum(SalesTable)))); systemSequence.removeRecIdSuspension(tableNum(SalesTable)); }
Lifecycle issue search directly from AX 2012 R3
AX 2012 R3 comes with new feature of searching any issue, if there is any, against each AOT object. Let’s take example of SalesTable table and try to lookup issues reported for this object in LCS. It will redirect you LCS site, and requires Partner or Customer source Id to log in. It lists the total number of issues against SalesTable table along with all hotfixes information.
PostLoad() method in AX tables
Today I found an interesting thing with regards to AX tables and this post is all about this new experience which is the PostLoad() method in AX tables. When we create a new table in AOT, Morphx automatically creates a series of methods for it. We cannot see those methods but those can be overriden on each table as per requirements. PostLoad() is one of these system methods. List of all system methods can be seen from here https://msdn.microsoft.com/en-us/library/aa625830.aspx Lets create a new table, I named it PostLoadTable with two fields Name and Value. I added 5 records in the table manually (open table and added). Tables in Microsoft Dynamics AX have a number of system-defined methods, such as insert, validateField,validateWrite. For a list of these methods, see the xRecord system class. The xRecord class can be seen as the base class for the Common table. The Common table can be seen as the base table for all tables. In any table class, the body of each system-defined method contains only a call to super(). When you edit the X++ code in a table method, you override the parent’s implementation of that method. Usually the call to super() must remain in the methods that you edit. PostLoad() is the method that is used to read records from database and you can perform any custom logic by overriding this method on any table. Let’s override this method and play around it public void postLoad() { super(); if (this.Name == ‘MEL’) this.Value = 5; } By opening table again it shows me different result as compared to what we entered earlier as shown above. Value for name MEL changes from 1 to 5 and I did not require to call update method. There are many existing implementation of postLoad method in AX tables, I am listing few of them here for ease. HCMWorkerTablepostLoad() VendTransPostLoad() CustTransPostLoad()
How to check table size from SQL server
We often require to check size of the table to moniter database performance, specially working with files and storing it in database. AX does store files in database which can be setup under Document types in Document Management module. We can use following sql command to get table size; sp_spaceused docuValue
Retrieve worker email address through X++
Below code snipet is one of the way to retrieve employee/worker’s primary email address. private LogisticsElectronicAddressLocator getInstructorEmail(HcmWorkerRecId _workerRecId) { LogisticsElectronicAddress logisticsElectronicAddress; HcmWorker hcmWorker; DirPerson dirPerson; DirPartyTable dirPartyTable; select hcmWorker where hcmWorker.RecId == _workerRecId join dirPerson where dirPerson.RecId == hcmWorker.Person join dirPartyTable where dirPartyTable.RecId == dirPerson.RecId join logisticsElectronicAddress where dirPartyTable.PrimaryContactEmail == logisticsElectronicAddress.RecId; return logisticsElectronicAddress.Locator; }
AX 2012 upgrade – Connect to source database failure
During database upgrade checklist I was failed to connect with source database. I followed the suggested steps from upgrade guide as pasted below but these weren’t enough in my case for successful connection. Configure matching user permissions Windows integrated security is used to connect to the source database from the target system. If the administrative user who is performing the upgrade on the target system does not have access to the source system database, the source system will reject the database connection. Open Microsoft SQL Server Management Studio on the source system and perform the following steps: 1. Grant Microsoft Dynamics AX database access to a domain user with administrative privileges on the target Microsoft Dynamics AX 2012 system. 2. Add the user to the db_owner and public roles. SOLUTION: Make sure you have assigned sysadmin role to the AOS service account from SQL management studio under this path SQLSERVERINSTANCESecurityLogins<AOSService Account>. Right click on AOSService account and choose Server Roles from left hand side panel and assign sysadmin role listed on right hand side.
