Tuesday, May 21, 2019

Post Sales Order Confirmation X++

Generate post sales order confirmation from X++

SalesTable salesTable = SalesTable::find(“000747”);
SalesFormLetter salesFormLetter;

salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);
salesFormLetter.update(salesTable, systemDateGet(), SalesUpdate::All);

Change Report name of original invoice

modify method runprintmgmt in  SalesInvoiceController

if(formLetterReport.moveNextPrintSetting())
            {
                printSettingDetail = formLetterReport.getCurrentPrintSetting();

                if(printSettingDetail.parmReportFormatName() == PrintMgmtDocType::construct(PrintMgmtDocumentType::SalesOrderInvoice).getDefaultReportFormat())
                {
                    this.parmReportName(ssrsReportStr(SalesInvoiceCopy, Report));
                 
                }
                printSettingDetail.parmReportFormatName(this.parmReportName());
                this.resetReportDataContract();
                formLetterReport.parmReportRun().loadSettingDetail(printSettingDetail);
            }

Tuesday, May 14, 2019

Get all Security roles with related Privileges duties permissions and related paths of menuitem


This post will guid you to get all security roles with it related privileges duties permissions with related paths of menu item

Run this job to fill SysSecFlatDataTable, after job complete process you can open form from AOT SysSecObjectsInRole to confirm data population.

static void updateSecurityData(Args _args)
{
   sECURITYROLE secRoleTbl;

   SecuritySubRole secSubRoleTbl;

   SECURITYROLE secSubRoles;

   SecurityRoleTaskGrant secRoleTaskGrantTbl;

   SecurityTask secTaskTbl;

   SecurityTaskExplodedGraph secTaskExplodedGraphTbl;

   SecurityTask privilegesTbl;

   SecurityTaskEntryPoint secTaskEntryPointTbl;

   SecurableObject entryPointTbl;

   SysSecFlatDataTable dataTable;

   delete_from dataTable;



   while select * from secRoleTbl

       outer join * from secSubRoleTbl where (secSubRoleTbl.SecurityRole == secRoleTbl.RecId)

       outer join * from secSubRoles where (secSubRoleTbl.SecuritySubRole == secSubRoles.RecId)

       join   * from secRoleTaskGrantTbl where(secRoleTbl.RECID == secRoleTaskGrantTbl.SECURITYROLE || secSubRoles.RECID == secRoleTaskGrantTbl.SECURITYROLE)

       join * from secTaskTbl where (secRoleTaskGrantTbl.SECURITYTASK == secTaskTbl.RECID)

       join * from secTaskExplodedGraphTbl where (secTaskExplodedGraphTbl.SECURITYTASK == secTaskTbl.RECID)

       join * from privilegesTbl where (secTaskExplodedGraphTbl.SECURITYSUBTASK == privilegesTbl.RECID)

       join * from secTaskEntryPointTbl where (secTaskExplodedGraphTbl.SECURITYSUBTASK == secTaskEntryPointTbl.SECURITYTASK)

       join * from entryPointTbl where secTaskEntryPointTbl.ENTRYPOINT == entryPointTbl.RECID

       {
             ttsbegin;
           SysSecObjectsMiner::AddRelatedRolesRecToDataTable(dataTable, secRoleTbl.RecId, secRoleTbl.AOTNAME, secRoleTbl.NAME,

            secSubRoles.RecId, secSubRoles.AotName, secSubRoles.Name, secTaskTbl.RecId, secTaskTbl.AOTNAME, secTaskTbl.NAME, privilegesTbl.RecId, privilegesTbl.AOTNAME, privilegesTbl.NAME,

           entryPointTbl.RecId, entryPointTbl.NAME, entryPointTbl.TYPE, secTaskEntryPointTbl.PERMISSIONGROUP);
            ttscommit;

   }

}

And then run this job to truncate and run batch job to update Xref Tables

static void UpdateCrossRefBatch(Args _args)

{

    ;

    xRefUpdate::truncateXrefTables();

    xRefUpdateIL::updateAllXref(true, false, true);

    info("Done, cross reference update batch job created.");


}

And then create table with 2 field path string 900 and RefRecId recid to be filled by below jobs


