How to get packed list(Pack & Unpack) values of custom fields using extensions in RunBase class in D365

Hi Folks,

There will be also always a change needed for STD objects in D365 from client side. Today I'm telling you about adding a dialog field on RunBase batch classes where it should fetch the custom field value from local macros with STD buffer values in RunBase Macro current version level. Here we create extension methods of pack and unpack methods in Extension of RunBase class. Please find the below example to achive our task. Example: We are adding a dialog field (Status) on InventQuarantineOrder_Scrap class Please create Extension class of InventQuarantineOrder_Scrap using CoC and add below methods accorinding to your logic.


ExtensionOf(classStr(InventQuarantineOrder_Scrap))]
public final class InventQuarantineOrder_Scrap_Extension 
{
    private RecordStatus status;
 
    #define.CurrentVersion(1)
    #localmacro.CurrentList
        status
    #endmacro
    [DataMemberAttribute]
    public RecordStatus parmRecordStatus(RecordStatus  _status)
    {      
       status = _status;
 
       return status;
    }
 
    
    public container pack()
    {
        container packedClass = next pack();
        return SysPackExtensions::appendExtension(packedClass, classStr(InventQuarantineOrder_Scrap_Extension), 		this.packMyExtension());
    }
 
    public boolean unpack(container _packedClass)
    {
        boolean result = next unpack(_packedClass);
 
        if (result)
        {
            container packedClassExtension = SysPackExtensions::findExtension(_packedClass, classStr(InventQuarantineOrder_Scrap_Extension));
            //Also unpack the extension
            if (!this.unpackMyExtension(packedClassExtension))
            {
                result = false;
            }
        }
 
        return result;
    }
 
    private container packMyExtension()
    {
        return [#CurrentVersion, #CurrentList];
    }
 
    private boolean unpackMyExtension(container _packedClass)
    {
        Integer version;
 
        if (typeOf(conPeek(_packedClass, 1)) == Types::Integer)
        {
            version = conPeek(_packedClass, 1);
        }
        else
        {
            version = RunBase::getVersion(_packedClass);
        }
         
        switch (version)
        {
            case #CurrentVersion:
                [version, #currentList] = _packedClass;
                break;
            default:
                return false;
        }
        return true;
    }
} 

Note: This logic is only related to get the values fromLocal Macro which we needed in the custom dialog field along with STd dialog fields.

 H@ppy D@xing!!

Keywords to use while working on code upgrading project from AX 2012 to D365

Hi All,

Please find the keywords below explanation which will be easy to check the over-layering code in STD objects. There will be 3 types of keywords which we use to filter the objects for clear view of custom code or over-layer in the object level and to focus on that part alone and migrate the custom code to extension objects like classes. After opening the objects  Right click on object and select open designer, Kindly follow the below points.

 1) Customization object (we can see custom objects which needed to migrate.) [Type C: in search bar]




    



 2) Custom Conflict objects (We can see the methods or controls which has conflicts with STD) [Type CF: in search bar]



 3) Extension objects ( we can see the extension objects which we moved from over-layering objects to reconfirm our work.) [Type E: in search bar]



Thanks

Un-mark settlement and reverse the customer payment journal transaction

Hi Folks, 

 This post is regarding un-marking the settlement which was done and reverse the transaction of customer. Please find the below piece of code.


public static void unsettlementAndReverse(Voucher _voucher)

