Tuesday, February 24, 2026

Code to update Acutal sales tax amount of a salesline in D365F&O X++

public static void main(Args _args)

{

   SalesTable      salesTable = SalesTable::find("000811");

   TaxRegulation   taxRegulation;

   taxRegulation = TaxRegulation::newTaxRegulation(

   SalesTotals::getTax(salesTable),

   null,

   tableNum(SalesLine),

   68719862322); //salesline recid

   if(taxRegulation)

  {

       taxRegulation.allocateAmount(10);

       taxRegulation.saveTaxRegulation();

   }      

}

Output :


SalesLine :



Code to get the Actual sales tax amount for a salesLine in D365F&O X++

public static void main(Args _args)

{

   SalesTotals           salesTotals;

   TaxAmountCur      taxAmountCur;

   SalesTable              salesTable = SalesTable::find("000811");

   salesTotals = SalesTotals::construct(salesTable);

   salesTotals.calc();

   salesTotals.tax().sourceSingleLine(true, true);

   taxAmountCur    =   salesTotals.tax().totalTaxAmountSingleLine(tableNum(SalesLine), 68719676632, true, false); //salesline recid

   Info(strFmt("%1",taxAmountCur));

}

SalesLine>Financials>SalesTax


 

Reference link : https://community.dynamics.com/forums/thread/details/?threadid=3662fb97-0b10-4d8c-b3c4-cd2a4d64018a

Tuesday, February 17, 2026

Extending Standard Budget Validation with Line-Level Legal Entity Customization

This is a customization where I added a custom field at the line level to capture the legal entity. When a specific legal entity is selected in this field, the system triggers the above process to validate the budget. If sufficient budget is available for that legal entity, the transaction proceeds. If not, the standard process is allowed to execute and throw the appropriate error.


[ExtensionOf(classStr(BudgetControlProcessor))]
final class Dax_BudgetControlProcessor_Extension
{

    public str errormsg;
    public boolean result;

    protected boolean abortProcessForBudgetCheckFailure()
    {
        boolean doAbortProcess;
        Ledger primaryLedger;
        BudgetControlConfiguration configuration;
        CompanyInfo  CompanyInfo = CompanyInfo::findDataArea(curExt());
        primaryLedger = Ledger::findByLegalEntity(CompanyInfo.recid);
        if (primaryLedger.IsBudgetControlEnabled)
        {
            configuration = BudgetControlConfiguration::findActiveByPrimaryLedger(primaryLedger.RecId);
        }
        doAbortProcess = next abortProcessForBudgetCheckFailure(); 
        if(configuration)
        {
            doAbortProcess = false;
        }
        return doAbortProcess;

 

    }

 

    public  DimensionDisplayValue getAttributeValueFromCombination(
        DimensionAttributeValueCombination _combination,
        Name _attributeName)
    {
        DimensionAttributeLevelValueView valueView;
        DimensionAttribute attribute = DimensionAttribute::findByName(_attributeName); //Retrive attribute record by Name

        select valueView
            where valueView.ValueCombinationRecId == _combination.recId
&& valueView.DimensionAttribute == attribute.RecId; //Retrieve individual Dimension attribute record

        return valueView.DisplayValue; //Retrive dimension attribute value
    }

 

