RSS

Dimension Controls in a Dialog for Dynamics 365 for Operations


 

To put it simply, we just need to create our own custom control type, let’s call it “Dimension Entry No Datasource” control.

Firstly, create an extension package so that you are not tempted to overlayer code. Be sure to include the Dimensions model in your package.  Visit the Dynamics ‘AX7’ menu and create a new model:

Name it however you wish:

And select extension package:

Include any other packages you want to reference.  Think of this as an assembly (DLL) referencing other assemblies.

Extensions is the new bag, baby!

Create a new class in your model, and extend the DimensionEntryControl class:

  1. [FormControlAttribute(‘Group’, ”, classStr(DimensionEntryControlBuildNoDS))]
  2. class DimensionEntryControlNoDS extends DimensionEntryControl
  3. {
  4. public DimensionDefault getDimensionRefRecId()
  5. {
  6. return this.parmDimensionValueSetId();
  7. }
  8. }

You’ll notice in the metadata I’ve also drafted a separate extension class for DimensionEntryControlBuildNoDS as well.

In the class example above, you’ll see we have overridden the getDimensionRefRecId() method which is declared as Protected in the parent class.  By setting it to public, we can use it as required in our dialog form.

Build your package from the AX7 menu.

Now it’s time to make use of your training in SysOperation Framework from AX 2012! Create a new controller class which extends SysOperationServiceController, in this example I’ve called it MyController.  Override the templateForm() method and specify a new form:

  1. class MyController extends SysOperationServiceController
  2. {
  3. /// <summary>
  4. /// Swenka internal use only.
  5. /// </summary>
  6. /// <returns>
  7. /// A <c>formName</c> value.
  8. /// </returns>
  9. protected FormName templateForm()
  10. {
  11. return formStr(MyTemplateForm);
  12. }
  13. public static void main(Args _args)
  14. {
  15. MyController c = new MyController();
  16. c.initializeFromArgs(_args);
  17. c.startOperation();
  18. }
  19. }

The new form I’m using above called MyTemplateForm is just a duplicate of the SysOperationTemplateForm.  Expand the design to the DialogStartGrp group which is the main group for any SysOperation dialog.

Add your new custom dimension control here by right-click and new control:

Typically a dimension entry control can infer the type of dimension entry we are requiring based on the Extended Data Type (EDT) of the table field that is associated to the control.  This will either be a Default Dimension such as on master data, or a Ledger Dimension such as on General Journal lines.

In our case however, we have no datasource on the form. So we must specify explicitly the default dimension controller class in the control properties.  Also set the auto declare to True.

From here it is a quick couple lines of code in the init() of the form to tell the control to display values upon loading:

  1. public void init()
  2. {
  3. super();
  4. DimensionEntryControlNoDS.parmDisplayValues(true);
  5. }

And upon closing the dialog we want to capture that default dimension recId and save it to our data contract for use in our service:

  1. // <summary>
  2. /// Command control message called when the form’s OK button is clicked.
  3. /// </summary>
  4. public void closeOk()
  5. {
  6. if (this.controller().checkCloseDialog())
  7. {
  8. super();
  9. var someRecId = DimensionEntryControlNoDS.getDimensionRefRecId();
  10. //now we need to save this in the data contract
  11. //via calling…
  12. DataContract c = this.controller().getDataContractObject(‘_myContractParameterName’);
  13. c.parmDim(someRecId);
  14. //now we can close the form, and execute the job
  15. if(this.controller().skipRunOperation())
  16. {
  17. this.controller().skipRunOperation(false);
  18. }
  19. else
  20. {
  21. this.controller().dialogClosedWithOk(this.dialog());
  22. }
  23. }
  24. }

Using a simple action menu item to invoke the service, we can see the dialog displays our default dimensions for the current legal entity:

Advertisements
 

Tags:

Model, Model store, Importing, Compilation, IL generation and Upgrade scripts.


Nice post can I reblog it on my blog if you do not having problem.

