Wednesday, January 28, 2026

Limit the Records in Sales order list page- D365FO

 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.

Wednesday, January 21, 2026

Debugging Large Loops in D365 F&O

 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.


The Common Beginner Problem

You write code like this:

while select employee
{
    employeeId = employee.PersonnelNumber;

    // complex logic
} 

Now imagine:

  • The loop runs for hundreds of employees
  • A bug happens only for one employee (E0001)

You put a breakpoint inside the loop…

And then:

  • The debugger stops again and again
  • You keep pressing F5
  • You lose focus and patience

This is normal when you are starting out.


What I Used to Do Earlier (Many Beginners Still Do)

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


The Right Tool: Conditional Breakpoints

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


How to Add a Conditional Breakpoint (Step-by-Step)

  1. Put a breakpoint on the required line
  2. Right-click the breakpoint → Conditions
  3. Enable Conditions
  4. Enter the condition:

employeeId == "E0001" 

Now the debugger will:

  • Skip all other employees
  • Stop only when E0001 is processed


Article content
Article content



⚠️ Very Important for Newbies: String Syntax Gotcha

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.

✅ Always use double quotes in debugger conditions:

employeeId == "E0001" 

Or even safer:

strCmp(employeeId, "E0001") == 0 

This small detail can save you a lot of confusion.


Where Should You Place the Breakpoint?

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.

Tuesday, December 16, 2025

X++ Code for Sending PO Details in a Tabular Format by Email

        PurchTable          purchTable;
        PurchLine           purchLine;
        PurchLineAmount     poAmount;
        Map                 templateTokens;
        str                 emailSubject,body;
        templateTokens      = new Map(Types::String, Types::String);
        boolean ret = false;
       
        emailSubject = "Open PO list above one CR and above 180 days";
        templateTokens.insert("@SYS74341", emailSubject);
        body = '<p>Dear Team,</p>';
        body+= '<p>Open PO details listed below which exceeds the 180 days.</p>';
        body+= '<table style="border-collapse: collapse; width: 100%;" border="1">';
        body+= '<tbody>';

        body+= '<tr>';
        body+= '<td style="width: 16.6667%;"><strong>Purchase Id</strong></td>';
        body+= '<td style="width: 16.6667%;"><strong>Purchase name</strong></td>';
        body+= '<td style="width: 16.6667%;"><strong>Vendor Id</strong></td>';
        body+= '<td style="width: 16.6667%;"><strong>Vendor name</strong></td>';
        body+= '<td style="width: 16.6667%;"><strong>Purchase amount</strong></td>';
        body+= '</tr>';
 
        try
        {
            while select purchTable // write your custom logic
            {    
                        ret = true;
     
                        body+= '<tr>';
                        body+= '<td style="width: 16.6667%;">';
                        body+= strFmt('%1', purchTable.PurchId);
                        body+= '</td>';
                        body+= '<td style="width: 16.6667%;">';
                        body+= strFmt('%1', purchTable.PurchName);
                        body+= '</td>';
                        body+= '<td style="width: 16.6667%;">';
                        body+= strFmt('%1', purchTable.OrderAccount);
                        body+= '</td>';
                        body+= '<td style="width: 16.6667%;">';
                        body+= strFmt('%1', VendTable::find(purchTable.OrderAccount).name());
                        body+= '</td>';
                        body+= '<td style="width: 16.6667%;">';
                        body+= strFmt('%1', poAmount);
                        body+= '</td>';
                        body+= '</tr>';
            }

            if(ret)
            {
                SysEmailParameters        emailParameters   =   SysEmailParameters::find();
                SysMailerMessageBuilder   messageBuilderloc = new SysMailerMessageBuilder();
                messageBuilderloc.setFrom(emailParameters.SMTPUserName);
                messageBuilderloc.addTo("TOMAIL");
                //messageBuilder.addCc(_emailCC);
                messageBuilderloc.setSubject(emailSubject);
                messageBuilderloc.setBody(body,true);
                SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(messageBuilderloc.getMessage());
         
                info("Mail alert operation completed");
            }
        }
        catch(Exception::Error)
        {
            throw Exception::Error;
        }

----------------

Output :