    public boolean checkBudgetAmount(BudgetSource _budgetSource,BudgetCheckResultErrorWarningDetail _detailResult)
    {
        boolean ret;

 

        BUDGETTRANSACTIONLINE                   bUDGETTRANSACTIONLINE,bUDGETTRANSACTIONLINELoc;
        BUDGETTRANSACTIONHEADER                 bUDGETTRANSACTIONHEADER,bUDGETTRANSACTIONHEADERloc;
        BudgetSource                            budgetSource = _budgetSource;
        BudgetCheckResultErrorWarningDetail     budgetCheckResultErrorWarningDetail;
        DimensionAttributeValueCombination      dimensionAttributeValueCombination,dimensionAttributeValueCombinationloc,dimensionAttributeValueCombinationlocerror;
        DimensionAttribute                      dimensionAttribue,dimensionAttribueloc;
        DimensionAttributeLevelValueAllView     dimensionAttributeLevelValueAllView,dimensionAttributeLevelValueAllViewloc;
        LedgerDimensionBudgetControl            controlLedgerDimension;
        Map map = new Map(Types::String, Types::String);

        MapEnumerator mapEnumerator;
        container                               conDimensions;

 

        DimensionDisplayValue mainAccount,businessUnit,costCenter,legalEntity,mainAccountloc,businessUnitloc,costCenterloc,legalEntityloc,project,projectloc,region,regionloc;

 

        select bUDGETTRANSACTIONLINELoc
            where bUDGETTRANSACTIONLINELoc.RecId == budgetSource.BudgetTransactionLine;

 

        select bUDGETTRANSACTIONHEADERloc
                where bUDGETTRANSACTIONHEADERloc.RecId == bUDGETTRANSACTIONLINELoc.BudgetTransactionHeader;

        if(bUDGETTRANSACTIONHEADERloc.Dax_TransferCrossCompany == NoYes::Yes /*&& bUDGETTRANSACTIONLINELoc.Dax_ToCompany != curExt() */ && bUDGETTRANSACTIONLINELoc.displayAccountingAmount() < 0)
        {
            //LedgerRecId primaryLedgerId = primaryLedgersToCheckBudget.lookup(CompanyInfo::findDataArea(curExt()));

 

// Budget control rule found, get budget control ledger dimension
            controlLedgerDimension = BudgetControlLedgerDimensionHelper::findBudgetControlLedgerDimension(
                                        bUDGETTRANSACTIONHEADERloc.PrimaryLedger,
                                        bUDGETTRANSACTIONLINELoc.LedgerDimension);

 

           // real currentAmount = abs(bUDGETTRANSACTIONLINELoc.displayAccountingAmount());
            real currentAmount = abs(bUDGETTRANSACTIONLINELoc.TransactionCurrencyAmount);

 

            select dimensionAttributeValueCombination
                where dimensionAttributeValueCombination.RecId == bUDGETTRANSACTIONLINELoc.LedgerDimension;

 

            select dimensionAttributeValueCombinationlocerror
                where dimensionAttributeValueCombinationlocerror.RecId == controlLedgerDimension;

 

            while select dimensionAttributeLevelValueAllView
                where dimensionAttributeLevelValueAllView.ValueCombinationRecId == controlLedgerDimension
            {
                DimensionAttribute attribute = DimensionAttribute::find(dimensionAttributeLevelValueAllView.DimensionAttribute);

 

                conDimensions += attribute.Name;
            }

 

            for(int c=1; c<=conLen(conDimensions);c++)
            {
                str dimensionValue = this.getAttributeValueFromCombination(dimensionAttributeValueCombination,conPeek(conDimensions,c));

 

                map.insert(conPeek(conDimensions,c),dimensionValue);
            }
            // mainAccount = LedgerDimensionFacade::getMainAccountFromLedgerDimension(bUDGETTRANSACTIONLINELoc.LedgerDimension).MainAccountId;

 

        
            Amount  budgetAmount;
            boolean  mapResult;

            while select  bUDGETTRANSACTIONLINE
                join bUDGETTRANSACTIONHEADER
                    where bUDGETTRANSACTIONHEADER.RECID == bUDGETTRANSACTIONLINE.BUDGETTRANSACTIONHEADER
&& bUDGETTRANSACTIONHEADER.BUDGETMODELDATAAREAID == bUDGETTRANSACTIONLINELoc.DAX_TOCOMPANY
&& budgetTransactionHeader.TransactionStatus == BudgetTransactionStatus::Completed
            {
                map maploc = new Map(Types::String, Types::String);

 

                select dimensionAttributeValueCombinationloc
                    where dimensionAttributeValueCombinationloc.RecId == bUDGETTRANSACTIONLINE.LedgerDimension;

 

                for(int c=1; c<=conLen(conDimensions);c++)
                {
                    str dimensionValue = this.getAttributeValueFromCombination(dimensionAttributeValueCombinationloc,conPeek(conDimensions,c));

 

                    maploc.insert(conPeek(conDimensions,c),dimensionValue);
                }

                mapResult = Map::equal(map,maploc);

 

                if(mapResult)
                {
                    budgetAmount += bUDGETTRANSACTIONLINE.displayAccountingAmount();
                }
            }

 

            if(budgetAmount == 0)
            {
                errormsg = strFmt("@SYS128612",
                        bUDGETTRANSACTIONHEADERloc.TransactionNumber,
                        dimensionAttributeValueCombinationlocerror.DisplayValue,
                      //  bUDGETTRANSACTIONLINELoc.displayAccountingAmount(),
                      bUDGETTRANSACTIONLINELoc.TransactionCurrencyAmount,
                    bUDGETTRANSACTIONLINELoc.TransactionCurrency);

 

                return false;
                //throw Error(strFmt("@SYS128612",
                //        bUDGETTRANSACTIONHEADERloc.TransactionNumber,
                //        dimensionAttributeValueCombinationlocerror.DisplayValue,
                //      //  bUDGETTRANSACTIONLINELoc.displayAccountingAmount(),
                //      bUDGETTRANSACTIONLINELoc.TransactionCurrencyAmount,
                //        bUDGETTRANSACTIONLINELoc.TransactionCurrency));

            } 
            Amount exbudget;

 

            changecompany(bUDGETTRANSACTIONLINELoc.DAX_TOCOMPANY)
            {
                CurrencyExchangeHelper  currencyExchangeHelper;
                currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::current(), systemDateGet());
                CurrencyCode tocurrCode = Ledger::accountingCurrency(CompanyInfo::current());
                currencyExchangeHelper.parmLedgerRecId(Ledger::current());
                currencyExchangeHelper.parmExchangeRateTypeRecId(Ledger::budgetExchangeRateType());
                exbudget = currencyExchangeHelper.calculateCurrencyToCurrency(tocurrCode,bUDGETTRANSACTIONLINELoc.TransactionCurrency,budgetAmount,true);
            }

 

            if(exbudget >= currentAmount)
            {
                ret = true;
            }
            else
            {
               /* if(_detailResult)
                {
                    ttsbegin;
                    _detailResult.selectForUpdate(true);
                    _detailResult.AccountingCurrencyAmountOverAvailable = currentAmount - exbudget;
                    _detailResult.update();
                    ttscommit;
                } */
                Amount value = currentAmount - exbudget;

 

                if(!errormsg)
                {
                    errormsg = strFmt("@SYS128612",
                        bUDGETTRANSACTIONHEADERloc.TransactionNumber,
                        dimensionAttributeValueCombinationlocerror.DisplayValue,
                      //  bUDGETTRANSACTIONLINELoc.displayAccountingAmount(),
                      value,
                    bUDGETTRANSACTIONLINELoc.TransactionCurrency);
                }
            }
        }
        return ret;
    }

 

   public void ttsNotifyPreCommit()
    {
        BudgetSource  budgetSource,budgetSourceloc = currentSource;
        BudgetCheckResultErrorWarningDetail _detailResult;
        PurchReqLine purchReqLine;
        SourceDocumentLine  sourceDocumentLine;
        VendInvoiceInfoLine   vendInvoiceInfoLine;

        next ttsNotifyPreCommit();

 

        select  forupdate budgetSource
                where budgetSource.RecId == budgetSourceloc.RecId;
        select purchReqLine
            where purchReqLine.SourceDocumentLine == budgetSourceloc.SourceDocumentLine;
        PurchReqTable purchReqTable =PurchReqTable::find(purchReqLine.PurchReqTable);


        if(budgetSource && budgetSource.CheckResult == BudgetCheckResult::Failed && strStartsWith(purchReqTable.YNV_PurchReqStatus,"DoA"))
        {
            ttsbegin;
            budgetSource.selectForUpdate(true);
            budgetSource.CheckResult = BudgetCheckResult::PassedWithWarnings;
            budgetSource.update();
            ttscommit;
        }

 

select * from vendInvoiceInfoLine
            where vendInvoiceInfoLine.SourceDocumentLine == budgetSourceloc.SourceDocumentLine;

 

       // VendInvoiceInfoTable VendInvoiceInfoTable = VendInvoiceInfoTable::find(vendInvoiceInfoLine.SourceDocumentLine);

 

        if(budgetSource && budgetSource.CheckResult == BudgetCheckResult::Failed && vendInvoiceInfoLine && purchReqTable)
        {
            ttsbegin;
            budgetSource.selectForUpdate(true);
            budgetSource.CheckResult = BudgetCheckResult::PassedWithWarnings;
            budgetSource.update();
            ttscommit;
        }

        result = this.checkBudgetAmount(budgetSourceloc,_detailResult);

        if(result)
        {
            select  forupdate budgetSource
                where budgetSource.RecId == budgetSourceloc.RecId;
            if(budgetSource)
            {
                ttsbegin;
                budgetSource.selectForUpdate(true);
                budgetSource.CheckResult = BudgetCheckResult::Passed;
                budgetSource.update();
                ttscommit;
            }
        }
        else
        {
            if(errormsg)
            {
                select forupdate _detailResult
                    where _detailResult.BudgetSource == budgetSourceloc.RecId;

 

                if(_detailResult)
                {
                    ttsbegin;
                    _detailResult.CheckResult = BudgetCheckResult::Failed;
                    _detailResult.update();
                    ttscommit;
                }

 

                select  forupdate budgetSource
                    where budgetSource.RecId == budgetSourceloc.RecId;
                if(budgetSource)
                {
                    ttsbegin;
                    budgetSource.selectForUpdate(true);
                    budgetSource.CheckResult = BudgetCheckResult::Failed;
                    budgetSource.update();
                    ttscommit;
                }

 

               // throw Error(errormsg);
            }
        }

    }

 

    protected boolean determineMessagesForCheckResultDetails(
        LedgerRecId _primaryLedgerId,
        BudgetCheckResultErrorWarningDetail _detailResult,
        BudgetCheckResultErrorWarningDetail _groupResult)
    {
        BudgetSource                    budgetSource;
        BUDGETTRANSACTIONLINE           bUDGETTRANSACTIONLINE;
        BudgetTransactionHeader         bUDGETTRANSACTIONHEADERloc;

        str toCompany;

 

        select budgetSource
            where budgetSource.RecId == _detailResult.budgetSource;

 

        select bUDGETTRANSACTIONLINE
            where bUDGETTRANSACTIONLINE.RecId == budgetSource.BudgetTransactionLine;

 

        select bUDGETTRANSACTIONHEADERloc
            where bUDGETTRANSACTIONHEADERloc.RecId == bUDGETTRANSACTIONLINE.BudgetTransactionHeader;

 

        boolean ret,check;

 

        if(bUDGETTRANSACTIONHEADERloc.YNV_TransferCrossCompany == NoYes::Yes && /*bUDGETTRANSACTIONLINE.YNV_ToCompany != curExt() && */ bUDGETTRANSACTIONLINE.displayAccountingAmount() < 0)
        {
            result = this.checkBudgetAmount(budgetSource,_detailResult);

            ttsbegin;
            _detailResult.selectForUpdate(true);
            _detailResult.CheckResult = BudgetCheckResult::Passed;
            _detailResult.update();
            ttscommit;
        }

        ret = next determineMessagesForCheckResultDetails(_primaryLedgerId,_detailResult,_groupResult);

        return ret;
    }

 

    public void ttsNotifyCommit()
    {
        next ttsNotifyCommit();

 

        if(errormsg)
        {
            throw Error(errormsg);
        }
    }

 

}

 

