Wednesday, 19 August 2026

Company Lookup for an Unbounded Control in D365FO

 In D365FO, you can create a Company (DataArea) lookup for an unbounded control using SysTableLookup without requiring any datasource binding.

[FormControlEventHandler(formControlStr(PurchCreateFromSalesOrder, DSS_IntercompanyId), 
FormControlEventType::Lookup)] public static void DSS_IntercompanyId_OnLookup(FormControl sender, FormControlEventArgs e) { SysTableLookup sysTableLookup; Query query; QueryBuildDataSource qbds; sysTableLookup = SysTableLookup::newParameters(tableNum(CompanyInfo), sender); sysTableLookup.addLookupfield(fieldNum(CompanyInfo, DataArea)); sysTableLookup.addLookupfield(fieldNum(CompanyInfo, Name)); query = new Query(); qbds = query.addDataSource(tableNum(CompanyInfo)); // Optional filter // qbds.addRange(fieldNum(CompanyInfo, DataArea)) // .value(SysQuery::valueNotEquals(curExt())); sysTableLookup.parmQuery(query); sysTableLookup.performFormLookup(); }

Key Point

Use CompanyInfo to display available companies/legal entities and pass sender to SysTableLookup::newParameters() for the unbounded control.

ItemId Lookup for an Unbounded Control in D365FO

 In D365FO, you can create an ItemId lookup for an unbounded control using SysTableLookup without requiring any datasource binding.

The key is to pass the control (sender) directly to SysTableLookup::newParameters() and define the required lookup fields and query.

[FormControlEventHandler(formControlStr(PurchCreateFromSalesOrder, MarkupItemId), 
FormControlEventType::Lookup)] public static void MarkupItemId_OnLookup(FormControl sender, FormControlEventArgs e) { SysTableLookup sysTableLookup; Query query; QueryBuildDataSource qbds; sysTableLookup = SysTableLookup::newParameters(tableNum(InventTable), sender); sysTableLookup.addLookupfield(fieldNum(InventTable, ItemId)); sysTableLookup.addLookupfield(fieldNum(InventTable, NameAlias)); query = new Query(); qbds = query.addDataSource(tableNum(InventTable)); // Optional filter // qbds.addRange(fieldNum(InventTable, ItemType)) // .value(queryValue(ItemType::Item)); sysTableLookup.parmQuery(query); sysTableLookup.performFormLookup(); }

Key Point

For an unbounded control, pass sender to SysTableLookup::newParameters(). No datasource binding is required.

How to Confirm a Purchase Order in D365 Finance & Operations Using X++

In Microsoft Dynamics 365 Finance & Operations, a Purchase Order can be confirmed programmatically using the standard PurchFormLetter framework.

This is useful when you need to confirm a Purchase Order from custom business logic, batch processes, integrations, or custom forms without manually clicking Confirm from the Purchase Order form.

The following method accepts a PurchTable record and confirms the Purchase Order using the standard D365 F&O framework.


public static PurchTable confirmPurchaseOrder(PurchTable _purchTable)

{

    PurchFormLetter          purchFormLetter;

    PurchFormletterParmData  purchFormLetterParmData;

    PurchParmUpdate          purchParmUpdate;

    PurchParmTable           purchParmTable;


    ttsBegin;


    // Create parameter data for Purchase Order confirmation

    purchFormLetterParmData = PurchFormletterParmData::newData(

        DocumentStatus::PurchaseOrder,

        VersioningUpdateType::Initial);


    purchFormLetterParmData.parmOnlyCreateParmUpdate(true);

    purchFormLetterParmData.createData(false);


    purchParmUpdate = purchFormLetterParmData.parmParmUpdate();


    // Populate PurchParmTable

    purchParmTable.clear();


    purchParmTable.TransDate =

        DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone());


    purchParmTable.DocumentDate =

        DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone());


    purchParmTable.Ordering              = DocumentStatus::PurchaseOrder;

    purchParmTable.ParmJobStatus         = ParmJobStatus::Waiting;

    purchParmTable.PurchId               = _purchTable.PurchId;

    purchParmTable.PurchName             = _purchTable.PurchName;

    purchParmTable.DeliveryName          = _purchTable.DeliveryName;

    purchParmTable.DeliveryPostalAddress = _purchTable.DeliveryPostalAddress;

    purchParmTable.OrderAccount          = _purchTable.OrderAccount;

    purchParmTable.CurrencyCode          = _purchTable.CurrencyCode;

    purchParmTable.InvoiceAccount        = _purchTable.InvoiceAccount;

    purchParmTable.ParmId                = purchParmUpdate.ParmId;


    purchParmTable.insert();


    // Create Purchase Order confirmation

    purchFormLetter = PurchFormLetter::construct(

        DocumentStatus::PurchaseOrder);


    purchFormLetter.transDate(

        DateTimeUtil::getSystemDate(

            DateTimeUtil::getUserPreferredTimeZone()));


    purchFormLetter.proforma(false);

    purchFormLetter.specQty(PurchUpdate::All);

    purchFormLetter.purchTable(_purchTable);


    purchFormLetter.parmParmTableNum(purchParmTable.ParmId);

    purchFormLetter.parmId(purchParmTable.ParmId);

    purchFormLetter.purchParmUpdate(

        purchFormLetterParmData.parmParmUpdate());


    // Execute the confirmation

    purchFormLetter.run();


    ttsCommit;


    return _purchTable;

}