Raziq AX's Blog

I prepared this post from different sources which would give you clear cut picture on Importing & Compilation objects and IL generation. So, let’s begin withModel and Model store.

What is Model?
A model is a set of elements in a given layer. Each layer consists of one or more models. Each layer contains one system-generated model that is specific to that layer. Every element in a layer belongs to only one model. In other words, no element can belong to two models in the same layer, and every element must belong to a model.

A default model owned by Microsoft exists in each layer. Default models cannot be modified.

A model is permanently associated with the layer that the model was created in. If you need to move one of your models from one layer to another, you must create a project from the model in the Application…

View original post 804 more words

 
Leave a comment

Posted by on September 14, 2016 in Uncategorized

 

AIF–handling related incoming records


I had to being able to handle HRM applicants and applications from a corparate website. In basics the customer wanted to have a webform where the applicant could enter his/her personal data and attach files like eg. a CV, the application or any other relevant stuff.

To handle that scenario I created two tables in AX – one to handle the applicant and application related stuff and another to handle the file attachments. One application should be able to have many attachments. Therefore the first attachment should relate to one application and the second attachment to the same application and so on…

Having the datamodel set, I created a document service.

I created a simple webform in c# that consumed the AIF service and I was soon able to send data into AX. Then it occured to me, that I wasn’t able to create the relation between attachments and applications from the webclient because I needed the RecID og the Application in order to put in onto the attachments.

Inside ax i found the PrepareForSaveExtended method of my AXD class to be useful. Here I could make sure that applications would be processed before attachments. And once the applications were processed I could fetch the RecId and put in on each attachment.

I ended up with this:

Class declaration:

 

class Axdegf_HRMWebRecruitment extends AxdBase

{

#define.WebRecruitment_DataSourceName(‘WebRecruitment’)

#define.Attachments_DataSourceName(‘Attachments’)

 

 

HRMWebRecruitment            axbc_WebRecruitment;

HRMWebRecruitmentAttachments axbc_Attachments;

 

}

PrepareForSaveExtended:

public boolean prepareForSaveExtended(

AxdStack                    _axBcStack,

str                         _dataSourceName,

AxdRecordProcessingContext  _recordProcessingContext,

AxInternalBase              _childRecord)

{

//TODO: Add code here to ensure that required fields specified in the initMandatoryFieldsMap method are sent in by the service caller.

switch (_dataSourceName)

{

// ———————————————————————-

// Process WebRecruitment records

// ———————————————————————-

case #WebRecruitment_DataSourceName:

 

axbc_WebRecruitment = _axBcStack.top();

switch (_recordProcessingContext)

{

 

case AxdRecordProcessingContext::BeforeChildRecordProcessed:

switch(_childRecord.dataSourceName())

{

case #Attachments_DataSourceName:

if(!axbc_WebRecruitment.isProcessed())

{

return true;

}

break;

}

return false;

 

// Ensure WebRecruitment record is saved

case AxdRecordProcessingContext::AfterAllChildRecordsProcessed:

if (!axbc_WebRecruitment.isProcessed())

{

return true;

}

return false;

}

return false;

// ———————————————————————-

// Process Attachments records

// ———————————————————————-

case #Attachments_DataSourceName:

 

axbc_Attachments = _axBcStack.top();

//axbc_Attachments.parmDescription(“dudelidut”);

switch (_recordProcessingContext)

{

 

// Propagate parent’s key

case AxdRecordProcessingContext::BeforeAnyChildRecordsProcessed:

axbc_WebRecruitment = axbc_Attachments.parentAxBC();

axbc_Attachments.parmHRMWebRecruitmentRecIdRef(axbc_WebRecruitment.currentRecord().RecId);

return false;

 

// Ensure Attachments record is saved

case AxdRecordProcessingContext::AfterAllChildRecordsProcessed:

if (!axbc_Attachments.isProcessed())

{

 

return true;

}

 

return false;

}

return false;

 

// ———————————————————————-

// Unsupported data sources

// ———————————————————————-

default:

error(strfmt(“@SYS88979”,classId2Name(classidget(_axBcStack.top()))));

return false;

}

return false;

}

 

 
Leave a comment

