Skip to main content

Posts

Showing posts with the label Job

Workflow hierarchy limit checker for D365FO

A couple of years back I wrote a post on a workflow hierarchy limit checker job . It was a simple job that took a starting worker and traversed up the hierarchy. It printed the userid/worker/position/manager/spending limit/approval limit in an info log. Today I rewrote it slightly to use a dialog for D365FO. Since it is not possible to change the code that easily in D365. This currently only works for Expenses. Its not pretty at the moment but it works. I intentionally left the error in there. This will print the same error as what the workflow engine would. Hopefully this would give you a clue on where it stops. Hopefully I can come back and extend it to the other document types such as purchase requisition and purchase orders. Code is available on GitHub . I gave it a generic name like “Workflow plus”. I hope to add a few other nice commonly used workflow enhancements to it. Another common enhancement I can think of is - Purchase order spending and approval limit; currently you don’t...

“Error in getting SID” when running Named user license count report [AX 2012]

Recently I tried running the Named user license count report and got this error. “Error in getting SID” From the error I know what the problem is. One of the users can not be found in Active directory. I wrote a quick job to find me the invalid users. static void navax_findBadUserNames ( Args _args ) { UserInfo userInfo ; container con ; ;    while select forUpdate userInfo where userInfo . Enable && userInfo . AccountType != UserAccountType :: ADGroup { con = SysUserLicenseMiner :: getUserRoles ( [ userInfo . Id , userInfo . company ] ) ; if ( conLen ( con ) == 0 ) { warning ( strFmt ( "Userid: %1, username: %2" , UserInfo . networkAlias , UserInfo . name ) ) ; } } } You will get something like this in the infolog.

Import ledger alias with a job [AX 2012]

I wrote a job to import the ledger alias in 2012. It is fairly straight forward if you have the DMF installed. Create a csv file with the following: End result will be: Code: //Name,Type,company,Account alias definition,initial focus //test,Shared,CEED,401100-CR_GEN1-OU_3566-Training,MainAccount static void importLedgerAccountAlias( Args _args) { //dialog AsciiIO asciiIO; Filename filename; NoYesId skipFirstLine; Container line; Dialog dialog; DialogField dialogFileName, dialogSkipFirstLine, dialogCountryRegionId; //tables DimensionAlias dimensionAlias ; Ledger ledger; //fields to import DimensionAliasName aliasName; DimensionAliasType aliasType; LedgerName ...

Delete Private AOT projects in AX 2012

This is a common problem since the old days. People leave projects in their private project and no one can get to it to clean it up. In pre AX2012, it was a matter of selecting the utilElements and calling the AOTDelete method. I won’t go through it here. In AX2012, it is all maintained in the model store. Let see it in pictures. Below are the projects you want to delete. You can see them in the SysModelElement table. It is in the system tables section. I wrote a job to loop through and delete them. I had to Code: static void deleteAllProjectObjects3( Args _args) { /* msdn.microsoft.com/en-us/library/bb190038(v=ax.10).aspx */ SysModelElement sysModelElement; ProjectNode privatePn; ProjectNode pn; utilElementName shortName; int len; str preFix; // Navigate to the Private projects folder. privatePn = infolog.projectRootNode().AOTfindChild( "Private" ); ...

AX - Import flat file job

I use this quite often. When I want a quick job to import a text file. static void ImportFileWithDialog(Args _args) { AsciiIO asciiIO; Filename filename; NoYesId skipFirstLine; Container line; Dialog dialog; DialogField dialogFileName, dialogSkipFirstLine; ; dialog = new Dialog("Import file"); dialogFileName = dialog.addField(typeid(Filenameopen), "File name"); dialogSkipFirstLine = dialog.addField(typeid(NoYesId), "Skip first line"); dialog.run(); if (dialog.run()) { filename = dialogFileName.value(); skipFirstLine = dialogSkipFirstLine.value(); } asciiIO = new AsciiIO(filename, 'R'); if (!asciiIO || asciiIO.status() != IO_Status::Ok ) { throw error (strfmt("@SYS19312",filename)); } ttsbegin; asciiIO.inRecordDelimiter('\r\n'); asciiIO.inFieldDelimiter(',')...