Convert private Workspace to public in Azure DevOps

Sometime we do not have permission to access private workspace in Azure DevOps to make it accessible follow below steps :

  1. Global Administrator permissions –Member of the “Project Collection Administrators” permissions group in Azure DevOps Project which is linked with workspace.
  2. Open up Developer Command Prompt for VS 2019.
  3.  Identify the workspace name and owner:
    tf workspaces /owner:* /computer:* /collection:https://<site.url>/defaultcollection
  4.  Change Permission to Public:
    tf workspace /collection:https://<site.url>.visualstudio.com/defaultcollection        AzureBIDEV01_01;https://<site.url>.visualstudio.com\<username> /permission:Public  

Running custom X++ scripts in Production

Running custom X++ scripts without any downtime?

In 10.0.25 you can run simple X++ scripts on a production environment without any downtime.

This feature lets you run custom X++ scripts without having to go through Dynamics LCS or suspend your system. Therefore, you can correct minor data inconsistencies without causing any disruptive downtime.

Script details page.

Read more :

https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/deployment/run-custom-scripts

Settle payment journal against sales invoice in D365 FinOpsApps

Code used to settle posted payment journal transaction against the sales invoice

// <summary>
    /// Settle payment journal (which still has balance) against sales invoice. Each payment journal is make for one sales order only.
    /// No payment is made for multiple order. If balance is available after settle, leave the balance as there might be another invoice
    /// not comes in yet for the same order. This periodic job will settle against them when the invoice is in.
    /// </summary>
    /// <param name = "_contract"></param>
    public void processSettlement(AG_CustSalesPaymSettlementDataContract _contract)
    {
        RefRecId            paymLedgerJournalTransRefRecId = _contract.parmPaymLedgerJournalTransRecId();
        boolean             showInfoLog                    = _contract.parmShowInfoLog();
        LedgerJournalTable  paymLedgerJournalTable;
        LedgerJournalTrans  paymLedgerJournalTrans;
        CustTransOpen       paymCustTransOpen, custTransOpen;
        CustTrans           paymCustTrans;

        //Loop through all payment journal which still has open balance
        while select paymLedgerJournalTable
            where   paymLedgerJournalTable.Posted       == NoYes::Yes
            join    paymLedgerJournalTrans
            where   paymLedgerJournalTrans.JournalNum   == paymLedgerJournalTable.JournalNum
                &&  ((!paymLedgerJournalTransRefRecId)                                      //If specific payment journal line is provided, get that only,
                ||   (paymLedgerJournalTrans.RecId      == paymLedgerJournalTransRefRecId)) //else, get all lines (which satisfy other query criteria)
            join    paymCustTrans
            where   paymCustTrans.Voucher               == paymLedgerJournalTrans.Voucher
                &&  paymCustTrans.RecId                 == paymLedgerJournalTrans.CustTransId
                &&  paymCustTrans.TransType             == LedgerTransType::Payment
            join    paymCustTransOpen
            where   paymCustTransOpen.RefRecId          == paymCustTrans.RecId
        {
           AG_CustSalesPaymSettlementService::settleByPaymJourTrans(paymLedgerJournalTrans, showInfoLog);
        }

    }

    public static void settleByPaymJourTrans(LedgerJournalTrans _paymLedgerJournalTrans, boolean _showInfoLog)
    {
        boolean             useLegacyMethod = false;
        CustTable           custTable;
        LedgerJournalTrans  paymLedgerJournalTrans;
        CustTransOpen       invCustTransOpen, paymCustTransOpen, custTransOpen;
        CustTrans           invCustTrans, paymCustTrans;
        CustInvoiceJour     custInvoiceJour;
        SpecTransManager    manager;
        CustVendTransData   custVendTransData;

        //Given the payment LedgerJournalTrans, find the related CustTrans which has CustTransOpen
        select firstonly paymLedgerJournalTrans
            where   paymLedgerJournalTrans.RecId  == _paymLedgerJournalTrans.RecId
            join    paymCustTrans
            where   paymCustTrans.Voucher         == paymLedgerJournalTrans.Voucher
                &&  paymCustTrans.RecId           == paymLedgerJournalTrans.CustTransId
                &&  paymCustTrans.TransType       == LedgerTransType::Payment
            join    paymCustTransOpen
            where   paymCustTransOpen.RefRecId    == paymCustTrans.RecId;

        //Find the related invoice to be settled against the payment journal in the query above
        select firstonly invCustTrans
            where   invCustTrans.AccountNum      == paymCustTrans.AccountNum
                &&  invCustTrans.MCRPaymOrderID  == paymCustTrans.MCRPaymOrderID
                &&  invCustTrans.TransType       == LedgerTransType::Sales
            join    invCustTransOpen
            where   invCustTransOpen.RefRecId    == invCustTrans.RecId;

        custTable = CustTable::find(paymCustTrans.AccountNum);

        try
        {
            ttsbegin;

            if(paymCustTransOpen && invCustTransOpen)
            {
                //Legacy code for settlement --------------------------------------------------------------------------------------------------------
                if(useLegacyMethod)
                {
                    //Create an object of the CustVendTransData class with the invoice transaction as parameter and mark it for settlement
                    custVendTransData = CustVendTransData::construct(invCustTrans);
                    custVendTransData.markForSettlement(custTable);

                    //Create an object of the CustVendTransData class with the payment transaction as parameter and mark it for settlement
                    custVendTransData = CustVendTransData::construct(paymCustTrans);
                    custVendTransData.markForSettlement(custTable);

                    // Settle all transactions marked for settlement for this customer
                    CustTrans::settleTransact(custTable, null, true, SettleDatePrinc::DaysDate, systemdateget());
                }
                //New code for settlement -----------------------------------------------------------------------------------------------------------
                else
                {
                    //Mark for settlement
                    SpecTransExecutionContext specTransExecutionContext = SpecTransExecutionContext::newFromSource(custTable);
                    SpecTransManager          specTransManager          = SpecTransManager::construct(specTransExecutionContext.parmSpecContext());
                    Amount                    settleAmount              = invCustTransOpen.AmountCur;

                    //Prevent over settle
                    if(settleAmount > (-paymCustTransOpen.AmountCur))
                        settleAmount = (-paymCustTransOpen.AmountCur);

                    //Payment
                    specTransManager.insert(paymCustTransOpen.DataAreaId,
                                            paymCustTransOpen.TableId,
                                            paymCustTransOpen.RecId,
                                            -settleAmount,
                                            paymCustTrans.CurrencyCode);
            
                    //Invoice
                    specTransManager.insert(invCustTransOpen.DataAreaId,
                                            invCustTransOpen.TableId,
                                            invCustTransOpen.RecId,
                                            settleAmount,
                                            invCustTrans.CurrencyCode);
                
                    //Settle
                    if(CustTrans::settleTransaction(specTransExecutionContext, CustTransSettleTransactionParameters::construct()))
                    {
                        if(_showInfoLog)
                            info(strFmt("@AG:AG_SettlementCompletedFor", invCustTrans.MCRPaymOrderID, invCustTrans.Invoice, settleAmount)); //Label: Settlement completed for Sales order %1, Invoice %2, Amount %3
                    }
                }
            }

            ttscommit;
        }
        catch
        {
            error(strFmt("@AG:AG_SettlementForPaymentJournalLineFailed", _paymLedgerJournalTrans.RecId, _paymLedgerJournalTrans.accountDisplay())); //label: Settlement for payment journal line is unsuccessful (RecId: %1, Account: %2)
        }
    }

