Thursday 19 November 2020

Error message : More than one form was opened at once for the lookup control. in D365 FinOps

 Error message: More than one form was opened at once for the lookup control. in lookup in D365 F&O

If you get error message (More than one form was opened at once for the lookup control.) in notification Action Centre while clicking on lookup button in D365 then you just need to call a peace of code just after lookup performs.

        //cancel super() to prevent error.

        FormControlCancelableSuperEventArgs cancelEventArgs = e as FormControlCancelableSuperEventArgs;

        cancelEventArgs.CancelSuperCall();

For example - Lookup method:

[FormControlEventHandler(formControlStr(EcoResProductDetailsExtended, InventTable_HSNRFColorCode), FormControlEventType::Lookup)]

    public static void InventTable_HSNFRColorCode_OnLookup(FormControl sender, FormControlEventArgs e)

    {

        Query                   query = new Query();

        QueryBuildDataSource    queryBuildDataSource;

        SysTableLookup          sysTableLookup;


        sysTableLookup = SysTableLookup::newParameters(tableNum(HSNRFColorCodes), sender);

        queryBuildDataSource = query.addDataSource(tableNum(HSNRFColorCodes));

   

        sysTableLookup.addLookupField(fieldNum(HSNRFColorCodes, NRFColorCode));

        sysTableLookup.addLookupField(fieldNum(HSNRFColorCodes, NRFColorGroup));

        sysTableLookup.addLookupField(fieldNum(HSNRFColorCodes, Description));


        sysTableLookup.parmQuery(query);

        sysTableLookup.performFormLookup();

        // If you get error message (More than one form was opened at once for the lookup control.) in notification Action Centre then call below one line code.

        //cancel super() to prevent error.

        FormControlCancelableSuperEventArgs cancelEventArgs = e as FormControlCancelableSuperEventArgs;

        cancelEventArgs.CancelSuperCall();

    }


Happy DAXing...

Monday 9 November 2020

How to get ExecutionId at runtime in D365 FO Data management

 Get ExecutionId at runtime in Data entity.

Today, I am going to share a practice code to get ExecutionId at runtime in D365 FinOps.
Lets say, you are working on a data entity and you need to get ExecutionId at run time so that you can call you custom logic for that particular data job.

Check the data entity you are working on and find the 2- methods (1. postGetStagingData 2. postTargetProcess). If you don't find these methods, you can add in the Data entity extension.