{
    CustTable           custTable;
    CustTrans           findCustTrans;
    CustSettlement      custSettlement;
    SpecTransManager    specTransManager;
    AmountCur           balanceAmount;

    select firstonly * from findCustTrans
        where findCustTrans.Voucher == _voucher;
     if (findCustTrans.RecId)
     {
         balanceAmount = findCustTrans.remainAmountCur();
         if (balanceAmount == 0)
         {
             custTable = custTable::find(findCustTrans.AccountNum);
             
             select firstonly custSettlement
                   where custSettlement.TransCompany == findCustTrans.dataAreaId && custSettlement.TransRecId == findCustTrans.RecId && custSettlement.AccountNum == findCustTrans.AccountNum;

             specTransManager = SpecTransManager::newRefTableId(custTable, tablenum(custSettlement), true);
             specTransManager.insert(custSettlement.DataAreaId, custSettlement.TableId, custSettlement.RecId, 		    custSettlement.SettleAmountCur, findCustTrans.CurrencyCode);
             // custSettlement.CustVendSettlement::markOffsets(specTransManager, findCustTrans.CurrencyCode, true);
             // custSettlement.CustVendSettlement::unmarkThisAndRelatedOffsets(specTransManager);
             custSettlement.CustVendSettlement::markThisAndRelatedOffsets(specTransManager,findCustTrans.CurrencyCode);
             if (CustTrans::reverseTransact(custTable, null, settleDatePrinc::DateOfPayment, custSettlement.TransDate))
             {
                specTransManager.deleteAll();
	     }
         }
     }        
}
H@ppy D@xing!!!

Testing custom service/odata logic in postman for D365 F&O

Hi All,

Today I'm sharing few thoughts while I was testing the custom service logic from Postman.


I have searched many sources and blogs regarding this concept, But all shared about the logic of building the custom service in Dynamics365 and no one shared how to test the logic which was written in those x++ classes or to test the request/response output.

 Below are the steps need to follow for REST API custom service through POSTMAN.

1. Register an app (like for dev envn or QA/UAT)  for postman testing.



2. Client id will be auto populate and mention the below options to register app.

  •  Select accounts in any organizational directory (Any Azure AD directory - Multitenant)
  • Give Redirect Url as http://localhost




 3. Go to API permission tab Create API Permission and Mention the type of app (like Custom service or AX or Odata).

4. Go to Manifest and edit few lines for   

        "allowPublicClient": true, "oauth2AllowImplicitFlow": true





5. Go to Certificate and secrets tab and Create a Secret token and save the value in the notepad, Why because its one time visible.



6. Go to Certificate and secrets tab and Create a Secret token and save the value in the notepad, Why because its one time visible.

7. Go to Dynamics 365 F&O >>Login>>System Administration>>Setup>>Azure Active Directory  Application form>>Click New Button and enter Client Id and User



8. Now go to postman website and download the desktop app. Create the environment(in my case its Dev2) and create a collection(GetAccessToken) and mention   the below values in the body level.

    Client id : you will get it in portal.azure.com>>app registration.

    Client_secret: secret value which we saved in notepad

    Grant_type : Client_Credentials

  Scope: https://xxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudax.dynamics.com/.default ((dot)default mention this at the end) replace xxxxxxx with your environment url.

9. Mention this in url column (https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token)     

( https://login.microsoftonline.com/TenentId/oauth2/v2.0/token ) and post it.


10. Go to test tab and run the below code (Please expose all the client id,BearerToken,Sercet token and grantType as Global Variables)

       <pre><code class="language-C#">

      var json = JSON.parse(responseBody);

      tests["Get Azure AD Token"] = !json.error && responseBody !== '' && responseBody !== '{}'       &&   json.access_token !== '';

     postman.setEnvironmentVariable("bearerToken", json.access_token);

     </code></pre>



11. Create one more collection for your requirement(Like Calling Custom service) Eg: In my case its         Call Service.

12. Below is the code of sample as JSON file. 

 (Note: All the below parameters are parameter methods[parm methods] which I created in RequestDataContract Class.)

         <pre><code class="language-C#">       

        {   "_request" :

                {   

                        "PaymentReference": "100000",

                        "TransDate": "2021-09-28",

                        "BankTransactionType": "ACH-P",

                        "PaymOriginId": "ACI-PP",

                        "PaymMethodName": "EPAY",

                        "InvoiceId": " ",

                        "AmountCurCredit": "0.00",

                        "AmountCurDebit": "25.47",

                        "AmountCur": "0.00",

                        "CustAccount": "100000451",

                        "DivisionId": "Test",

                        "Description": "ACH-P",

                        "TransactionText" :"TEST",

                         "ChequeStatus": "Created",

                         "OriginalConfirmation":  "100",

                         "LedgerJournalId": " "

            }

    }

  </code></pre>

13.Select POST type and paste custom service url which we created and Click Send Button

For Custom Service:

 https://xxxxxxxxxxxxxxxx.cloudax.dynamics.com/api/services/ServiceGroup/CustomerPaymentOptio nService/createRecord

For Odata:

https://xxxxxxxxxxxxxxxx.cloudax.dynamics.com/data/[DataentityName]


Output:

This output will get depends upon the respond data contract parameters which we created in Dynamics 365 F&O



Thanks....




Difference between Power Automate/Flow Vs Azure Logic Apps

Hi Folks,

This article is to clarify the differences between both Power Automate and Azure Logic Apps. Below few points that could help us to take decision making while desiging the customization to the client requirements.


Here are the points which will match and has quality in both of them.

1) Most of the connectors are available in both.
2) Both are cloud based services for automating workflows across apps.





