str subject = strFmt("Subject: %1 [Ref#]", AccountNum); str body = "<body><p>Dear Sir/Madam,</p><p>Please find attached.</p><p>Yours sincerely,<br>XXXX</p></body>"; if (email) { var fileDestination = ERObjectsFactory::createFileDestinationAttachmentWithOtherDocuType(CustTable); Query query = new Query(); query.addDataSource(tableNum(CustTable)) .addRange(fieldNum(CustTable, AccountNum)) .value(CustTable.AccountNum); str attachmentName = strFmt("OP-%1-%2", CustTable.AccountNum , DateTimeUtil::getSystemDateTime()); str fileName = strFmt("%1.docx",attachmentName); ERObjectsFactory::createFormatMappingRunByFormatMappingId((select ERFormatMappingTable where ERFormatMappingTable.Name == CASParameters::find().ERCorporatePreSuspensionFormatName).RecId, fileName) .withFileDestination(fileDestination) .withParameter(new ERModelDefinitionDatabaseContext() .addQuery(tableNum(CustTable), query)) .run(); EmailService_XX::sendEmailAttachment(subject, body, email, this.getAttachmentData(member,fileName), attachmentName); } else { throw error(strFmt("No primary email found for : %1", AccountNum)); } public static void sendEmailAttachment( str _subject, str _body, SysEmailAddress _emailAddr, DocuRef _docuRef, str _fileName) { SysMailerMessageBuilder mailer = new SysMailerMessageBuilder(); mailer.setSubject(_subject); mailer.setFrom(SysEmailParameters::find().SMTPUserName); mailer.setBody(_body); mailer.addTo(_emailAddr); var conversionResult = ERPdfConversionService::convertFileToPdf(DocumentManagement::getAttachmentStream(_docuRef), ".docx"); mailer.addAttachment(conversionResult.ResultStream,strFmt("%1.pdf",_fileName)); try { SysMailerFactory::sendNonInteractive(mailer.getMessage()); } catch(Exception::CLRError) { System.Exception ex = CLRInterop::getLastException(); error(ex.Message); ttsbegin; _docuRef.selectForUpdate(true); _docuRef.delete(); ttscommit; } finally { ttsbegin; _docuRef.selectForUpdate(true); _docuRef.delete(); ttscommit; } } //////////Another class using Microsoft.Dynamics365.LocalizationFramework; using TL = Microsoft.Dynamics365.LocalizationFramework.Telemetry; using BCS = Microsoft.Dynamics365.LocalizationFramework.ExternalApi.BCS; using DC = Microsoft.Dynamics365.LocalizationFramework.Services.DocumentConversion; using EA = Microsoft.Dynamics365.LocalizationFramework.ExternalApi; /// <summary> /// Class to provide access to PDF conversion process for Office documents. /// </summary> static class ERPdfConversionService { private static EA.MicrosoftInternalUseOnly.IOfficeConversionClient conversionClient; /// <summary> /// Converts given Microsoft Word or Excel file stream to PDF. /// </summary> /// <param name = "_stream">A given file stream.</param> /// <param name = "_fileExtension">A given file extension.</param> /// <param name = "_requestId">A request id to track request; optional.</param> /// <param name = "_conversionSettings">Conversion settings; optional.</param> /// <param name = "_localeIdentifier">The locale identifier.</param> /// <returns>The conversion result.</returns> [Hookable(false)] static BCS.ConvertToPdfResponse convertFileToPdf( System.IO.Stream _stream, str _fileExtension, guid _requestId = newGuid(), // ERFormatFileDestinationPdfConversionSettings _conversionSettings = null, int _localeIdentifier = 0 ) { BCS.ConvertToPdfRequest request = new BCS.ConvertToPdfRequest(); request.FileStream = _stream; request.ClientCorrelationId = _requestId; request.ClientName = identifierStr(DynamicsAxElectronicReporting); request.FileExtension = _fileExtension; request.PageOptions = null; request.LocaleIdentifier = _localeIdentifier; var conversionClient1 = CASERPdfConversionService::getClient(); return conversionClient1.ConvertToPdf(request, TL.ElectronicReportingMappingTelemetryLogger::Log); } /// <summary> /// Gets the client. /// </summary> /// <returns>Office conversion client.</returns> internal static EA.MicrosoftInternalUseOnly.IOfficeConversionClient getClient() { if (conversionClient == null) { conversionClient = EA.BCS.BcsApiClient::Instance; } return conversionClient; } /// <summary> /// Sets the client. /// </summary> /// <param name = "_conversionClient">A conversion client.</param> /// <remarks>For testing purpose.</remarks> internal static void setClient(EA.MicrosoftInternalUseOnly.IOfficeConversionClient _conversionClient) { conversionClient = _conversionClient; } } ///////
This blog is contains coding reference related to Microsoft AX 2012 and D365 finance and operations and Power platform
Thursday, October 2, 2025
Run ER Report through code and send as an Email attachment
Currency Exchange Helper
CurrencyExchangeHelper currencyExchangeHelper; CurrencyCode toCurrency = _claimLine.CurrencyClaimed; CurrencyCode FromCurrency = modifierAward.FixedAmountCurrencyCode; currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::current(), _claimLine.TreatmentDate); fixedAmt = currencyExchangeHelper.calculateCurrencyToCurrency(toCurrency, fromCurrency,modifierAward.FixedAmount,true);
Sort a Map Descending order in X++
public static Map sortbasedonRVUlevel(Map _unsortedMap, SortOrder _sortOrder = SortOrder::Descending) { // Initialize map with key=int, value=real Map sortedMap = new Map(Types::Int64, Types::Real); MapEnumerator e; container pairs = conNull(); int64 key; int counter, i, j; real valueA, valueB; container temp; // Insert test data //m.insert(1, 10); //m.insert(2, 50); //m.insert(3, 20); //m.insert(4, 80); //m.insert(5, 40); //m.insert(6, 40); // Gather all entries into the main container e = _unsortedMap.getEnumerator(); while (e.moveNext()) { key = e.current(); pairs += [[key, _unsortedMap.lookup(key)]]; } // Sort container pairs by value descending (bubble sort for demonstration) counter = conLen(pairs); for (i = 1; i < counter; i++) { for (j = i + 1; j <= counter; j++) { valueA = conPeek(conPeek(pairs, i), 2); valueB = conPeek(conPeek(pairs, j), 2); if(_sortOrder == SortOrder::Descending) { if (valueA < valueB) // For descending order { temp = conPeek(pairs, i); pairs = conPoke(pairs, i, conPeek(pairs, j)); pairs = conPoke(pairs, j, temp); } } else { if (valueA > valueB) // For ascending order { temp = conPeek(pairs, i); pairs = conPoke(pairs, i, conPeek(pairs, j)); pairs = conPoke(pairs, j, temp); } } } } // Output sorted pairs for (i = 1; i <= counter; i++) { key = conPeek(conPeek(pairs, i), 1); valueA = conPeek(conPeek(pairs, i), 2); sortedMap.add(key, valueA); info(strFmt("Key: %1, Value: %2", key, valueA)); } return sortedMap; }
Generate custom URL D365 FO
public static str generateFTILink(RecId _invoiceIdentifier, DataAreaId _dataAreaId) { //gets the generator instance var generator = new Microsoft.Dynamics.AX.Framework.Utilities.UrlHelper.UrlGenerator(); var currentHost = new System.Uri(UrlUtility::getUrl()); generator.HostUrl = currentHost.GetLeftPart(System.UriPartial::Authority); generator.Company = _dataAreaId; generator.MenuItemName = menuItemDisplayStr(CustFreeInvoiceListPage); generator.Partition = getCurrentPartition(); generator.PageType = FormViewOption::Details; var requestQueryParameterCollection = generator.RequestQueryParameterCollection; requestQueryParameterCollection.AddRequestQueryParameter( formDataSourceStr(CustFreeInvoice, CustInvoiceTable), 'RecId', int642Str(_invoiceIdentifier)); System.Uri fullURI = generator.GenerateFullUrl(); // to get the encoded URI, use the following code return fullURI.AbsoluteUri; }
Thursday, January 30, 2025
Reserve and unreserve Item using X++
public void reserveItem(ItemId _itemId,InventTransId _inventTransId, Purchline _purchline) { InventTrans inventTrans; InventTransOrigin inventTransOrigin; InventMovement inventMovement; InventUpd_Reservation inventUpd_Reservation ; InventDim inventdim; // Reserve an item select inventTrans where inventTrans.ItemId == _itemId && inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::OnOrder exists join inventTransOrigin where inventTransOrigin.RecId == inventTrans.InventTransOrigin && inventTransOrigin.InventTransId == _inventTransId && inventTrans.MarkingRefInventTransOrigin == InventTransOrigin::findByInventTransId(_purchline.InventTransId).RecId; inventdim = inventTrans.inventDim(); inventdim.inventBatchId = strFmt("%1-%2",_purchline.PurchId,_purchline.InventTransId ); inventdim = inventdim::findDim(inventdim); if(inventTrans.RecId) { Inventmovement = inventTrans.inventmovement(true); inventUpd_Reservation = InventUpd_Reservation::newInventDim(inventmovement,inventdim ? inventdim : inventTrans.inventDim(),inventTrans.Qty, false); inventUpd_Reservation.updatenow(); } } public void removeReserveItem(ItemId _itemId,InventTransId _inventTransId) { InventTrans inventTrans; InventTransOrigin inventTransOrigin; InventMovement inventMovement; InventUpd_Reservation inventUpd_Reservation ; // Remove reservations and markings on a reserved transfer order while select inventTrans where inventTrans.ItemId == _itemId && inventTrans.StatusReceipt == StatusReceipt::None && (inventTrans.StatusIssue == StatusIssue::ReservPhysical || inventTrans.StatusIssue == StatusIssue::ReservOrdered) exists join inventTransOrigin where inventTransOrigin.RecId == inventTrans.InventTransOrigin && inventTransOrigin.InventTransId == _inventTransId { if (inventTrans.StatusIssue == StatusIssue::ReservPhysical || inventTrans.StatusIssue == StatusIssue::ReservOrdered) { Inventmovement = inventTrans.inventmovement(true); inventUpd_Reservation = InventUpd_Reservation::newInventDim(inventmovement,inventTrans.inventDim(), -1 * inventTrans.Qty, false); inventUpd_Reservation.updatenow(); } } }
Trigger Sysoperation through button click
class PurchTableForm_EventHandler { /// <summary> /// run business logic for ConnectTransferOrder button /// </summary> /// <param name="sender">sender</param> /// <param name="e">e</param> [FormControlEventHandler(formControlStr(PurchTable, ConnectTransferOrder), FormControlEventType::Clicked),SuppressBPWarning('BPParameterNotUsed', 'Parameter required')] public static void ConnectTransferOrder_OnClicked(FormControl sender, FormControlEventArgs e) { FormDataSource formds = sender.formRun().dataSource(formDataSourceStr(PurchTable, PurchTable)); PurchTable purchTable = PurchTable::findRecId(formds.cursor().RecId); CreateUpdateTransferOrderController controller; SysOperationStartResult sysOperationStartResult; Args args = new Args(); args.caller(sender.formRun()); args.record(purchTable); controller = CreateUpdateTransferOrderController::newFromArgs(args); controller.parmExecutionMode(SysOperationExecutionMode::Synchronous); sysOperationStartResult = controller.startOperation(); formds.refresh(); formds.reread(); } }
Parse JSON response using X++ to vairables
str output =//JSON String; output = strRem(output, "["); output = strRem(output, "]"); Map jsonData; jsonData = RetailCommonWebAPI::getMapFromJsonString(output); container Error,Log,LinkIds,currentReponse; ListEnumerator listEnumerator,listenum; MapEnumerator mapEnumerator; mapEnumerator = jsonData.getEnumerator(); int AccNum; int Name; int Phone; int address; str errorTxt; str logTxt; str hasErrorStr; while (mapEnumerator.moveNext()) { switch (mapEnumerator.currentKey()) { case "Error": hasErrorStr = mapEnumerator.currentValue(); break; case "Log": logTxt = mapEnumerator.currentValue(); break; case "CustomerDetails"://json array currentReponse = mapEnumerator.currentValue(); if(currentReponse) { for (int i=1; i <= conlen(currentReponse); i++) { switch(conpeek(currentReponse, i)) { case "AccNum": AccNum = conPeek(currentReponse,i+1); break; case "Name": Name = conPeek(currentReponse,i+1); break; case "Phone": Phone = conPeek(currentReponse,i+1); break; case "address": address = conPeek(currentReponse,i+1); break; } } } break; } }
Sysoperation multithread using subtasks
class CustInvoiceProcessBaseService extends SysOperationServiceBase { public void process(CustInvoiceProcessContract _contract) { Query query; QueryRun queryRun; CustInvoiceJour custInvoiceJour; int defaultBundleSize = _contract.parmbundleSize(); int defaultRecordLimit = _contract.parmRecordLimit(); query = _contract.getQuery(); queryRun = new QueryRun(query); int counter = 0, lineCount = 0; BatchHeader batchHeader = this.getCurrentBatchHeader(); List customerInvoiceList = new List(Types::Int64); while (queryRun.next()) { custInvoiceJour = queryRun.get(tableNum(CustInvoiceJour)); if (batchHeader) { counter++; customerInvoiceList.addEnd(custInvoiceJour.RecId); if (counter == DefaultBundleSize) { CustInvoiceProcessSubTaskController accountResolver = CustInvoiceProcessSubTaskController::newTaskController(customerInvoiceList, strFmt("@DistITServices:BundleSize", lineCount == 0 ? 1 : lineCount, lineCount + counter)); batchHeader.addRuntimeTask(accountResolver, BatchHeader::getCurrentBatchTask().RecId); customerInvoiceList = new List(Types::Int64); lineCount = lineCount + counter; counter = 0; } if (lineCount >= DefaultRecordLimit) { break; } } else { lineCount++; CustInvoiceProcessSubTaskService::run(custInvoiceJour); } } if (batchHeader) { //To add last lines if (counter != 0 && counter <= DefaultBundleSize) { CustInvoiceProcessSubTaskController accountResolver = CustInvoiceProcessSubTaskController::newTaskController(customerInvoiceList, strFmt("@DistITServices:BundleSize",lineCount == 0 ? 1 : lineCount, lineCount + counter)); batchHeader.addRuntimeTask(accountResolver, BatchHeader::getCurrentBatchTask().RecId); customerInvoiceList = new List(Types::Int64); lineCount = lineCount + counter; counter = 0; } if (batchHeader) { batchHeader.save(); if (lineCount) { info(strFmt("%1 : %2", "@DMP1153", lineCount)); } } } else if (lineCount) { info(strFmt("%1 : %2", "@DMF:NumberOfRecordsProcessed", lineCount)); } } } /////////////////////////// [DataContractAttribute] class CustInvoiceProcessSubTaskContract extends SysOperationDataContractBase { List custInvoiceJourList = new List(Types::Int64); [ DataMemberAttribute, SysOperationControlVisibilityAttribute(false), AifCollectionTypeAttribute('return', Types::Int64) ] public List parmCustInvoiceJourList( List _custInvoiceJourList = custInvoiceJourList ) { custInvoiceJourList = _custInvoiceJourList; return custInvoiceJourList; } } ////////////////////////// class CustInvoiceProcessSubTaskController extends SysOperationServiceController { public ClassDescription defaultCaption() { return "@DistITServices:CustInvoiceProcess"; } private void new() { super(); this.parmClassName(classStr(CustInvoiceProcessSubTaskService_DIS)); this.parmMethodName(methodStr(CustInvoiceProcessSubTaskService_DIS, process)); this.parmExecutionMode(SysOperationExecutionMode::Synchronous); } public static SysOperationController newTaskController(List _list, str _taskDesc) { CustInvoiceProcessSubTaskControllercontroller = new CustInvoiceProcessSubTaskController_DIS(); CustInvoiceProcessSubTaskContract contract = controller.getDataContractObject() as CustInvoiceProcessSubTaskContract_DIS; controller.parmDialogCaption(strFmt("@DistITServices:BatchTaskDescription", _taskDesc)); contract.parmCustInvoiceJourList(_list); return controller; } [Hookable(false)] public boolean canGoBatch() { return true; } protected boolean canRunInNewSession() { return true; } [Hookable(false)] public boolean parmShowDialog(boolean _showDialog = showDialog) { return false; } [Hookable(false)] public boolean parmShowProgressForm(boolean _showProgressForm = showProgressForm) { return false; } } ////////////////////////////////////////// class CustInvoiceProcessSubTaskService extends SysOperationServiceBase { public void process(CustInvoiceProcessSubTaskContract _contract) { ListIterator custInvoiceJourListIterator = new ListIterator(_contract.parmCustInvoiceJourList()); container conCompleted, conEDIFailed, conEmailFailed, conNotSent; while (custInvoiceJourListIterator.more()) { custInvoiceJourListIterator.next(); } } public static void run(CustInvoiceJour _custInvoiceJour) { #OCCRetryCount try { } catch (Exception::Error) { throw Error("@SYS138340"); } catch (Exception::Deadlock) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::Deadlock; } else { retry; } } catch(Exception::UpdateConflict) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::UpdateConflictNotRecovered; } else { retry; } } else { throw Exception::UpdateConflict; } } } }
Subscribe to:
Posts (Atom)