Thursday, April 01, 2021

XDS Security

 The extended security model is used to create a customer rule for limiting the access to records. The different components of the XDS security are : 

1. Query: Whenever we are designing a record level security, there is one primary table where the logic to record restriction is built and then this is extended to all the related tables where this table is a foreign key. The query contains the condition to restrict the primary table. 

2. Security policy: Once the primary table to be restricted has been identified and the query designed, the next step is to plan when to apply the policy and to which all table. A policy is used to link the condition query (created in step 1) with a list of tables which need to be restricted for security (constraint tables). It also has a policy context which is used to determine when the policy is applied, this is generally set to a security role (i.e. anyone which the configured role would be applied with the record level security). 

The security policy also has a primary table mentioned which is the root of the query that is created. The primary table should have an explicit relationship with all the tables where the constraint is being applied. 

Every security policy would also have a property called Constrained Table which can be set to Yes or No to decide if the policy would be applied on the primary table itself or not. 

When the policy is applied on the primary table it be already applied before the xds method is called in MyTables. If the xds method needs access to the records in the primary table, this might be a concern as the policy would already be applied and not all the rows in the primary table would be available for the xds method. In cases like this a view based on the primary table can be created and that should be used instead of the actual table. 

3. MyTables : These are special tables created to be used in the security query, where custom logic can be written to populate data. These table names are prefixed with "My" keyword and the logic is written in xds function.

       

    public RefreshFrequency xds()
    {
        MyAFZCategory   myCategory;
        SPYHCMWorker       hcmWorker; //view is used as the primary table is contrained
        DirPersonUser   dirPersonUser;

        AFZEmployeeCategory afzEmployeeCategory;
        AFZWorkerCategoryUserAccess workerCategoryUserAccess;        
       
        insert_recordset myCategory(HcmWorkerRecId)
        select RecID from hcmWorker
        join afzEmployeeCategory
            where afzEmployeeCategory.Code == hcmWorker.AFZCategoryCode
        join workerCategoryUserAccess
            where workerCategoryUserAccess.UserId == curUserId()
            && afzEmployeeCategory.CodeGroup == workerCategoryUserAccess.CodeGroup ;             

        /*
        select generateOnly forceLiterals RecID from hcmWorker
        join afzEmployeeCategory
            where afzEmployeeCategory.Code == hcmWorker.AFZCategoryCode
        join workerCategoryUserAccess
            where workerCategoryUserAccess.UserId == curUserId()
            && afzEmployeeCategory.CodeGroup == workerCategoryUserAccess.CodeGroup ;
        info( hcmWorker.getSQLStatement() );
        */


        //Calculate current worker value
        select firstonly PersonParty, ValidFrom, ValidTo from dirPersonUser
            where dirPersonUser.User == curUserId();

        select firstonly RecId from hcmWorker
            where hcmWorker.Person == dirPersonUser.PersonParty;

        myCategory.initValue();
        myCategory.HcmWorkerRecId = hcmWorker.RecId;
        myCategory.insert();

        // This is static data, so only refresh when session is restarted
        return RefreshFrequency::PerSession;
    }

}

Monday, March 22, 2021

Data entities using Dimension for Power BI

When we work with dimension one of the key tables used is the DimensionAttributeValueCombination. However, when we look at the definition of this table in the AOT vs in the database we will notice that there is a difference.

AOT only has a subset of the fields that exists in the physical SQL Table 

AOT View

Certain fields like the SystemGeneratedAttribute are not visible in the AOT. 

SQL View

This is possible because Microsoft introduced a feature for configuration of custom fields in D365 (Platform update 13). This feature is using technology which enables creating table extensions on runtime. As dimensions are configured at runtime and not at design stage, the framework makes use of this feature where a table extension is created at runtime using the configuration to create this columns as table extension. 

When we are required to export the dimension values on a data entity, the process followed is to expose the financial dimensions as separate fields on the entity using extension. These adjustments are made in a resilient manner by using the extension approach, so that minimal maintenance will be required when we upgrade the code base to newer versions in the future. 

  • There is a ready made wizard that is provided to create an entity extension for the required dimensions. This wizard can be accessed from the Dynamics 365 -> Addins -> Add financial dimension for Odata


 In the resulting wizard screen the name of the dimensions required to be exported should be provided and this can be obtained from General Ledger -> Dimensions -> Financial dimension configuration for integrating applications


