Wednesday, May 23, 2018

Changing Business logic in Standard Microsoft Class methods without overlaying in D365 FO


// Changing Business logic in Standard Microsoft Class methods without overlaying

Tag: Dynamics 365 for finance and operations

Steps:

Scope:
è  Changing logic in Standard Microsoft Class methods without overlaying.

Pre Requisites:
è  Base model package should be reference to current package

Example:
Form->PurchTable
Data Source -> PurchLine
Requirement: Need to validate line amount value in purchLine table from system standard validation class method.

è  Let’s consider this below DEVCOCTEST as an assumption for system standard class and methods.
è  In DEVCOCTEST class, Process method contains validation on table (purchLine).
è  Requirement, need to change one of the intermediate line in process method or else changing or adding extra condition in process method.
Note: In Example code, I have written only few lines.
è  In example, currently overlay is not possible for this class method to do. Only way to achieve through extension and chain of command.
è  As assumption, Overlaying locked by Microsoft

//As per our assumption, this is our Microsoft Standard class and methods
//sample code - MS Hard sealed
Class DEVCOCTEST //Parent Class
{
    static DEVCOCTEST construct(PurchLine _purchLine)
    {
        if(_purchLine)
        {
            return new DEVCOCTEST();
        }
        else
        {
            throw error(Error::wrongUseOfFunction(funcName()));
        }

        return null;
    }

    void  Process(PurchLine _purchLine) //Standard Method
    {
        if(_purchLine.LineAmount > 1000)
        {
            throw warning("Purchase Amount limit exceed _ Parent Class");
        }
    }

}

//This is new customize class, created in new model
//With extends system standard class
Note:
è  Here we need to write method which you want to modify requires  business logic
è  If method not written in child class means then system will automatically call parent class method from child class.
class DEVCOCTEST_COCCHILD extends DEVCOCTEST
{
    public void Process(PurchLine _purchLine)
    {
        if(_purchLine.LineAmount > 1000)
        {
            throw warning("Purchase Amount limit exceed _ Child COC Class");
        }
        else
        {
            super(_purchLine); //if requires
        }
    }

}

//This is new customize class, created in new model
//For Extension of assumed Microsoft standard class (DEVCOCTEST)
Note:
è  Here wherever system is constructing DEVCOCTEST class, based on extension of Microsoft standard class using chain of command. System will hit below code
è  After calling, next command we creating new instance of child class (DEVCOCTEST_COCCHILD)

ExtensionOf(classStr(DEVCOCTEST))]
final class DEVCOCTEST_Extension
{
    static DEVCOCTEST construct(PurchLine _purchLine)
    {
        DEVCOCTEST a = next construct(_purchLine);
        a = new DEVCOCTEST_COCCHILD();
        return a;           
    }

}

//This is only for testing, to call

//Code for Event handler
//This is new customize class
//In example, I have consider FORMDATASOURCEEVENT type as Written
class DEVCOCTESTPURCHTABLEFORMEVENTHANDLER
{
    [FormDataSourceEventHandler(formDataSourceStr(PurchTable, PurchLine), FormDataSourceEventType::Written)]
    public static void PurchLine_OnValidatedWrite(FormDataSource sender, FormDataSourceEventArgs e)
    {  
        var purchLine_ds = sender as FormDataSource;
        PurchLine purchLine = purchLine_ds.cursor() as
            PurchLine;

        if(purchLine)
        {
            DEVCOCTEST  coc =   DEVCOCTEST::construct(purchLine);
            coc.Process(purchLine);
        }
        else
        {
            throw Error("Purchase lines Arguments must be called from journal");
        }
    }

}

Sample tested with
Class\PurchLineType_Purch\


Version: (Dynamics 365 for finance and operations)

Standard Class with example:

//Std PurchLineType_Purch class method - Hard seal
ClassPurchLineType_Purch 
Method: ValidateField

Requirement: Here i need to add one more field validation in switch case
public boolean validateField(FieldId _fieldId)
    {
        boolean      ret;

        ret = super(_fieldId);
        switch (_fieldId)
        {
            case fieldNum(PurchLine, TaxItemGroup) :
            case fieldNum(PurchLine, TaxGroup)     :
                if (purchLine.TaxGroup     &&
                    purchLine.TaxItemGroup &&
                    VendTable::find(purchTable.OrderAccount).vatTaxAgent_RU)
                {
                    ret = Tax::checkVATChargeSource_RU(purchTable.purchTable_RU().vatChargeSource_RU, purchLine.TaxGroup, purchLine.TaxItemGroup);
                }
                break;

            case fieldNum(PurchLine, LineNumber):
                var purchLine_orig = purchLine.orig();

                if (purchLine_orig.RecId                                != 0
                    && purchLine.LineNumber                             != purchLine_orig.LineNumber
                    && PurchParameters::find().DisallowLineRenumbering  == NoYes::Yes)
                {
                    ret = checkFailed("@SCM:RenumberingOfLinesNotAllowed");
                }
                break;
        }

        return ret;
    }


//This is new customize class, created in new model
//With extends system standard class
Note:
è  Here we need to write method which you want to modify requires override business logic of that method
è  If method not written in child class means then system will automatically call parent class method from child class.
class PurchLineType_PurchCOC extends PurchLineType_Purch
{
    public boolean validateField(FieldId _fieldId)
    {
        boolean      ret;
        Price   purchPrice;

        switch (_fieldId)
        {
            //Added - start
            case fieldNum(PurchLine, PurchPrice) :
                purchPrice = InventTableModule::find(PurchLine.itemId,ModuleInventPurchSales::Purch,false).Price;
                if(PurchLine.PurchPrice > purchPrice)
                {
                    throw warning("Purch price shouldn't be greater than, Product default purchase price");
                }
                break;
            //Added - end

            Default : 

                break;
        }

        return ret;
    }
}



//This is new customize class, created in new model
//For Extension of Microsoft standard class (PurchLineType_Purch)
Note:
è  Here wherever system is constructing PurchLineType_Purch class, based on extension object concept System will hit below code
è  After calling, next command we creating new instance of child class (PurchLineType_PurchCOC )

[ExtensionOf(classStr(PurchLineType_Purch))]
final public class PurchLineType_Purch_Extension
{
    static PurchLineType construct(PurchLine purchLine, PurchTable  purchTable)
    {
        PurchLineType_Purch coc = next construct(purchLine,purchLine.purchTable());
        coc = new PurchLineType_PurchCOC(purchLine,purchLine.purchTable());
        return coc;
    }

}

Output:
if Current Purchase line price is valid with default purchase price

If current purchase line price is greater than compare with default purchase price

No comments:

Post a Comment

Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...