Thursday, February 5, 2026

Filtering Grid Data Using a Display Method and Unbound Controls in D365f&o

Step 1: Add an Unbound Control for the Display Method

Create an unbound control on the form and bind it to the display method you want to show. This control is used only for display purposes and does not store data directly.

Step 2: Add a Field to the Table

Add a new field in the table where the logic of the display method will be written. This field acts as a helper to support filtering, since display methods alone cannot be directly used in queries.

Step 3: Update the Field Inside the Display Method

In the display method, update the newly added table field with the calculated value. This ensures the field always reflects the same data shown by the display method.

Step 4: Add an Unbound Control for Filtering

Place another unbound control above the grid. This control will be used as a filter input (for example, a string or enum value entered by the user).

Step 5: Apply Filtering Logic in the Data Source

Write the filtering logic in the executeQuery() method of the data source associated with the display method. Use the value from the unbound filter control to modify the query dynamically.

Finally, call the executeQuery() method from the modified() method of the unbound filter control so that the grid refreshes whenever the filter value changes.

Code in Execute query :

  FormDataSource   wHSInventReserve_ds = this.dataSource(formDataSourceStr(WHSInventOnHandReserve,WHSInventReserve ));

  FormStringControl   NMCOPTFilter = this.design().controlName(formControlStr(WHSInventOnHandReserve, NMCOPTFilter)); //Unbound control   

 SysQuery::findOrCreateRange(wHSInventReserve_ds.query().dataSourceTable(tableNum(WHSInventReserve)),

                                  fieldNum(WHSInventReserve, NMCOutsideProcessTag))

                                  .value(SysQuery::valueLikeAfter(!NMCOPTFilter.text() ? '*' : NMCOPTFilter.text()));