The resulting dimension combination would be displayed which can then be copied based on the need on the wizard screen.



Once the wizard is completed the extensions would be generated into a new project. This project should be compiled to ensure that the required tables are generated. Its needs to be ensured that the project is marked for database sync on build. 




We are now ready to add the DimensionCombinationentity entity to our existing entity wherever the dimension values are required additionally to be exposed. It should also be ensured that DimensionCombinationentity entity is outer-joined as showed below


Once the join has been established the Dimension fields would be Visible. To make the fields available on the Data Entity, the desired fields should be dragged and dropped on the field node and the necessary relation should be set.




Wednesday, December 09, 2020

Budgeting at Totals

The AX system has two level check for budget. 

  • Level 1: Budget control rule which works at the individual account + dimension combination level.  
  • Level 2: The budget group rule executes a secondary budget check. This is applied after the level 1 check is failed. This is performed at a summary of 1 or more accounts which is created using an entity called budget groups. 
To budget for a group of accounts as a block, we need to create budget group. The budget groups must be created on the **Budget control configuration ** page. The criteria that you specify must include the total main account and the range of accounts. The criteria can further be nested to accommodate multiple queries and when a group is considered then all the queries nested below it are accumulated before the check is performed. This provides enough flexibility to create complex budget groups.

It is also important to note here that sometimes when the budget registers are posted before the budget configurations are enabled, the budget control statistics might not be udpdate. AX now provided a period job to process any such budget register entries that have not been processed or were posted before the budget controls were enabled. 

To process any pending budget register entries we need to do the following: 

  1. We need to ensure that all the financial periods with the budgets are open. To open the financial periods you can go to General Ledger-> Ledget Setup -> Ledger Calender option. 
  2. Once the periods are opened then any pending registers can be processed using the periodic job in Budgeting -> Periodic-> Budget control data maintenance 
Please ensure that the budget control is enabled before the budget control data maintenance is initiated. 

Sunday, September 06, 2020

Outlook out of memory

When you get out of memory error on the outlook client. One of the solutions that worked is as follows:-

1. Goto the below folder and delete all the xml files in there

%appdata%\Local\Microsoft\Outlook\16

2. Start the Microsoft outlook client in safe mode to reconfigure the mails. 


Wednesday, September 02, 2020

AX Dialog : Override controls

 Dialog is a another important framework in AX 2012. When a dialog is created using classes it demands a good understanding of what happens under the hood. 

Each dialogField that is added using the dialog classes is internally given a system name and this name can then be used to attach events to the runtime Field. The fieldName method in the dialog class creates the name for a field being added. 

We can find the systemName that a control has been assigned by calculating it from the sequence it was added in or alternatively we can run the dialog and check the name from the personalization form. 

Once we have the name we can write the extension methods for the control in the class. Follow the following steps for the same

//To allow the system to do Overloading of the function :
public void dialogPostRun(DialogRunbase _dialog)
{
;
super(_dialog);
// allow the dialog infrastructure to raise dialog field events _dialog.dialogForm().formRun().controlMethodOverload(true); _dialog.dialogForm().formRun().controlMethodOverloadObject(this);
}


// To override the lookup method of a field. (For the third field)
private void fld3_1_lookup(FormControl _formControl, str _filterStr)
{
Object control;
;
control = dialog.formRun().controlCallingMethod();
WMSLocation::lookupLocationId(control, DlgFromWrhs.value(),InventLocation::find(DlgFromWrhs.value()).InventSiteId,true);
}

//modified
// To override the modified method of a field. (For the second field)

public boolean fld2_1_modified()
{
boolean                     ret;
Object                      control = dialog.formRun().controlCallingMethod();

WMSLocationIdDefaultIssue   WMSLocationIdDefaultIssue;
;
ret = control.modified();

if (ret)
{
    WMSLocationIdDefaultIssue = InventLocation::find(DlgFromWrhs.value()).WMSlocationIdDefaultIssue;

if (WMSLocationIdDefaultIssue)

DlgFromLocation.value(WMSLocationIdDefaultIssue);

else

DlgFromLocation.value('');

}

return ret;

}


There is a second method which is more concise in cases where we directly want to overload the runtime control properties 


–> A lookup method is required in the first place. Below is the sample code to lookup the exchange rates.

private void journal_Lookup(FormStringControl _control)