Method-1:
// This is the method which executes before data execution from staging to target
public static void postGetStagingData(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
{
        DMFExecutionId     executionId = _dmfDefinitionGroupExecution.ExecutionId;
}


Method-2:
// This is the method which executes after data execution in target at event of DMFEntityWritter.write()
public static void postTargetProcess(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
{
        DMFExecutionId     executionId = _dmfDefinitionGroupExecution.ExecutionId;
}


Happy DAXing...

Wednesday 30 September 2020

Customize Sales Totals form in D365 FO (AX)

Customize Sales Totals form in D365 FO (AX)

Today, I am going to share with you that how to override Sales tax in Sales Totals form based on condition.

Here, my requirement is- If (SalesTable.HSChangedInD365 == NoYes::No) then Sales Totals form should display the tax what we have received through web service (Or, order import through from party API) otherwise it should display the standard calculated tax. So I have overridden the tax value when values are initializing in container.

Here, we go...

/// <summary>
///     this is the extension class of SalesTotals class.
/// </summary>
[ExtensionOf(classStr(SalesTotals))]
final class SalesTotalsLFI_Extension
{
    /// <summary>
    ///     this is the COC of SalesTotals.displayFieldsServer()
    ///     to modify container and initialize Total sales tax and updated Invoice amount based on below condition.
    /// </summary>
    /// <param name = "_orderTable">Caller table to calculate totals for.</param>
    /// <param name = "_specQty">Quantity to calculate totals for.</param>
    /// <param name = "_currencyCode">Currency code to calculate totals for.</param>
    /// <returns>
    /// Container of the field values to be shown on the totals form.
    /// </returns>
    static public container displayFieldsServer(Common _orderTable, SalesUpdate _specQty, CurrencyCode _currencyCode)
    {
        container       resultContainer = conNull();

        resultContainer = next displayFieldsServer(_orderTable, _specQty, _currencyCode);

        if (_orderTable.TableId == tableNum(SalesTable))
        {
            SalesTable  salesTableLoc = _orderTable;
            if (salesTableLoc.HSChangedInD365 == NoYes::No && conPeek(resultContainer, TradeTotals::posTaxTotal()) == 0)
            {
                resultContainer = conPoke(resultContainer, TradeTotals::posTaxTotal(), salesTableLoc.HSTotalWebTaxAmountCur);
                resultContainer = conPoke(resultContainer, TradeTotals::posTotalAmount(), (salesTableLoc.HSTotalWebTaxAmountCur + conpeek(resultContainer, TradeTotals::posTotalAmount())));
            }
        }

        return resultContainer;
    }

Happy DAXING...




Monday 28 September 2020

How to override (adjust) tax through X++ code in D365 FO

 Override the tax in D365 FinOps

Today, I am going to share some activities based on Sales tax on to "Override" and "Remove the adjusted tax amount" too for a particular Sales order. 

Task# 01: To override sales tax amount in a Sales order

Here, I am going to share my experience to override the sales tax (adjust sales tax) in a Sales order.

Scenario# 1.1: To override sales tax in a sales order

Here, you just need SalesTable buffer at runtime which you need to pass to the code. I have a custom field control in the SalesTable where I am storing total actual tax amount (which I am getting from the third-party tool). 

TaxRegulation   taxRegulation;
                    SalesTotals     salesTotals = SalesTotals::construct(salesTableLocal);
        
                    salesTotals.calc();
                    taxRegulation = TaxRegulation::newTaxRegulation(salesTotals.tax());
                    taxRegulation.allocateAmount(salesTableLocal.HSTotalWebTaxAmountCur);
                    taxRegulation.saveTaxRegulation();

Scenario# 1.2: To override sales tax in a sales order

Here, the scenario is to create a Sales order and post Sales invoice along with Tax override activity too.





Task# 02: To reset Actual to Calculated sales tax amount in a Sales order

Here, I am going to share my experience on to remove adjusted sales tax amount in a Sales order.

Scenario# 2.1: To override sales tax in a sales order

Here, you just need SalesTable buffer at runtime which you need to pass to the code.

// reset actual to calculated sales tax amount.
            TaxRegulation   taxRegulation;
            SalesTotals     salesTotals = SalesTotals::construct(salesTableLocal);
            salesTotals.calc();

            taxRegulation = TaxRegulation::newTaxRegulation(salesTotals.tax(), null,salesTableLocal.TableId, salesTableLocal.RecId);
            if (taxRegulation.taxLinesExist())
            {
                taxRegulation.resetTaxRegulation();

                taxRegulation.saveTaxRegulation();
            }



Happy DAXing...


Tuesday 15 September 2020

How to calculate total tax for a order in D365 using X++

 How to calculate total tax for a Sales order using X++

Today, I will show, how to calculate tax in D365 FO (AX) through code

Scenario 1: To find Sales Totals values for Sales order in D365

Here, my requirement is to export Sales Totals component's value through custom data entity. I have applied below logic, hope it will help you...

Accounts receivable/ All sales orders/ select any Sales order/ Sales order button group/ View/ Totals 
public void postLoad()
    {
        SalesLine   salesLineLoc;
        SalesTable  salesTableLoc = SalesTable::find(this.SalesId);
        SalesTotals totals;

        super();

        select sum(LineAmount) from salesLineLoc
            where salesLineLoc.SalesId == salesTableLoc.SalesId;
        this.SubTotalAmount = salesLineLoc.LineAmount;

        // No problem if the total is not negative
        totals = SalesTotals::construct(salesTableLoc, SalesUpdate::All);
        totals.calc();
        this.TotalEndDisc   = conPeek(totals.displayFields(), TradeTotals::posEndDisc());
        this.TotalLineDisc  = conPeek(totals.displayFields(), TradeTotals::posLineDisc());
        this.TotalCharges   = conPeek(totals.displayFields(), TradeTotals::posMarkup());
        this.InvoiceAmount  = conPeek(totals.displayFields(), TradeTotals::posTotalAmount());
        
        salesLineLoc = null;
        salesLineLoc = SalesLine::findInventTransId(this.InventTransId);
        if (salesTableLoc.HSChangedInD365 == NoYes::No)
        {
            this.WebShippingTaxAmount   = salesTableLoc.HSWebChargeTaxAmountCur;
            this.TotalTaxAmount         = salesTableLoc.HSTotalWebTaxAmountCur;
            this.LineTaxAmount          = salesLineLoc.HSWebLineTaxAmountCur;
        }
        else
        {
            this.TotalTaxAmount = conPeek(totals.displayFields(), TradeTotals::posTaxTotal());
            //this.TotalTaxAmount = abs(salesTotals.tax().totalTaxAmountCalculated());   // Total calculated sales tax amount
            //this.TotalTaxAmount = abs(salesTotals.tax().totalTaxAmount());             // Total actual sales tax amount

            totals.tax().sourceSingleLine(true, true);
            this.LineTaxAmount = totals.tax().totalRegulatedTaxAmountSingleLine(salesLineLoc.TableId, salesLineLoc.RecId);  // sales line actual tax amount
            //this.LineTaxAmount = salesTotals.tax().totalTaxAmountSingleLine(salesLineLoc.TableId, salesLineLoc.RecId);    // sales line calculated tax amount
            
            // to get calculated tax for a particular charge line associated with a sales order.
            MarkupTrans markupTransLoc;
            select firstonly markupTransLoc
                where markupTransLoc.MarkupCode == HSIntegrationParameters::find().PaidByCustomer  //'CUSTFRGHT'
                &&    markupTransLoc.TransRecId == salesTableLoc.RecId
                &&    markupTransLoc.TransTableId == tableNum(SalesTable);
            this.WebShippingTaxAmount = abs(totals.tax().taxPrLine(tableNum(MarkupTrans), markupTransLoc.RecId));
        }       
    }

//You have to pass these values to the functions whether it comes from PurchLine or SalesLine or any other table.
//This may not work for Avalara tax engine then follow below scenarios...

Tax::calcTaxAmount(purchLine.TaxGroup, purchLine.TaxItemGroup, Systemdateget(), purchLine.CurrencyCode, purchLine.LineAmount, TaxModuleType::Purch);

Scenario 2.1: To calculate tax for each Sales order line in D365

I have written display method in SalesLine table to show line-wise calculated sales tax. This method can be utilized in multiple places...

public display TaxAmountCur displayLineTaxAmount()
    {
        salesTable      salesTable;
        SalesTotals     salesTotals;
        TaxAmountCur    taxAmountCur;

        salesTable  = SalesTable::find(this.SalesId, false); 
        salesTotals = SalesTotals::construct(salesTable, SalesUpdate::All);
        salesTotals.calc();
        salesTotals.tax().sourceSingleLine(true, true);
        taxAmountCur    = salesTotals.tax().totalTaxAmountSingleLine(this.TableId, this.RecId);

        return TaxAmountCur;

    }

Scenario 2.2: To calculate tax for each Sales order line in D365

I have written display method in SalesLine table to show line-wise calculated sales tax. This method can be utilized in multiple places...


public display TaxAmount displayLineTaxAmount()
    {
        SalesLine       salesLineLoc;
       
select firstonly salesLineLoc
            where salesLineLoc.RecId == this.RecId;

        return Tax::calcTaxAmount(salesLineLoc.TaxGroup,
                                salesLineLoc.TaxItemGroup,
                                Systemdateget(), 
                                salesLineLoc.CurrencyCode,
                                salesLineLoc.LineAmount,
                                TaxModuleType::Sales);
    }

Scenario 3: To calculate tax for Sales order in D365

I have written display method in SalesTable table to show total calculated sales tax. This method can be utilized in multiple places...


public display TaxAmountCur displayTotalTaxAmount()
    {
        salesTable      salesTable;
        SalesTotals     salesTotals;
        TaxAmountCur    taxAmountCur;

        salesTable  = SalesTable::find(this.SalesId, false);
        salesTotals = SalesTotals::construct(salesTable, SalesUpdate::All);
        salesTotals.calc();
        taxAmountCur = abs(salesTotals.tax().totalTaxAmount());

        return TaxAmountCur;
    }

Add display method as a data field in Field groups in a table



ScenariScenario 4: To calculate tax for each Purchase order line in D365.

I have written display method in PurchLine table to show line-wise calculated purch tax. This method can be utilized in multiple places...

public display TaxAmountCur totalTaxAmount(boolean _adjustTaxSign = true, boolean _includeUseTax = false)
{
    PurchTotals     purchTotals;
    TaxAmountCur    taxAmountCur;

    purchTotals     = PurchTotals::newPurchTable(this.purchTable());
    purchTotals.calc();
    purchTotals.tax().sourceSingleLine(true, true);
    taxAmountCur    = purchTotals.tax().totalTaxAmountSingleLine(this.TableId, this.RecId, _adjustTaxSign, _includeUseTax);

    return taxAmountCur;
}

Scenario 5: To calculate tax for Purchase order in D365

I have written display method in PurchTable table to show total calculated purch tax. This method can be utilized in multiple places...

public display TaxAmountCur totalTaxAmount(boolean _adjustTaxSign = true, boolean _includeUseTax = false)
{
    PurchTotals     purchTotals;
    TaxAmountCur    taxAmountCur;

    purchTotals     = PurchTotals::newPurchTable(this.purchTable());
    purchTotals.calc();
    taxAmountCur    = purchTotals.tax().totalTaxAmount();

    return taxAmountCur;
}

Scenario 6: To calculate tax for GL journal in D365

I have written display method in LedgerJournalTrans table to show total calculated tax. This method can be utilized in multiple places...

public display TaxAmountCur totalTaxAmount(boolean _adjustTaxSign = true, boolean _includeUseTax = false)
{
        TaxCalculation taxCalculation;
    LedgerJournalTrans      ledgerJournalTrans;
    TmpTaxWorkTrans         tmpTaxWorkTrans;
    TaxAmountCur            taxAmountCur;

    ledgerJournalTrans = LedgerJournalTrans::findRecId(5637293082, false); 

    // This is from `\Classes\LedgerJournalEngine\getShowTax`
    taxCalculation = LedgerJournalTrans::getTaxInstance(ledgerJournalTrans.JournalNum, 
ledgerJournalTrans.Voucher,
  ledgerJournalTrans.Invoice, 
true, 
null, 
false, 
ledgerJournalTrans.TransDate);
    taxCalculation.sourceSingleLine(true, false);

    // This is from `\Classes\TaxTmpWorkTransForm\initTax`
    tmpTaxWorkTrans.setTmpData(taxCalculation.tmpTaxWorkTrans());

    // This is the temporary table that is populated
    while select tmpTaxWorkTrans
    {
        // This is from `\Classes\TaxTmpWorkTransForm\getSourceBaseAmountCur`
        taxAmountCur = (tmpTaxWorkTrans.SourceTaxAmountCur * tmpTaxWorkTrans.taxChangeDisplaySign(null));

        // This just outputs some data
        info(strFmt("%1: %2", tmpTaxWorkTrans.TaxCode, taxAmountCur));
    }

    return taxAmountCur;
}


--------------------------------
Happy DAXing...

Friday 14 August 2020

Issue on Avalara Sales tax calculation in D365 FO

 Hi Techies,

This post is related to issue on Avalara sales tax calculation. 

Scenario: You are good with sales tax calculation while creating sales order manually. The reason, Avalara tax engine is been triggered on SalesTable_OnWrite() event through SalesTable form.

Issue: If you are importing sales orders through data entities or through interface, in that case SalesTable insert event is been triggered and you will see Avalara sales tax has not been calculated for those sales orders. Here is a fix:  

You can copy the Avalara code that is part of the Write method and use it in the Insert method/event - 

The code –


AVA_TaxEngine    ava_TaxEngine = new AVA_TaxEngine();

if (AVA_TaxEngine::isAvaTaxConfigurationEnabled() &&  !Ava_Configuration::find().DisableTaxCalculation)

        {

            ava_TaxEngine.GetTax(_salesTable,

                DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()),

                                 false,

                                 null,

                                 AVA_DocumentType::SalesOrder,

                                 '',

                                 _salesTable.SalesType == SalesType::ReturnItem ?                 AVA_ConnSource::ReturnOrder : AVA_ConnSource::SalesOrder );

}

You need to pass the right parameters with the method.


Happy DAXing...


Thursday 23 July 2020

The supplied SnapshotPoint is on an incorrect snapshot.

Hi Techies,

Before moving to the issue and resolution, I will be sharing some background:

  • Using Visual Studio 2015
  • Dynamics 365 FinOps 10.0.11 PU35
  • Azure based cloud hosted development environment
All of sudden I started getting an error "The supplied SnapshotPoint is on an incorrect snapshot." and hard crash while doing code development in VS for D365 FO AOT. VS doesn't allow to do a line change.


Resolution-1: Navigate to VS -> Tools -> Options -> Text Editor -> All languages -> X++

 


Un-check "Word wrap" and "Show visual glyphs for word wrap" check boxes and select OK.



Issue should be fixed.

Resolution-2: In case issue still exists, then go to higher version of VS or go with the latest update

This issue has been fixed and is now available in our latest update. You can download the update via the in-product notification or from here: https://visualstudio.microsoft.com/vs/ 


Happy DAXing...