static void updatePathData(Args _args)
{
    Custom_SecurityPaths Custom_SecurityPaths;
    SysSecFlatDataTable SysSecFlatDataTable;
    #TreeNodeSysNodeType

   #Properties

   #AOT

   TreeNode menuItemNode = TreeNode::findNode(@"\Menu Items\Display\CustTableListPage");

   TreeNode menuNode;

   xRefPaths xRefPaths;

   xRefReferences xRefReferences;

   TreeNode parentNode;

   Str path;
    while select SysSecFlatDataTable where SysSecFlatDataTable.EntryPointType==SecurableType::MenuItemDisplay && SysSecFlatDataTable.EntryPoint>''{
      menuItemNode = TreeNode::findNode(@"\Menu Items\Display\"+SysSecFlatDataTable.EntryPoint);

   xRefPaths = xRefPaths::find(menuItemNode.treeNodePath());

       while select xRefReferences

           where xRefReferences.referencePathRecId == xRefPaths.RecId

           && xRefReferences.Reference == XRefReference::Read

       {

           path = SysLabel::labelId2String(menuItemNode.AOTgetProperty(#PropertyLabel));

           menuNode = TreeNode::findNode(xRefPaths::findRecId(xRefReferences.xRefPathRecId).Path);

           if(menuNode && SysTreeNode::path2ApplObjectType(menuNode.treeNodePath()) == UtilElementType::Menu)

           {

               parentNode = menuNode.AOTparent();

               while(parentNode && parentNode.treeNodePath() != #MenusPath)

               {

                   path = SysLabel::labelId2String(parentNode.AOTgetProperty(#PropertyLabel))  + " > " + path;

                   parentNode = parentNode.AOTparent();

               }
            Custom_SecurityPaths.clear();
            Custom_SecurityPaths.Path=path;// info(path);
            Custom_SecurityPaths.RefRecid=SysSecFlatDataTable.RecId;
            Custom_SecurityPaths.doInsert();

           }
while select SysSecFlatDataTable where SysSecFlatDataTable.EntryPointType==SecurableType::MenuItemDisplay && SysSecFlatDataTable.EntryPoint>''{
      menuItemNode = TreeNode::findNode(@"\Menu Items\Action\"+SysSecFlatDataTable.EntryPoint);

   xRefPaths = xRefPaths::find(menuItemNode.treeNodePath());

       while select xRefReferences

           where xRefReferences.referencePathRecId == xRefPaths.RecId

           && xRefReferences.Reference == XRefReference::Read

       {

           path = SysLabel::labelId2String(menuItemNode.AOTgetProperty(#PropertyLabel));

           menuNode = TreeNode::findNode(xRefPaths::findRecId(xRefReferences.xRefPathRecId).Path);

           if(menuNode && SysTreeNode::path2ApplObjectType(menuNode.treeNodePath()) == UtilElementType::Menu)

           {

               parentNode = menuNode.AOTparent();

               while(parentNode && parentNode.treeNodePath() != #MenusPath)

               {

                   path = SysLabel::labelId2String(parentNode.AOTgetProperty(#PropertyLabel))  + " > " + path;

                   parentNode = parentNode.AOTparent();

               }
            Custom_SecurityPaths.clear();
            Custom_SecurityPaths.Path=path;// info(path);
            Custom_SecurityPaths.RefRecid=SysSecFlatDataTable.RecId;
            Custom_SecurityPaths.doInsert();

           }
while select SysSecFlatDataTable where SysSecFlatDataTable.EntryPointType==SecurableType::MenuItemDisplay && SysSecFlatDataTable.EntryPoint>''{
      menuItemNode = TreeNode::findNode(@"\Menu Items\Output\"+SysSecFlatDataTable.EntryPoint);

   xRefPaths = xRefPaths::find(menuItemNode.treeNodePath());

       while select xRefReferences

           where xRefReferences.referencePathRecId == xRefPaths.RecId

           && xRefReferences.Reference == XRefReference::Read

       {

           path = SysLabel::labelId2String(menuItemNode.AOTgetProperty(#PropertyLabel));

           menuNode = TreeNode::findNode(xRefPaths::findRecId(xRefReferences.xRefPathRecId).Path);

           if(menuNode && SysTreeNode::path2ApplObjectType(menuNode.treeNodePath()) == UtilElementType::Menu)

           {

               parentNode = menuNode.AOTparent();

               while(parentNode && parentNode.treeNodePath() != #MenusPath)

               {

                   path = SysLabel::labelId2String(parentNode.AOTgetProperty(#PropertyLabel))  + " > " + path;

                   parentNode = parentNode.AOTparent();

               }
            Custom_SecurityPaths.clear();
            Custom_SecurityPaths.Path=path;// info(path);
            Custom_SecurityPaths.RefRecid=SysSecFlatDataTable.RecId;
            Custom_SecurityPaths.doInsert();

           }


       }

}

}

Then outer join the paths table with SysSecFlatDataTable 1:n and you will get each role and entry point path with access

Sunday, May 12, 2019

AX2012 : CIL generation error : The given key was not present in the dictionary.

Recently I faced this error when generating incremental IL 
"CIL generation: The given key was not present in the dictionary."

The quick way to fix this is to check the CIL log file, generally located at "C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL\Dynamics.Ax.Application.dll.log"

Here you will find the AOT object for which the CIL generator found the error. Compile that object, fix the error and then regenerate the IL. 

Before generating IL it is good practise to make sure that there are no compilation errors in the code. 

How to create a batch Job in AX 2012


The Batch Job can be created in Different manners. I am explaining one way for it.
Steps:
Create a class for the logic what you want you want to do.
Add this class with the Batch Job.
run the Batch Job.
Note: If you want to run the batch job in the client mode to one more step needed.
4) run the batch job in client mode.

Step:1
I am creating a simple class .
go to classes node in the AOT. create a New Class name it. Open Class Declaration
and extend it to the RunBaseBatch class.
class Batch4Demo extends RunBaseBatch
{
}
after this override the run method of the class. Right click on the class in the AOT go to Override and select run method. in this run methode write your own logic like as shown bellow.
public void run()
{
//Code logic
}
after this override pack and unpack methods.
public container pack()
{
return conNull();
}
public boolean unpack(container packedClass)
{
return true;
}
now create a main method foe the class and call the run method in that
(this is very important with out main you cant run the class)
right click and add new method write following code.
private void main(Args _Args)
{
    Classname b = new classname(); //name of the class
    b.run();
}

Step:2
Create a Job in the Job Node of AOT write the following code in it.
static void EEMC_SecurityRoleBatch(Args _args)
{

    BatchHeader batHeader;
    BatchInfo batInfo;
    RunBaseBatch srTask;
    str sParmCaption = "Security Role Update Batch Job";
    ;
    srTask = new classname();
    batInfo= srTask .batchInfo();
    batInfo.parmCaption(sParmCaption);
    batInfo.parmGroupId(""); // The "Empty batch group".
    batHeader = BatchHeader ::construct();
    batHeader.addTask(srTask);
    batHeader.save();
    info(strFmt("'%1' batch has been scheduled.", sParmCaption));
}
Step:3
Now Compile the Job And Class. run the Batch Job by pressing F5.
Before running Generate the IL code. Go to Build and click on Generate Incremental CIL..
It will create a Batch job in the Batch Jobs Form you can view it by going into the
following path
System Administration --> Inquiries --> BatchJobs --> Batch Jobs.
You should see the status as waiting---> Executing --> Ended in the status column
of the Batch Jobs form.
Now the above batch job will run only on the server.
If you want to make it run on the Client. follow bellow steps.
Step:4
Override the method runsImpersonated. Right click on the Batch4Demo class and override the above method write the following code in it.
public boolean runsImpersonated()
{
// false means that the batch must run on a client.
return false;
}
Now run the class as mentioned above.
After running it we have to add it to the client section to do this.
Go to Organization administration --> Basic Or Periodic --> Batch Processing.
open the form and you can see batch group and private check box option.
in the group option select empty group( Because in the above code we have selected empty in the batch group). uncheck the private. now click ok. the batch job will run.






Monday, May 6, 2019

Users Security Roles Inquiry

Get all related security roles for users
below is a job and you can create query and form for visual view


static void FT_UserRoleInquiry(Args _args)
{
    UserInfo        _UserInfo;
    SecurityRole    _SecurityRole;
    SecurityUserRole    _SecurityUserRole;
   
   while select * from _UserInfo join _SecurityUserRole where _SecurityUserRole.User == _UserInfo.id join _SecurityRole where _SecurityRole.RecId == _SecurityUserRole.SecurityRole
    {
        info(strFmt("user %1 Security %2",_UserInfo.name,_SecurityRole.AotName    ));
    }
}