Friday, 16 January 2026

Get Parent Position Worker Name from Current Worker Position | D365FO X++

In this blog, we explore how to fetch the Parent Position Worker from a Current Worker Position in D365FO.


















The solution revolves around core HCM tables: 
- HcmWorker
- HcmPositionWorkerAssignment
- HcmPosition
- HcmPositionHierarchy.

Source Code:

public Name getParentPositionWorkerName(HcmPositionRecId _positionRecId)
{

    HcmWorker                   hcmWorker;

    HcmPositionWorkerAssignment workerAssignment;

    HcmPositionHierarchy        hcmPositionHierarchy;

    utcdatetime                 now = DateTimeUtil::getSystemDateTime();

 

    // 1. Find the parent position in the hierarchy

    // 2. Join to the assignment table to find who sits in that parent position

    // 3. Join to the worker table to get the name

    select firstonly * from hcmWorker

    join workerAssignment

        where workerAssignment.Worker == hcmWorker.RecId

           && workerAssignment.ValidFrom <= now

           && workerAssignment.ValidTo   >= now

    join hcmPositionHierarchy

        where hcmPositionHierarchy.ParentPosition == workerAssignment.Position

           && hcmPositionHierarchy.Position       == _positionRecId

           && hcmPositionHierarchy.ValidFrom     <= now

           && hcmPositionHierarchy.ValidTo       >= now;

 

    return hcmWorker.name();

}

Monday, 12 January 2026

To understand AI, think in layers

 ðŸš€ Many people think AI progress is about bigger models or new buzzwords.

 But that’s not the real shift.


To understand AI, think in layers:


🔹 Rules-based AI followed instructions written by humans.

 No thinking. No learning.


🔹 Deep Learning learned patterns from data.

 It didn’t know things — it recognized them.


🔹 Generative AI creates content.

 Text, images, code — impressive, but mostly reactive.

 You ask → it responds.


🔹 Agentic AI is different.

 It doesn’t just answer.

 It plans steps, chooses tools, and takes action to reach a goal.


That’s why this matters 👇

 The real breakthrough isn’t what AI can say.

 It’s what AI can do next without being told.


So instead of asking:

 ❌ “Is this the newest model?”


Start asking:

 ✅ “Can this AI think ahead and act on its own?”


That shift — from response to action — is where the next wave of AI is coming from.



Wednesday, 3 July 2024