Thanks...

Error: One or more checked work items failed transition error while TFS check-In (VS,Dynamics365)

 

Hi There,

Some times when we complete our development/Bug and try to do check_In we will face following error.

Issue:

"One or more checked work items failed transition testing due to invalid field values.Please correct the values and try the check-in."



 Solution: Change the option to Associate from Resolve as below screenshot.



Output:



Difference between Hookable vs Wrappable vs Replaceable in D365

 Hi All,


Please find the below the concept of all Hookable vs Wrappable vs Replaceable explained in detail.


Hookable

If a method is hookable, extenders can subscribe to pre-events and post-events.

For public methods, you can opt out by adding [Hookable(false)] to the method.

You can opt in for private and protected methods by adding [Hookable(true)] to the method.

If a method is explicitly marked as [Hookable(false)], then it is not wrappable.


Best practices when you write code

When a method is hookable, the compiler generates extra intermediate language (IL) code to enable the method as an extension point. Although the extra code has performance overhead, this overhead is negligible in most cases. However, for performance-critical methods, consider marking the method as non-hookable.


Wrappable

If a method is wrappable, extenders can wrap it by using Chain of Command (CoC). Extenders must call next, because they aren't allowed to break the CoC.


For protected and public methods, you can opt out by adding [Wrappable(false)] to the method.

You can't opt in for private methods.


Best practices when you write code

CoC resembles inheritance in many ways. Typically, if you want other people to be able to call your method but not change it, you mark the method as final. Consider marking these methods as non-wrappable or non-hookable.


Replaceable

If a method is replaceable, extenders can wrap it by using CoC, but they don't have to unconditionally call next. Although extenders can break the CoC, the expectation is that they will only conditionally break it. The compiler doesn't enforce calls to next.

To be replaceable, a method must also be wrappable.

For wrappable methods, you can opt in by adding [Replaceable] to the method.


see more details here: https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/extensibility/extensibility-attributes

Adding a new inventory dimensions using extension is easy now in D365

 Hi Folks,

I was browsing for a concept where i need to add new inventory dimension to my customization and came to know that, Its pretty easy and simple now in Dynamics 365 using extension concept.

Please check out the link below for more details:

https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/extensibility/inventory-dimensions


H@ppy D@xing...


Form implements interface concept now in D365

Hi All, Forms can now implement interfaces.

public class MyForm extends FormRun implements SysPackable
{
} 