{    

    SysTableLookup sysTableLookUp;

    QueryBuildDataSource qbds;


    Query query = new Query();


    qbds = query.addDataSource(tableNum(LedgerJournalTable));    


    qbds.orderMode(OrderMode::OrderBy);

    qbds.addSortField( fieldNum( LedgerJournalTable , JournalNum), SortOrder::Descending);    


    query.allowCrossCompany(true);

    query.addCompanyRange( dlgLegalEntity.value() );        


    sysTableLookUp = SysTableLookup::newParameters(tableNum(LedgerJournalTable), _control, true);

    sysTableLookUp.addLookupfield(fieldNum(LedgerJournalTable, JournalName), false);


    sysTableLookUp.addLookupfield(fieldNum(LedgerJournalTable, JournalNum), true);

    sysTableLookUp.addLookupfield(fieldNum(LedgerJournalTable, Name));

    sysTableLookUp.addLookupfield(fieldNum(LedgerJournalTable, OriginalJournalNum));

    sysTableLookUp.addLookupfield(fieldNum(LedgerJournalTable, OriginalCompany));


    sysTableLookUp.parmQuery(query);

    sysTableLookUp.performFormLookup();


}

–> The above method can then be called in the dialog method of the runbase class


public Object dialog()

{

FormStringControl control;

dialog = super();


    dlgPostPayrolldlg = dialog.addFieldValue( extendedTypeStr(JournalId),postPayrollJournalId, "Journal to split");


   sourceJournalControl = dlgSourceBatch.control();

    journalToSplitControl.registerOverrideMethod(methodstr(FormStringControl, lookUp),methodstr(AFZ_CostAllocChangeProcess, journalToSplit_Lookup),this);


return dialog;


}

Sunday, August 30, 2020

Getting rid of Unidentified Network

 Had a bad network experience for a few days. My network was slow on the machine and was i was losing the connection a no of times in a day. 

Luckily if found a quick fix for the problem. Start the cmd command on an elevated command prompt and enter the following command 

C:\>netsh winsock reset

After this command restart your computer and hopefully the problem would be resolved. 

Friday, May 15, 2020

X++ SysOperation Framework

Firstly, what is a framework:
To understand frameworks we first need to understand libraries. Libraries are a bunch of code that is pre-written and packaged to save our time. When we need to do a task, we just call the appropriate library and it does the job for us. We don’t need to know the details of how the functions inside the libraries work, we just need to know how to call them.

Frameworks are just like libraries in a way that they make our job easier, but we can't call frameworks in the same way as libraries. To use framework, we have to learn the framework, the framework gives us a structure to place and call our code, and not the other way round.

In simple terms framework is to structure what libraries is to code. Using library we reuse code, and using a framework we reuse a class structure.

When we work with X++ there are these set of framework classes that are used all over X++ development.

SysOperation framework:  
The SysOperation is used whenever there is a user interface which triggers a certain functionality. Its quite close to the MVC pattern and work on the similar principles of segregating code to remove dependencies. 

The Model : Data contract
Its the model class from the MVC pattern in which we define attributes we need for our operation, commonly set as parameters by the user in a dialog. A regular class is identified as a SysOperation Data Contract class by adding the DataContractAttribute attribute to its declaraion.

Additionally, if we want a set of methods to be available to us, we can also extend the SysOperationDataContractBase base class. With this class, we can define how our basic dialog will look like to the user. We can define labels, groups, sizes and types of the parameters.

The View : UI Builder
Its an optional class and is the view part from the MVC pattern. Generally AX creates the dialog for us with a standard view, however if are not happy with the standard view of we want to extend it we use the UI Builder class.

The Controller : Controller 
The controller orchestrates the whole operation. It holds information about the operation, such as if it should show a progress form, if it should show the dialog, and its execution mode - asynchronous or not. To create a controller class you should extend the SysOperationServiceController.

Service
While using the MVC we have to understand that not everything is a perfect MVC and as per OOP principles we have to ensure the dependencies between the classes is minimal. Technically one could put the business logic in the controller, however what if the same business logic has to be used outside the controller and without an interaction ? Hence, it a good idea to store the business logic outside the controller and hence we have the service classes. 

The service class stores the business logic. To create a service class we have to extend it from the SysOperationServiceBase class. When constructing your controller, you can indicate which class holds the operation that the controller will trigger.