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 :