Below taking the example of to implement a method on each form part that is used on the workspace that would get a filter value from its parent workspace form and trigger those methods each time a modified() method is triggered on a workspace itself. However, this solution has two main issues.

 First, some controls may not be present on the workspace itself, but they can be located on the setup dialog, that is called from the workspace instead (like the inventory dimensions’ setup). 

 Second, the count tiles are basically menu items with a particular query specified, so there is no way to create or trigger any method within them. 

 Tile filtering and form part filtering share common interfaces and still, there are some differences in implementation. Below are instructions for both: 

  Tile Filtering 

 Create a new AOT query and use it as a source for the count tile. 

 Create a new class that implements the SysIFilterStructureStrategy interface and extends the   SysFilterStructureStrategyQuery. 
 

 Implement the SysIFilterProvider interface for your workspace. 

 Add methods that will bound the filter control with the SysIFilterStructureStrategy engine. 


  Form Part Filtering 

 The Form part filtering shares the same approach as the Tile filtering but it requires an additional code on the form part itself.

 Create a new form part and use the AOT query as the main datasource for the form. It will be used to filter for data. Implement the SysIFilterEventHandler and SysIFilterConsumerForm interfaces. 

 Create a new class that implements the SysIFilterStructureStrategy interface and extends the SysFilterStructureStrategyQuery similarly to the class described in the Tile filtering section of this article 

 Add methods that will bound the form datasource with the filter control from your workspace.


 Add your form part to the workspace and set the RunMode property value to Local. 

 Please note: The solution described above utilizes Dynamics 365 for Finance and Operations cache and tile cache storages. The query or class renaming might require the usage data and tile configuration refresh.

New capability in X++ : The In operator

Hi Folks, 

Microsoft recently added a new feature in X++, making it easier to make certain SQL-where clauses extensible in X++. 


 Consider this method from CustomTrans>>calcPriceAmountStdAdjustment (Custom objects)

private PriceAmountStdAdjustment calcPriceAmountStdAdjustment()
{
        CustomSettlement customSettlement;

       
        select sum(PriceAmountAdjustment) from customSettlement
where customSettlement.TransRecId == this.RecId
&& customSettlement.Cancelled == NoYes::No
&& (customSettlement.OperationsPosting == PostingType::PurchStdProfit
|| customSettlement.OperationsPosting == PostingType::PurchStdLoss
|| customSettlement.OperationsPosting == PostingType::InventStdProfit
|| customSettlement.OperationsPosting == PostingType::InventStdLoss)
; return customSettlement.PriceAmountAdjustment;
}
It can now be refactored to support an extender in controlling which PostingTypes to include in the calculation:

private PriceAmountStdAdjustment calcPriceAmountStdAdjustment()
{ CustomSettlement customSettlement;
Container postingTypes = this. postingTypesForPriceAmtStdAdjustmentCalculation(); select sum(PriceAmountAdjustment) from customSettlement
where customSettlement.TransRecId == this.RecId
&& customSettlement.Cancelled == NoYes::No
&& (customSettlement.OperationsPosting in postingTypes ;
return customSettlement.PriceAmountAdjustment;
} protector container postingTypesForPriceAmtStdAdjustmentCalculation()
{ return    [PostingType::PurchStdProfit,
PostingType::PurchStdLoss,
PostingType::InventStdProfit,
PostingType::InventStdLoss];
}
Awesome feature but still most people didn't noticed.

Chain of command on Form level are more flexible now in Dynamics 365

Hi All, Happy to share few more concepts of chain of Commands on form level in Dynamics 365 

Day by day the Microsoft is releasing Platform updates which opens up Flexibility for the developers to code easily. Below are the concepts are mingled with new and old concepts which were explained on form level. 

Now we can write down or create extension to the deep root level of datasource fieldsto controls of the forms Below are few points we can acheive in different way. 

 1. Extension Methods on the root of the form. 

 2. Extension Methods on controls. 

 3. Extension Methods on data sources. 

 4. Extension Methods on fields on data sources. 

 So far you can only wrap system methods on the latter 3, i.e. methods that are defined on the FormControl, FormDataSourceObject and FormDataSet classes, respectively. You can wrap any method defined in the root of the form. Also, there is no support for extending multiple forms, controls, data sources or fields within the same extension-of class. Examples:

  
[ExtensionOf(formStr(SomeForm))]

[ExtensionOf(formControlStr(SomeForm, SomeControl))]

[ExtensionOf(formDataSourceStr(SomeForm, SomeDataSource))]

[ExtensionOf(formDataFieldStr(SomeForm, SomeDataSource, SomeField))]

See more links here: https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/extensibility/method-wrapping-coc