Wednesday, 24 February 2021

Ax2012 Multi Select Report Parameter

 In this post I share you step by step how to build multi-select lookup for SSRS report.

1: Create Contract class

[

DataContractAttribute,

SysOperationContractProcessingAttribute(classStr(SL_ WarehouseMultiLookUIBuilder))

]

class SL_WarehouseMultiLookContract

{

List                             warehouse;

}

we need to create the parm method in the contract class for this multi select warehouse.

2: Create parmWarehouse Method

[

DataMemberAttribute(“warehouse”),

SysOperationLabelAttribute(“warehouse:”),

AifCollectionTypeAttribute(“warehouse”,Types::String)

]

public List parmWarehouse(List _warehouse = warehouse)

{

warehouse  = _warehouse;

return warehouse;

}

3: Create UI Builder class

class SL_ WarehouseMultiLookUIBuilder extends SysOperationAutomaticUIBuilder

{

DialogField                                     dfWareHouse;

SysLookupMultiSelectGrid            msCtrlWarehouse;

}

we need to bind the control to this parm method of multi select warehouse lookup to the dialog box in the build method of the UI Builder Class.

4: Create build method

public void build()

{

Dialog localdialog;

localdialog = this.dialog();

datacontract = this.dataContractObject();

this.addDialogField(methodStr(SL_WarehouseMultiLookContract , parmWarehouse),datacontract);

}

5: Create lookup Warehouse

private void WareHouseLookup(FormStringControl _control)

{

msCtrlWarehouse = SysLookupMultiSelectGrid::construct(_control, _control);

msCtrlWarehouse.parmQuery(this.WareHouseQuery());

msCtrlWarehouse.run();

}

6: Create warehouse Query

private Query WareHouseQuery()

{

Query       query;

query = new query();

query.addDataSource(tableNum(InventLocation));

query.dataSourceTable(tableNum(InventLocation)).addSelectionField(fieldNum(InventLocation,     InventLocationId));

return query;

}

7: Create post build method

super();

dfWareHouse   = this.bindInfo().getDialogField(datacontract, methodStr(SL_WarehouseMultiLookContract , parmWarehouse));

dfWareHouse.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(SL_ WarehouseMultiLookUIBuilder ,WareHouseLookup), this);

if (dfWareHouse)

{

dfWareHouse.lookupButton(2);

}

8: Create post run method

public void postRun()

{

dialogLocal.dialogForm().formRun().controlMethodOverload(false);

this. WareHouseLookup();

}

after complete these step Refresh your Dataset and deploy report.

Below is the screen shot of the multi select lookup of how its looks like.

WH WH2

Friday, 12 February 2021

Table fields on form visible/editable based on security role

 hide fields on a form using security

  •  OPEN THE SECURITY ROLES FORM
  • SELECT THE ROLE AND CLICK THE BUTTON 'OVERRIDE PERMISSIONS'. 
  • OPEN THE TABLES/FIELDS NODE. SEARCH THE RELATED TABLE AND UNCHECK THE FIELD 'DO NOT OVERRIDE'. 
  • THEN SET THE OVERRIDE ACCESS LEVEL TO THE ORIGINAL ACCESS LEVEL. 
  • NOW YOU CAN UNFOLD THE FIELDS. PER FIELD YOU CAN NOW ALSO UNCHECK THE 'DO NOT OVERRIDE' BUTTON AND SET THE LEVEL TO 'NO ACCESS' OR ALSO WHEN NEEDED TO 'VIEW'.

SECURITY HOW-TO: ONLY FINANCE USERS ARE ALLOWED TO SEE COST PRICES IN DYNAMICS 365 FINANCE AND OPERATION   

Scenario

For many different reasons, organizations do have the requirement to hide cost amounts. One of the most heard reasons is the fact that workers would make wrong assumptions about margins. The fact is that there are more costs related to running a company than only sales price minus cost price. If salespersons see e.g. a contribution margin of 25% they think they can give away more discount. They forget that salaries need to be paid, the office and warehouse rent should be covered, marketing efforts are also expenses and taxes are inevitable. If these organizations do approach it correctly, they should also hide any margin amounts or ratios.

Another reason would be securing company sensitive data. Some organizations would really like to prevent from leaking information about cost of producing items. For sure you can think of other reasons to secure individual fields.

The challenge

To solve this issue, you need to use table and field permissions. This is not the most difficult part of the steps you need to perform. In both Microsoft Dynamics 365 and AX 2012, you can achieve it, but there are differences.

More challenging will be hiding fields that are not directly bound to a table field. There are many occasions in the application where display methods are used to present data or perform a quick calculation with input from several fields. To be able to secure these, you need to change form control properties.

Continuing this post, I will elaborate on the challenge to hide the cost fields for sales orders and inventory transactions. These are not the sole entities with cost amounts, but a good representation of how to solve it in Microsoft Dynamics.

The number ‘1’ on the screenshots do refer to form controls that are bound to physical table fields. The number ‘2’ on the screenshots are display methods that do show a value based on business logic. How to handle both scenarios will be explained in two separate paragraphs.

Table and field security

When you want to manage the field access, you can achieve it as part of development or configuration. As mentioned above, there are differences between Dynamics 365 F&O and AX2012. I will list them in the next table:

SubjectAX 2012Dynamics 365 F&O
ConfigurationConfiguration changes do lead to changes in security objects in the AOTNo connection with the development environment. Changes are published on runtime only
ConfigurationUse the Override permissions button on the Security roles formUse the Permissions nodes on either the Security role or privilege on the Security configuration form
ConfigurationYou have to set table and field permissions.Table permissions can be set to Unset. Field permissions are managed for read and update permissions separately. To hide the field, you need a new Deny permission.
Development‘No access’ can be overridden by other security permissions in case of a combination of roles.‘No access’ on table and field permissions will be translated as ‘Deny’ which cannot be overridden by other security permissions for the same user.

Now we know some differences, we also can conclude that the solution direction for AX2012 and Dynamics 365 will be different. In AX2012, you need to verify all roles and privileges assigned to users who should not see the cost amount fields to set ‘No access’. In Dynamics 365, you can of course do the same, but only a single role would also achieve it as the Deny access level has higher priority above all other grants. I will continue explaining the Dynamics 365 example in this blog. You may have your own preference to start using the client configuration or a security development in Visual Studio. I will share the screenshots for both options. The inventory transactions table is configured in my demo where Deny permissions were set for all amount fields from this table.

The Return cost price on the sales order line is managed via a new privilege and the (table) permissions node. On the field itself the grant is set to No access.

You can find more cost related fields to be added, like cost prices from project or production transactions. Of course, you will choose one of above options for all fields to be secured. In this small demo, I have added the privilege to a security role called (Hide) Cost amounts. When the security role is assigned to a person all secured fields will be hidden. But, as mentioned above, we have a next step to secure display methods. This will be explained in the next paragraph.

Secure form controls

Besides table and field security, you can also set additional security on form controls. The controls do have a property NeededPermission which should have a different value than None. In Dynamics AX 2012, I usually set the NeededPermission value to Manual. The effect was that no business user could see the control, unless it was overridden on a specific privilege or role.

As explained above, in Dynamics 365 we can now rely on the deny permissions. This gives the option for another approach. The NeededPermission can now be set to Read which means that the control will be visible for anyone with at least read permissions. Using a privilege with No access for the form control, it can be managed to remove access to this form.

If you need to be able to manage the access level of form controls, you have to change the NeededPermission property. For existing forms, you can use a form extension to achieve this. You can check the next screenshot how to set the property in Visual Studio.

When the NeededPermission does not have the value None, you can set other permissions on the privilege. First you have to add the form on the Form Control Permissions node of the privilege. Then you are able to add the control name and set the permission to No access.

Note that the form control permission will not be visible via the Security configuration form, but it is certainly effective. On the Sales totals form, we want to hide three fields. As these three fields are part of a separate field group, you can set the NeededPermission property and security on the field group instead of all fields individually.

Next, when the form extensions and security objects are complete, you can test the access for a user without and with the role assigned to a user. You will notice that the fields and form controls with the cost prices are hidden when the role is assigned to a user.

Easy role assignment

When you have read my other blogs, this topic might be familiar to you. I have written several blogs about automatic role assignment in the past. For more background information on the method below, you an read about the automatic role assignment using the next link: How to setup easy automatic role assignment.

Suppose, we would like to have only the users part of the Accountant role being able to view the cost prices, in that scenario we have to assign all users to the (Hide) Cost amounts security role, except the users part of the role(s) which are allowed to view them.

To be able to select all users in the rule, except those based on a condition, you can join tables and use the Not-Exists Join option in table joins of queries. Credits to Kurt Hatlevik who made this feature possible: D365 – To exist or not, that is the question!(part 2) | Kurt Hatlevik

When creating the automatic role assignment rule, the query can look like displayed on the next screenshot.

It would be an option to also exclude the users with the System administrator role as these will anyway bypass any security. If you would like to add more roles, you can separate them with a comma in the Criteria field.

You are not limited to exclude users only as part of certain roles. You can exclude users manually by providing a criteria for the ID field of the User information table. With other table joins, you can also have criteria setup for users part of a Team or User group.

Now when you manually run the Automatic role assignment option or wait for the batch job, you will see users assigned to the (Hide) cost amounts role with the Assignment type Automatic.

When one of the users in the (Hide) Cost amounts role will be assigned to the Accountant role, the next time when the Automatic role assignment job runs, it will remove the role assignment automatically. Also when new users will be added to the system, this role will be added when the user is not an Accountant.

Reference :https://dynamicspedia.com/2021/02/security-how-to-only-finance-users-are-allowed-to-see-cost-prices-in-dynamics-365-finance-and-operations/

**********************************************************************************************

Through X++

select the "Visible" property of the field in the Grid to make that invisble.

By the below line of code you can hide the field using X++.

CustInvoicetrans_ds.object(fieldNum(CustInvoiceTrans,Overall_qty)).visible(false);


If you want to make it using Security role you have do some customizations:

  SecurityRole        role;
  SecurityUserRole    userRole;
  UserInfo            userInfo;
    
     while select * from role
        exists join userRole        
        where role.RecId == userRole.SecurityRole
        && userRole.User == curUserId()

    if(role)
    {
     // element.design().controlname("Overall_qty").visible(false);
        //CustInvoiceTrans_Overall_qty.visible(false);
        
         CustInvoicetrans_ds.object(fieldNum(CustInvoiceTrans,Overall_qty)).visible(false);
    }



POSTMAN D365

  Postman is useful to test the behavior of different OData class from/to D365FO. In this post we will see the steps to setup Postman with D...