Excel integration (filter records with form value)

Scenario: We want to filter records in excel adding based on form value.

Standard D365 example is the General journal form.

Solution:

  1. Create a data entity for the data source
  2. Create an excel file and add it as a resource in Dynamics365
  3. Creating a class that will extend DocuTemplateRegistrationBaseBelow is an example of that
    class AG_IARRequestProcessTemplate extends DocuTemplateRegistrationBase
    {
        private const DocuTemplateName ExcelTemplateName    = resourceStr(AG_IARExcelTemplate);
    
        public void registerTemplates()
        {
            this.addTemplate(
                    OfficeAppApplicationType::Excel,
                    ExcelTemplateName,
                    ExcelTemplateName,
                    literalStr("Excel template for IAR  Process"),
                    literalStr("IAR process - Excel template"),
                    NoYes::No,
                    NoYes::No,
                    NoYes::Yes);
       		}
    
    }
  4. On your form where you want to add this excel and filter you can implement below interfaces
    (officeIMenuCustomizer,OfficeITemplateCustomExporter) and implement customize menu options method on AG_IARProcess

Public class AG_IARProcess extends FormRun implements officeIMenuCustomizer,OfficeITemplateCustomExporter

public void customizeMenuOptions(OfficeMenuOptions _menuOptions)
{
ListIterator dataEntityIterator = new       ListIterator(_menuOptions.dataEntityOptions());
        while (dataEntityIterator.more())
        {
            dataEntityIterator.delete();
        }
        	
DocuTemplate docuTemplate = DocuTemplate::findTemplate(OfficeAppApplicationType::Excel, resourceStr(AG_IARExcelTemplate));
        if (docuTemplate)
        {
OfficeTemplateExportMenuItem menuItem = OfficeTemplateExportMenuItem:constructWithDocuTemplate(docuTemplate, docuTemplate.TemplateID);

            _menuOptions.customMenuItems().addEnd(menuItem);
        }
    }
}

