giovedì 26 maggio 2016

HOWTO: Debug the AifOutboundProcessingService

If you need to go more in depth using debugging of an outbound you have to write down a couple of customization on standard code:

  • Comment out the runas method on AifOutboundProcessingService.runAsUserInPartition method and replace with a direct call to processAsUser method. 
/*
// runAs currentUser and process all messages in the container.
new RunAsPermission(runAsUserId).assert();

// BP deviation documented
runas(runAsUserId,
classnum(AifOutboundProcessingService),
staticmethodstr(AifOutboundProcessingService, processAsUser),
messageIdContainer,
runAsCompany,
'',
runAsPartition);

// Revert the permission
CodeAccessPermission::revertAssert();

*/

AifOutboundProcessingService::processAsUser(messageIdContainer);

Important: You have to run the code on the same company and partition specified on runAsCompany and runAsPartition parameter.
  • Comment out or o skip execution this line of code on AifDispatcher.dispatchOperation method
//new AifDispatcherPermission().demand();

For process the message queue use the new AifOutboundProcessingService().run() method

HOWTO: Create computed columns in Views on Dynamics AX 2012

Computed columns have been using in SQL server since many versions but this feature was available Dynamics AX since version 2012.
Follow steps described here to learn how to create view and walthrough the complete example to understand how can we add computed columns in AX 2012 Views. More examples can be found from here; http://daxmusings.codecrib.com/2011/10/computed-view-columns-in-ax-2012.html 

Well, here is an example which illustrates how can we add computed columns in a view with different logic.

Computed column; Returning Field in View
public static server str compAmount() { #define.CompView(SWProjForecastCost) #define.CompDS(ProjForecastCost) #define.CostPrice(CostPrice)
   return SysComputedColumn::returnField(tableStr(#CompView), identifierStr(#CompDS), fieldStr(#CompDS, #CostPrice)); }

Computed column; Converting UTC Date to Date in View
public static server str compDate() { #define.CompView(SWProjForecastCost) #define.CompDS(ProjForecastCost) #define.ActualDateTime(ActualDateTime) str sDateTime; sDateTime = SysComputedColumn::returnField(tableStr(#CompView), identifierStr(#CompDS), fieldStr(#CompDS, #ActualDateTime));
   return SysComputedColumn::fromUtcDateToDate(sDateTime); }

Computed column; Returning Enum Value in View
public static server str compGeneralTransType() {    return SysComputedColumn::returnLiteral(Transaction::ProjectInvoice); }

Computed column; Multiplying two coulmns and returning resultant from View
private static server str compTotalCostPrice()
{
   #define.CompView(SWProjForecastCost)
   #define.CompDS(ProjForecastCost)
   #define.QtyCol(Qty)
   #define.PriceCol(CostPrice)


   return SysComputedColumn::multiply(
           SysComputedColumn::returnField(
               tableStr(#CompView),
               identifierStr(#CompDS),
               fieldStr(#CompDS, #PriceCol)
           ),
           SysComputedColumn::returnField(
               tableStr(#CompView),
               identifierStr(#CompDS),
               fieldStr(#CompDS, #QtyCol)
           )
         );
}

Computed column; Case Statement in View
public static server str TransType()
{
   #define.CompDS(ProjForecastCost)
   #define.CompView(SWProjForecastCost)
   str ret;
   str ModelId = SysComputedColumn::returnField(identifierStr(SWProjForecastCost), identifierStr(ProjForecastCost), identifierStr(ModelId));
   ret = "case " + modelId +          " when 'Sales' then 'Forecast Sales' " +          " when 'Orders' then 'Forecast Orders' " +          " when 'Latest' then 'Forecast Latest' " +          " end";    return ret;
}


Case Statement for this view looks like in SQL server as below;

   CASE T2.MODELID
      WHEN 'Sales' THEN 'Forecast Sales'
      WHEN 'Orders' THEN 'Forecast Orders'
      WHEN 'Latest' THEN 'Forecast Latest' END

martedì 19 aprile 2016

X++: How to find what projects an object from the AOT exists in (Recursive)

To find out what projects an AOT object exists in, use this script.
It's recursive, than it can find methods or inner nodes too

ProjectNode projectNode;
ProjectListNode projectListNode;

TreeNode treeNode;
TreeNodeIterator treeNodeIterator;

// Object we are searching for
TreeNode tnSearch = TreeNode::findNode(@'\Classes\MHT_DOCF_MasterTable');

void find(TreeNodeIterator _innerTreeNodeIterator)
{
TreeNode innerTreeNode;
;
innerTreeNode = _innerTreeNodeIterator.next();
while (innerTreeNode)
{
if (innerTreeNode.treeNodePath() == tnSearch.treeNodePath())
info(strfmt("Found in shared project %1", treeNode.AOTname()));
find(innerTreeNode.AOTiterator());
innerTreeNode = _innerTreeNodeIterator.next();
}
}

;

projectListNode = SysTreeNode::getSharedProject();
treeNodeIterator = projectListNode.AOTiterator();

treeNode = treeNodeIterator.next();
while (treeNode)
{
projectNode = treeNode;
projectNode = projectNode.loadForInspection();
find(projectNode.AOTiterator());
treeNode = treeNodeIterator.next();
}

TIP: Error executing code: The field with ID '0' does not exist in table 'SysExtensionSerializerExtensionMap'.


If you ever get "Error executing code: The field with ID '0' does not exist in table 'SysExtensionSerializerExtensionMap'." error in CIL, it may happen it is the table extension framework + the standard buf2buf function to blame.

Somehow, if you pass a Map instead of a table to buf2buf function, the following line fails:

_to.(fieldId) = _from.(fieldId);
However, if you replace this line with:

fieldName = fieldId2name(_from.TableId, fieldId);
 _to.setFieldValue(fieldName, _from.getFieldValue(fieldName));

everything is fine both in X++ and in CIL.

P.S. I didn't dare to change the standard buf2buf method. Istead, I created another method and used it in the table extension framework logic, which failed because of the issue (\Data Dictionary\Maps\SysExtensionSerializerMap\Methods\copyExtensionTableData)


Reposted: https://community.dynamics.com/ax/b/dynamicsaxnotesonthecuffs/archive/2016/04/04/error-executing-code-the-field-with-id-39-0-39-does-not-exist-in-table-39-sysextensionserializerextensionmap-39

venerdì 8 aprile 2016

HOWTO: Delete Label Files from AX 2012

Here are the steps to delete Label Files from AX 2012:

  • Create a new model. You could call it "LabelsBeGone".
  • Open the AOT and move the Label File(s) you want to get rid of to the new model.
  • Close AX and stop the AOS.
  • Use AXUtil to delete the new model.
  • Delete the label files from the server folder; C:\Program Files\Microsoft Dynamics AX\60\Server\...\bin\Application\Appl\Standard
  • Start the AOS.
  • Skip the upgrade wizard.

AX 2012: The request was aborted: Could not create SSL/TLS secure channel

The error you're encountering, "The request was aborted: Could not create SSL/TLS secure channel," can occur due to various re...