How to Get Customer Free Text Invoice "Totals" form field value with X++ in D365FO

Customer free text invoices are an essential aspect of financial management in D365FO. In this blog, I have compiled all the code needed to retrieve the value of every single field in the "Totals" form, as shown in the image below.












Note: Pre-requisite to get all the values is customer invoice (CustomerInvoiceTable).

Instantiating CustFreeInvoiceCalcTotals class:

CustFreeInvoiceCalcTotals custFreeInvoiceCalcTotals = new CustFreeInvoiceCalcTotals(custInvoiceTable);

Calculating Totals:

custFreeInvoiceCalcTotals.calc();

1- Get a Credit limit from the custFreeInvoiceCalcTotals class:

CustCreditMaxMST creditMax;

creditMax = custFreeInvoiceCalcTotals.custFreeInvoiceCreditMax();

2- Get a Credit Available from the custFreeInvoiceCalcTotals class:

CustCreditFreeValueMST freeValue;

freeValue = custFreeInvoiceCalcTotals.custFreeInvoiceFreeValue();

3- Get a Line Discount from the custFreeInvoiceCalcTotals class:

SalesSumLineDiscAmount lineDisc;

lineDisc = custFreeInvoiceCalcTotals.custFreeInvoiceLineDisc();

4- Get a Subtotal Amount from the custFreeInvoiceCalcTotals class:

AmountCur sumLines;

sumLines = custFreeInvoiceCalcTotals.custFreeInvoiceInvoiceAmountGTE();

5- Get a Total Discount from the custFreeInvoiceCalcTotals class:

SalesEndDiscAmount endDisc;

endDisc = custFreeInvoiceCalcTotals.custFreeInvoiceEndDisc();

6- Get a Total Charges from the custFreeInvoiceCalcTotals class:

MarkupSumSales sumMarkup;

sumMarkup = custFreeInvoiceCalcTotals.custFreeInvoiceMarkup();  

7- Get a Sales Tax from the custFreeInvoiceCalcTotals class: 

TaxAmountCur sumTax;

 sumTax = custFreeInvoiceCalcTotals.custFreeInvoiceTaxTotal();

8- Get a Round-Off from the custFreeInvoiceCalcTotals class:

RoundOff invoiceRoundOff;

invoiceRoundOff = abs(custFreeInvoiceCalcTotals.custFreeInvoiceRoundOff());

9- Get an Invoice Amount from the custFreeInvoiceCalcTotals class:

AmountCur invoiceAmount;

invoiceAmount = custFreeInvoiceCalcTotals.custFreeInvoiceInvoiceAmount();

10- Get a Cash Discount from the custFreeInvoiceCalcTotals class:

CustCashDiscAmount cashDisc;

cashDisc = custFreeInvoiceCalcTotals.custFreeInvoiceCashDisc();

11- Get an Exchange rate from the CustInvoiceTable table1-:

Exchrate exchRate;

exchRate = CustInvoiceTable.displayExchRateForReportingCurrency();

12- Get a Currency from the custFreeInvoiceCalcTotals class:

CustCurrencyCode currency; 

currency = custFreeInvoiceCalcTotals.custFreeInvoiceCurrency();

 Result:







 

Wednesday, 22 May 2024

How to Resolve DVT Script Issues When Applying Quality Updates in LCS for D365FO

Recently, while applying Quality updates 39, I encountered an error stating "DVT script for service mode: AOSService on machine." Upon examining the error logs, I found the description: "ERROR: System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."













After some research, I discovered a solution:

First: Abort the current process in the Lifecycle Services (LCS) as this option is only available for environments in the Deployed state. Second: Then, navigate to the Environment details page, click Maintain, and select Rotate secrets. Choose Rotate the SSL certificates and confirm the action.













This simple solution resolved my problem.

Company Lookup for an Unbounded Control in D365FO

 In D365FO, you can create a Company (DataArea) lookup for an unbounded control using SysTableLookup without requiring any datasource bind...