Posted by on July 29, 2016 in AIF, Uncategorized

 

Deadlocks show up in AIF exception log when CRM synchronizes multiple companies.


I was working on a case where some issues occured when trying to synhronize data between MS dynamics ax 2012 and MS CRM.

Scenario description:

In MS CRM the following maps have been set up for synchronization in two integrations.

CRM_maps

Each integration uses its own AX user for connection.

From the CRM point of view, the synchronization seems to succeed. However going through the exception log in AX it seems that quite a few deadlocks have occurred, please see screendump below:

AX_deadlocks

And here’s a screendump from the “general” tab showing the error message – “Cannot select a record in Change Tracking Version (AifSqlCtVersion). Change Tracking Version: 0.
Deadlock, where one or more users have simultaneously locked the whole table or part of it.
”:

AX_deadlock_general

The deadlocks seems to have disappeared by themselves.
From this blog post this issue seems to be a known issue – https://community.dynamics.com/ax/f/33/t/160640 – however the ax database had not recently been updated.

 

The cause:

The cause seems to be the SQL optimiser doing a clustered index scan (RecId) in the query below, resulting in blocking:

SELECT T1.CTVERSION,T1.CREATEDDATETIME,T1.RECVERSION,T1.RECID FROM AIFSQLCTVERSION T1 WITH ( UPDLOCK) WHERE (CTVERSION<@P1)

 

The solution:

  • Login to Dynamics AX –> Open a Development workspace, and navigate to AOT –> Dictionary -> tables,
    Find the table AIFSQLCTVERSION , and create a new non-unique index for CTVERSION field
  • Login to SQL server Management studio, and create a new plan guide for the query adding index hint
    EXEC sp_create_plan_guide @name = N'[PlanGuide-AIFSQLCTVERSION]’, @stmt = N’SELECT T1.CTVERSION,T1.CREATEDDATETIME,T1.RECVERSION,T1.RECID FROM AIFSQLCTVERSION T1 WITH ( UPDLOCK) WHERE (CTVERSION<@P1)’, @type = N’SQL’, @module_or_batch = N’SELECT T1.CTVERSION,T1.CREATEDDATETIME,T1.RECVERSION,T1.RECID FROM AIFSQLCTVERSION T1 WITH ( UPDLOCK) WHERE (CTVERSION<@P1)’, @params = N’@P1 bigint’, @hints = N’OPTION (TABLE HINT (T1, INDEX( I_100021KOO_CTVERSIONIDX), UPDLOCK))’
    GO(replace the index name I_100021KOO_CTVERSIONIDX with the actual name of the newly created index)
 
 

AIF–duplicate types with name Dynamics.Ax.Application…


I had to redeploy an AIF http document service several times due to changes. Ocassionally the below error would occur when opening the inbound ports form. The error indicated that the classes related to my document service somehow would conflict because they were already registered. In the current state it would not be possible to activate a new inbound port.

DuplicateType

Fortunateley a colleague of mine had experienced something similar and here is our guide that in the end solved my issue:

  • Create a job that deletes everything  from the SysXppAssembly

static void Job1(Args _args)
{
SysXppAssembly sysxppassembly;
ttsBegin;
delete_from SysXppAssembly;
ttsCommit;
}

  • Stop the AOS.
  • Delete all files (and folders) from the “C:\Program Files\Microsoft Dynamics AX\60\Server\[instancename]\bin\XppIL” folder
  • Start the AOS and go to Systemadministration/setup/services and application integration framework/inbound ports to check if the error has gone.

In most cases that would solve the problem. In one situation I experienced that the above gude was not enough. I also had to do the following:

  • compile the entire application
  • Perform full CIL
  • Restart the AOS