Implement the below method as well getInitialTemplateFilters
In this method, you can pass your filters

public Map getInitialTemplateFilters(OfficeTemplateExportMenuItem _menuItem)
{
     AG_IARequestDetailsTable   iarTable = AG_IARequestDetailsTable_ds.cursor();
     const str templateName = resourceStr(QTQ_IARExcelTemplate);
     DocuTemplate template = DocuTemplate::findTemplate(OfficeAppApplicationType::Excel, templateName);
     str iARequestDetailsTableEntity = tableStr(AG_IARequestDetailsTableEntity);  
      if (template && template.TemplateID == templateName)
       {
          ExportToExcelFilterTreeBuilder filterBuilder = new ExportToExcelFilterTreeBuilder(iARequestDetailsTableEntity);
          var filter = filterBuilder.areEqual(fieldStr(AG_IARequestDetailsTableEntity, CaseId), detailBase.CaseId);
          filtersToApply.insert(iARequestDetailsTableEntity, filter);
       }
}

Grid Capabilities in D365FO

Microsoft recently announced in new feature of Grid Capabilities in Platform updates for version 10.0.16 of Finance and Operations apps (February 2021)

This feature will help users will be able to expand or collapse groups as desired, which can help create a summarized view of data. Subtotals will also be shown at the group header level.

The new grid control provides several useful and powerful capabilities that you can use to enhance user productivity, construct more interesting views of your data, and get meaningful insights into your data. This article will cover the following capabilities:

Calculating totals
Typing ahead of the system
Evaluating math expressions
Grouping tabular data (enabled separately using the (Preview) Grouping in grids feature)
Pinned system columns.

1. Enable Feature
New Grid control
Go to System Admin > Feature Management > Search for New Grid control.

Note : If new feature is not available then click on Check for updates on top right corner.

Enable the feature and reload the form.

2. Grouping in grids

Enable the feature and reload the form.

Calculating totals
Users have the ability to see totals at the bottom of numeric columns in grids. A footer section at the bottom of the grid shows these totals.

First select a column where you need total

Depending on data, it will take some time to calculate totals

Once this is done, the total will be visible at the bottom.

Grouping tabular data
This is one of the good features for users to group the data based on certain columns and to get count.

Select the column where you need grouping. I have selected the grouping based on Department

Now it is showing count of positions under department and We can easily expands positions

Remove the grouping
If you want to remove the grouping then go to last column and click on three dots and select Ungroup all.

Hide/Show footer
Go to last column and select Hide/Show footer option for total.

 

Truncate AxDB database log

Recently on one of the environments with the below error

After investigation, found an issue with the MSSQL_Logs drive got full

So I figure the issue by truncating or shrinking of database log by following the below steps.

Truncate the transaction log

  1. Right-click the AxDB database and select Properties -> Options.
  2. Set the recovery model to Simple and exit the menu.
  3. Right-click the database again and select Tasks -> Shrink -> Files.
  4. Change the type to Log .
  5. Under Shrink action, select Reorganize pages before releasing unused space and click OK.

Re-sequencing of fields in Data Management in D365 F&SCM

Recently we got a required to rearranging/resequencing of fields when we export the data from Data Management framework for in Excel or CSV format.

Below are the steps we can do that :

  • Create a export data project

  • Add the entity for which data need to to exported

  • Once entity is add in the selected entities list there is a option Entity Attribute

  • What entity attribute form do? It provide the list of Fields and there sequence.

  • As shown below you can arrange the order in which data required for Integration layer or based 3rd Party Integration data mapping .
  • Now when ever we export or 3rd Party make a call to this data project it will export the data in define format.