Monday, September 4, 2023

Extend Map CustVendTrans in Dynamics 365 Finance and Operations

SCENARIO

New field MyNewField as NoYes on CustTrans and VendTrans

SIMPLE SOLUTION
OBEJCTS

Create method parmMyNewField on CustVendTans, CustTrans and VendTrans using Table code extensions.

USAGE

custVendTrans.parmMyNewField(NoYes::Yes) will work fine if the record hast been inserted.

ISSUE

If custVendTrans has not yet been inserted a call to custVendTrans.parmMyFlag(NoYes::Yes) will result in the errors
Error executing code: CustTrans table does not have method ‘parmMyNewField’.
or
Error executing code: VendTrans table does not have method ‘parmMyNewField’.

FULL SOLUTION

Extend the CustVendTransInterface class to properly handle mapped functions irrespective of the record being created or not.

OBJECTS

·       Create class MyCustVendTransInterface following plugin design pattern, decorated with [… ExportInterfaceAttribute]

·       Create sub-class MyCustTransCustVendTrans
decorated with [… ExportMetadataAttribute(…CustTrans…), … ExportAttribute(…MyCustVendTransInterface…)]

·       Create sub-class MyVendTransCustVendTrans
decorated with [… ExportMetadataAttribute(…VendTrans…), … ExportAttribute(…MyCustVendTransInterface…)]


public static void main(Args _args)

{

  ttsbegin;

  new SqlDataDictionaryPermission(methodstr(SqlDataDictionary,  tableTruncate)).assert();       

  new SqlDataDictionary().tableTruncate(tableNum(DocuHistory), false);

  CodeAccessPermission::revertAssert();

  ttscommit;

}

 

[Microsoft.Dynamics.AX.Platform.Extensibility.ExportInterfaceAttribute]

public abstract class MyCustVendTransInterface

{

    CustVendTransInterface custVendTransInterface;

 

    private void initializeCustVendTransInterface(CustVendTransInterface _custVendTransInterface)

    {

        custVendTransInterface = _custVendTransInterface;

    }

    public CustVendTrans parmCustVendTrans()

    {

        return custVendTransInterface.parmCustVendTrans();

    }

     protected void new()

    {

    }

     public static MyCustVendTransInterface createInstance(CustVendTransInterface _custVendTransInterface)

    {

        SysPluginMetadataCollection metadataCollection = new SysPluginMetadataCollection();

 

        metadataCollection.SetManagedValue(classStr(MyCustVendTransInterface), tableId2Name(_custVendTransInterface.parmCustVendTrans().tableId));

        MyCustVendTransInterface instance = SysPluginFactory::Instance(identifierStr(Dynamics.AX.Application), classStr(MyCustVendTransInterface), metadataCollection);

 

        instance.initializeCustVendTransInterface(_custVendTransInterface);

 

        return instance;

    }

 

    public NoYes parmMyNewField(NoYes _myNewField= NoYes::No)

    {

        return _myNewField;

    }

}

 

 

[System.ComponentModel.Composition.ExportMetadataAttribute(classStr(MyCustVendTransInterface), tableStr(CustTrans))

    ,System.ComponentModel.Composition.ExportAttribute('Dynamics.AX.Application.MyCustVendTransInterface')]

public class MyCustTransCustVendTrans extends MyCustVendTransInterface

{

    private CustTrans parmCustTrans()

    {

        return this.parmCustVendTrans();

    }

 

    public NoYes parmMyNewField(NoYes _myNewField = this.parmCustTrans().MyNewField)

    {

        CustTrans   custTrans = this.parmCustTrans();

        custTrans.MyNewField = _myNewField;

        return custTrans.MyNewField;

    }

}

 

[System.ComponentModel.Composition.ExportMetadataAttribute(classStr(MyCustVendTransInterface), tableStr(VendTrans))

    ,System.ComponentModel.Composition.ExportAttribute('Dynamics.AX.Application.MyCustVendTransInterface')]

public class MyVendTransCustVendTrans extends MyCustVendTransInterface

{

    private VendTrans parmVendTrans()

    {

        return this.parmCustVendTrans();

    }

 

    public NoYes parmMyNewField(NoYes _myNewField = this.parmVendTrans().MyNewField)

    {

        VendTrans   vendTrans = this.parmVendTrans();

        vendTrans.MyNewField = _myNewField;

        return vendTrans.MyNewField;

    }

}

 

  • Optional: create extenstion class CustVendTransInterface_My_Extension to provide simple access to the newly created class MyCustVendTransInterface

 

[ExtensionOf(classStr(CustVendTransInterface))]

final class MyCustVendTransInterfaceCls_Extension

{

    private MyCustVendTransInterface MyCustVendTransInterface;

 

    public MyCustVendTransInterface MyCustVendTransInterface()

    {

        if (!MyCustVendTransInterface)

        {

            MyCustVendTransInterface = MyCustVendTransInterface::createInstance(this);

        }

 

        return MyCustVendTransInterface;

    }

}

 USAGE

//if extension CustVendTransInterface_My_Extension implemented

MyCustVendTransInterface myCustVendTransInterface = CustVendTransInterface::createInstance(custVendTrans).myCustVendTransInterface()

//if extension CustVendTransInterface_My_Extension not implemented

MyCustVendTransInterface myCustVendTransInterface = MyCustVendTransInterface::createInstance(CustVendTransInterface::createInstance(custVendTrans))

//access field

myCustVendTransInterface.parmMyNewField(NoYes::Yes);

 

Final notes

Microsoft documents the extension of maps here: Extend table maps that are used as interfaces
However the example SalesPurchTable they are using has a special attribute class to decorate the methods (SalesPurchTableInterfaceFactoryAttribute. The example here is both more generic and simpler.

No comments:

Post a Comment