Reference :https://philippsen.wordpress.com/2015/05/11/aifduplicate-types-with-name-dynamics-ax-application/
 
Leave a comment

Posted by on July 29, 2016 in AIF, Uncategorized

 

Enumerator and Iterator in Dynamics AX 2012


Difference between Enumerator and Iterator(use for list, Maps or Sets element’s traversing)

  • We can traverse our List, Map or Set collections by using either an enumerator or an iterator
  • We can’t add/Delete elements in the List or Maps or Set using Enumerator class but we can do it via iterator class
  • It is a best practice to use the Enumerator class instead of the Iterator class, because enumerators are automatically created on the same tier as the map (when calling the List.getEnumerator method)
  • Enumerators require less code than iterators to initiate there instance, they perform slightly better.

For more information please refer to following link

Difference between Enumerator and Iterator in AX 2012

 
Leave a comment

Posted by on July 29, 2016 in Uncategorized

 

Adding custom filter on a list page


Imagine you want a filter on a list page say planned orders list page. Filter works on the order date and shows order due today or all. It has two values in the selection Today/All. Its not that straightforward as it may seem as it is a list page. On a normal AX form, its much easier.

A number of steps required to achieve this.

1. Add the custom filter to the list page. Note the filterExpression, its a call to method we create in next step. Also you need an enum and an EDT based off the enum, EDT is selected in the properties as well.

2. SysQueryRangeUtil
Add a method to the SysQueryRangeUtil.

3. Interaction class
List pages use the interaction classes for logic. We need to customize 2 methods in the ReqTransPOListPageInteraction.
In method initializing, after super(), add this
   customFilter = SysEPCustomFilter::construct(formStr(ReqTransPOListPage));  
   customFilter.load();  
   customFilter.setInitialFilterControlValue(formControlStr(ReqTransPOListPage, yourFilter), 0);  
Note: customFilter.load() will reload the last saved selection in your filter. In case, you want a specific enum selection everytime, comment out this line.
In method initializeQuery, before super(), add this
Note the call to method in SysQueryRangeUtil
   if (this.listPage().listPageArgs().parameters())  
   {  
     reqPOFilterEnum = customFilter.getFilterControlValue(formControlStr(ReqTransPOListPage, yourFilter));  
     SysQuery::findOrCreateRange(_query.dataSourceTable(tableNum(ReqPO)), fieldNum(ReqPO, ReqDateOrder)).value(SysQueryRangeUtil::xxxReqPOFilter(reqPOFilterEnum));  
   }  
4. Your list page
 
Leave a comment

Posted by on July 16, 2016 in AX 2012

 
 
All About Dynamics 365

Dynamics 365, D365, Implementor

Syed Rafay Ali

This blog contains information about Functional techniques and guidelines in Microsoft Dynamics AX, including tips, tricks, tutorials, tools and upcoming news enhancement in Microsoft Dynamics Ax

Philippsen's Blog

Everyday findings in my world of .net and related stuff

Microsoft Dynamics AX

A great WordPress.com site

Finite Minds

Adventures in IoT

Dynamics Ax

Technical Knowledge

timsaxblog

A blog about implementing Microsoft Dynamics AX and Dynamics 365 for Operations

Microsoft Dynamics 365 Blog

"Learn it all, not Know it all" in Dynamics 365 - Enterprise Edition, A Blog by Sandeep Chaudhury

DEVSerra - Dynamics AX development blog

Your official Microsoft Dynamics AX blog.

OrganicAX

Discovering Dynamics

AX

A blog by Hai Nguyen

Learn Dynamics Ax with Johnkrish

Live as if you were to die tomorrow. Learn as if you were to live forever - Mahatma Gandhi ****** The more I learn, the less I know - Albert Einstein

Twisted Untwirled

Just another WordPress.com site

ramdynamicsax

Just another WordPress.com site

guyterry's Dynamics AX blog

Just another Dynamics AX blog