https://www.youtube.com/watch?v=BU7BSuQIJ2Q
https://www.youtube.com/watch?v=jncRWZWt1bs
Connect with D365F&O
https://www.linkedin.com/pulse/power-automate-series-connect-dynamics-365-finance-operations-ali/
public boolean validate()
{
boolean ret = true;
BatchJob batchJob;
Batch batch;
select firstOnly batchJob
join batch
where batch.BatchJobId == batchJob.RecId
&& batch.ClassNumber == className2Id(classStr(Sysopertaioncontrollertest))
&& (batchJob.Status == BatchStatus::Waiting ||
batchJob.Status == BatchStatus::Executing);
if (batchJob)
{
error("This batch job is already running. Please wait for it to finish.");
ret = false;
}
return ret;
}
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 :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
[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);
}
}
}
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.
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.
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.
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).
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()));
Navigate to Accounts Receivable Parameter ->General -> Sales Setup

Default value 0 disables the limit. As per the help text given , a recommended value of 1 to 200 can be given for optimal performance.
I tested with a value of 25 and the ListPage shows exactly 25 records. How are these records being selected? It appears to be displaying the orders sorted in descending order by Order Number.

When you are new to D365 Finance & Operations (or X++), debugging can feel overwhelming — especially when your code runs inside large loops.
Let me start with a situation almost every beginner faces.
You write code like this:
while select employee
{
employeeId = employee.PersonnelNumber;
// complex logic
} Now imagine:
You put a breakpoint inside the loop…
And then:
This is normal when you are starting out.
Earlier in my career, I used this trick:
if (employeeId == 'E0001')
{
int x = 0; // breakpoint here
} It works — the debugger stops only for that employee
Visual Studio allows you to put a condition on a breakpoint.
Meaning:
“Stop execution only when a condition is true”
And the best part? 👉 No code change required
employeeId == "E0001" Now the debugger will:
In X++ code, this works:
if (employeeId == 'E0001') But in a conditional breakpoint, this does NOT work:
employeeId == 'E0001' ❌ Why?
Because the debugger treats single quotes as a character, not a string.
employeeId == "E0001" Or even safer:
strCmp(employeeId, "E0001") == 0 This small detail can save you a lot of confusion.
Always place it after the value is assigned:
employeeId = employee.PersonnelNumber;
// breakpoint here If you place it before assignment, the condition will never be true.