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 :



Wednesday, December 3, 2025

Code to attach multiple files from a folder X++

My requirement is to attach multiple files from a folder to a specific record. This code selects only the files that are allowed by D365 Finance & Operations.

  public static void main(Args _args)

  {

      FilePath filePath = @"C:\Temp\saitesting"; //Folder path

      PurchId  purchId  = "000030";

      int attachedCount = 0;

      int skippedCount  = 0;

      PurchTable purchTable = PurchTable::find(purchId, true);

      if (!purchTable)

      {

          throw error(strFmt("PO %1 not found", purchId));

      }

      DocuType docType = DocuType::find("File");

      if (!docType)

      {

          throw error("@SYS19389");

      }

      System.String[] files = System.IO.Directory::GetFiles(filePath, "*.*");

      System.Collections.IEnumerator enumerator = files.GetEnumerator();

      while (enumerator.MoveNext())

      {

          try

          {

              Filename fileFullPath = enumerator.get_Current();

              Filename fileNameOnly = System.IO.Path::GetFileName(fileFullPath);

              str fileExtension = Docu::GetFileExtension(fileNameOnly);

              if (fileExtension && !Docu::validateExtension(fileExtension))

              {

                  skippedCount++;

                  warning(strFmt("Skipped %1 due to invalid extension", fileNameOnly));

                  continue;

              }

              System.IO.FileStream fileStream =

          new System.IO.FileStream(fileFullPath, System.IO.FileMode::Open, System.IO.FileAccess::Read);

              System.IO.MemoryStream memStream = new System.IO.MemoryStream();

              fileStream.CopyTo(memStream);

              fileStream.Close();

              memStream.Position = 0;

              ttsBegin;

              DocumentManagement::attachFileForReference(

          purchTable.TableId,

          purchTable.RecId,

          curext(),

          docType.TypeId,

          memStream,

          fileNameOnly,

          fileNameOnly,

          ''

      );

              ttsCommit;

              attachedCount++;

              info(strFmt("Attached %1 to PO %2", fileNameOnly, purchId));

          }

          catch (Exception::Error)

          {

              skippedCount++;

              warning(strFmt("Error attaching %1: %2", enumerator.get_Current(), exceptionTextFallThrough()));

          }

      }

      info(strFmt("Attachment job completed. %1 files attached, %2 files skipped.", attachedCount, skippedCount));

  }

Reference blog :

https://daxture.blogspot.com/2017/04/ax-2012-reading-files-from-directory.html

Tuesday, November 25, 2025

How to Convert Amounts Between Currencies in D365F&O with X++

This code converts the specified amount from one currency to another using the exchange rates configured in the system, as shown in the images below.

 public Amount getExchangeRateCurrency(Amount _amount)

{

     CurrencyExchangeHelper  currencyExchangeHelper;

     CurrencyCode            toCurrency= SystemParameters::find().SystemCurrencyCode;

  

     TaxAmount               taxAmount;

    currencyExchangeHelper = currencyExchangeHelper::construct();

    currencyExchangeHelper.parmLedgerRecId(Ledger::current()); //gets the current company

    currencyExchangeHelper.parmExchangeRateTypeRecId(Ledger::budgetExchangeRateType()); // gets the budget rate type

 

    return currencyExchangeHelper.calculateCurrencyToCurrency(fromCurrencyCode,toCurrency,_amount, true);  

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




Sunday, November 23, 2025

Get individual dimensions value from Ledger Dimension in X++

Static DimensionDisplayValue getAttributeValueFromCombination(

    DimensionAttributeValueCombination _combination, 

    Name _attributeName = 'BusinessUnit')

{

    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

}

Reference :

https://d365ffo.com/2021/11/17/ax-d365fo-get-individual-dimensions-value-from-ledger-dimension-in-x/

Friday, November 14, 2025

Code to Read Manually Uploaded CSV Files in D365FO Using X++

public static void main(Args _args)

{

   AsciiStreamIo                       file;

   Array                               fileLines;

   FileUploadTemporaryStorageResult    fileUpload;

   fileUpload = File::GetFileFromUser() as FileUploadTemporaryStorageResult;

   file = AsciiStreamIo::constructForRead(fileUpload.openResult());

   if (file)

   {

       if (file.status())

       {

           throw error("@SYS52680");

       }

       file.inFieldDelimiter('|');

       file.inRecordDelimiter('\r\n');

   }

   container record;

   while (!file.status())

   {

       record = file.read();

       if (conLen(record))

       {

           info(strFmt("%1 - %2",conPeek(record,1),conPeek(record,2)));

       }

   }

}

......................................

Output :













Code to read CSV file from local folder in D365F&O X++

public static void main(Args _args)

{

   AsciiStreamIo                       file;

   Array                               fileLines;

   FileUploadTemporaryStorageResult    fileUpload;

   #File

   System.IO.FileStream    fileStream;

   System.IO.Stream        fileContentStream;

   System.IO.Stream        stream;

   System.String           filePath = @"C:\Temp\Vendor.csv"; //specify the file path

   fileStream = new System.IO.FileStream(filePath, System.IO.FileMode::Open, System.IO.FileAccess::Read);

   stream = fileStream;

 

   file = AsciiStreamIo::constructForRead(stream);

   if (file)

   {

       if (file.status())

       {

           throw error("@SYS52680");

       }

       file.inFieldDelimiter('|');

       file.inRecordDelimiter('\r\n');

   }

   container record;

   while (!file.status())

   {

       record = file.read();

       if (conLen(record))

       {

           info(strFmt("%1 - %2",conPeek(record,1),conPeek(record,2)));

       }

   }

}

Output :










Wednesday, November 12, 2025

Activate Financial Dimensions without Maintenance Mode - D365 F&O

Export the entity 'Dimension attribute activation'.

Article content

  • Export the entity

Article content

  • Once the export is completed (Status: Succeeded), download the file.


  • The file should look something like this

Article content

  • Now create an import project and import this file using the same entity.

  • Once the file is uploaded, click on Import to run the import job. Do not make any changes to the file. Import it as is.

Article content

  • Once the import is successful, the Financial dimension will be active. Note that this will activate all the Financial dimensions that were inactive.

Article content