/// <summary> /// Base class for search /// </summary> class searchBaseClass { const private Integer priorityMax = 99; /// <summary> /// Method that searches for values /// </summary> protected void search(//your parmeters) { } /// <summary> /// Method that indicates the class priority and therefor the number in which it is executed /// </summary> /// <returns> /// An integer indicating the class priority and therefor the number in which it is executed /// </returns> protected Priority priority() { return searchBaseClass::PriorityMax; } /// <summary> /// Method that creates a map of search classes to be executed in a priorized way /// </summary> /// <returns> /// A map containing class objects to execute /// </returns> private Map createExecutionMap() { DictClass dictClass; searchBaseClass searchBase; ListEnumerator listEnumerator; List listClass = new DictClass(classnum(searchBaseClass)).extendedBy(); Map mapExecutionClasses = new Map(Types::Integer, Types::Class); listEnumerator = listClass.getEnumerator(); while (listEnumerator.moveNext()) { dictClass = new DictClass(listEnumerator.current()); if (dictClass) { searchBase = dictClass.makeObject(); if (searchBase) { // Add class object to execution list unless the priority is already added if (!mapExecutionClasses.exists(searchBase.priority())) { mapExecutionClasses.insert(searchBase.priority(), searchBase); } else { warning(strFmt("SearchSkipped", dictClass.name(), searchBase.priority())); } } } } return mapExecutionClasses; } /// <summary> /// Method that run through all classes that searches for data /// </summary> public void run() { searchBaseClass searchBase; Map mapExecutionClasses; mapExecutionClasses = this.createExecutionMap(); for (int i = 1; i <= searchBase::priorityMax; i++) { if (mapExecutionClasses.exists(i)) { searchBase = mapExecutionClasses.lookup(i); if (searchBase) { searchBase.search(); } } } } } /// <summary> /// child Class searching /// </summary> class searchChildClass extends searchBaseClass { /// <summary> /// Method that indicates the class priority and therefor the number in which it is executed /// </summary> /// <returns> /// An integer indicating the class priority and therefor the number in which it is executed /// </returns> protected Priority priority() { return 1; } /// <summary> /// Method searching /// </summary> protected void search(//your parmeters) { //your logic }
This blog is contains coding reference related to Microsoft AX 2012 and D365 finance and operations and Power platform
Showing posts with label Extension. Show all posts
Showing posts with label Extension. Show all posts
Tuesday, April 23, 2024
Iterate through extended child classes dynamically using X++
Monday, December 12, 2022
D365FO IDisposable context class
Scenario: pass additional parameter to a method that doesnt have a parametr signature
After the execution of using code block , Dispose method will be called. IDisposible is a singleton instance of a class per session, for example if you open two different tabs and run the code you will get two different instance of the class
class DocTypeFile_CUSTOM_Context implements System.IDisposable { static DocTypeFile_CUSTOM_Context docTypeFileContext; public boolean overrideDefaultDocType = false; public boolean printSalesInvoiceReport; public boolean printSalesConfReport; // public PrintMgmtDocumentType printMgmtDocumentType; public DocuTypeId doucTypeId = strMin(); public void new() { if(docTypeFileContext) { throw error("NestingIsNotSupported"); } docTypeFileContext = this; } public void dispose() { docTypeFileContext = null; } static public DocTypeFile_CUSTOM_Context current() { return docTypeFileContext; } }
/// <summary> /// To handle the report design to print based on caller /// </summary> [ExtensionOf(classStr(SalesInvoiceController))] final class SalesInvoiceController_CUSTOM_Extension { /// <summary> /// choose report design /// </summary> protected void outputReport() { //initalize disposible context class using (var docTypeFileContext = new DocTypeFile_CUSTOM_Context()) { SRSPrintDestinationSettings srsPrintDestinationSettings = formLetterReport.getCurrentPrintSetting().parmPrintJobSettings(); if (srsPrintDestinationSettings.printMediumType() == SRSPrintMediumType::File) { docTypeFileContext.overrideDefaultDocType = true; docTypeFileContext.doucTypeId = "File"; } next outputReport(); } } }
[ExtensionOf(tableStr(DocuType))] final class DocuType_CUSTOM_Extension { static DocuTypeId typeFile() { DocuTypeId docuTypeId; docuTypeId = next typeFile(); DocTypeFile_CUSTOM_Context docTypeFileContext = DocTypeFile_CUSTOM_Context::current(); if(docTypeFileContext && docTypeFileContext.overrideDefaultDocType) { docuTypeId = docTypeFileContext.doucTypeId; } return docuTypeId; } }
Wednesday, November 30, 2022
D365FO: Zip/Unzip memory stream to byte[] array X++
Sometimes we have to deal with big file streams, during that scenario there is an option to zip/unzip the file using gzip in X++. for example: Pass files larger than 25MB to logic apps, logic app has a file size limit of 25 MB
using System.IO; using System.IO.Compression; class ZipUnzip { public static System.Byte[] Compress(System.Byte[] data) { var compressedStream = new MemoryStream(); var zipStream = new GZipStream(compressedStream, CompressionMode::Compress); zipStream.Write(data, 0, data.Length); zipStream.Close(); return compressedStream.ToArray(); } public static System.Byte[] Decompress(System.Byte[] data) { var compressedStream = new MemoryStream(data); var zipStream = new GZipStream(compressedStream, CompressionMode::Decompress); var resultStream = new MemoryStream(); System.Byte[] buffer = new System.Byte[4096](); int read; do { read = zipStream.Read(buffer, 0, buffer.Length); resultStream.Write(buffer, 0, read); } while(read); return resultStream.ToArray(); } }
Thursday, November 24, 2022
D365FO:Cancel Purchase order through X++
Create a new class and extend standard PurchCancel class
class PurchCancel_CUSTOM extends PurchCancel { public void cancelPO(PurchTable _PurchTable) { PurchCancel_CUSTOM purchCancel = PurchCancel_CUSTOM::construct(); purchCancel.parmPurchTable(_PurchTable); // purchTable = _PurchTable; purchCancel.run(); } static PurchCancel_CUSTOM construct() { return new PurchCancel_CUSTOM(); } void new() { super(); } }
Saturday, April 24, 2021
Sysoperations frameworks Tips and tricks in AX
protected ClassDescription defaultCaption() { return "@CashManagement:CashFlowTimeSeriesInitializeControllerCaption"; } public ClassDescription caption() { return this.defaultCaption(); } /// <summary> /// Indicates if the class must run in batch or not. /// </summary> /// <returns> /// Always returns false. /// </returns> /// <remarks> /// This method must be in this class because it is called from the <c>dialogRunbase</c> class. /// </remarks> public boolean mustGoBatch() { return false; } /// <summary> /// Determines whether the job can be executed in batch. /// </summary> /// <returns> /// false if the job cannot be executed in batch; otherwise, true. /// </returns> public boolean canGoBatch() { return false; } /// <summary> /// Sets whether to show the batch tab or not. /// </summary> /// <param name = "_showBatchTab">Flag to identify whether to show the batch tab or not.</param> /// <returns>False for batch tab to be invisible</returns> public boolean showBatchTab(boolean _showBatchTab = showBatchTab) { return false; } public boolean showBatchRecurrenceButton(boolean _showBatchRecurrenceButton = showBatchRecurrenceButton) { return false; }
Monday, April 12, 2021
Register override lookup in D365fo from form datasource
/// <summary> /// Extension of the form 'SalesTable' data source 'SalesLine'. /// </summary> [ExtensionOf(formDataSourceStr(SalesTable, SalesLine))] final class Sales_SalesTableForm_SalesLineDS_Extension { /// <summary> /// COC construct to handle standard datasource init method /// </summary> /// <remarks> /// Method overriden to add custom logic /// </remarks> void init() { next init(); this.m_Init(); } /// <summary> /// COC Implementation for additional logic on init method /// </summary> void m_Init() { this.sm_ReasonCodeLookupRegisterOverride(); } /// <summary> /// SM reason code lookup override method /// </summary> public void m_ReasonCodeLookupRegisterOverride() { FormDataSource salesLineDataSource = element.dataSource(formDataSourceStr(SalesTable, SalesLine)) as FormDataSource; SM_Sales_SalesTableFormRegisterMethods formRegisterMethods = new SM_Sales_SalesTableFormRegisterMethods(); salesLineDataSource.object(fieldNum(SalesLine, SM_ReasonCode)).registerOverrideMethod(methodStr(FormDataObject, lookup), methodStr(M_Sales_SalesTableFormRegisterMethods, lookupReasoncode ), formRegisterMethods); } } /// <summary> /// Form 'SalesTable', data source 'SalesLine' register override method implementation /// </summary> class Sales_SalesTableFormRegisterMethods { /// <summary> /// Overrides <c>SM_Reasoncode</c> field lookup /// </summary> /// <param name = "_formStringControl">The control that is bound to the <c>SM_Reasoncode</c> field.</param> public void lookupReasoncode(FormStringControl _formStringControl) { FormRun formRun = _formStringControl.formRun(); SalesTable salesTableLoc = formRun.dataSource(formDataSourceStr(SalesTable, SalesTable)).cursor() as SalesTable; SalesLine::m_lookupReasoncode(_formStringControl, salesTableLoc.DlvReason); } } /// <summary> /// Overrides <c>SM_Reasoncode</c> field lookup /// </summary> /// <param name = "_formStringControl">The control that is bound to the <c>SM_Reasoncode</c> field.</param> public static void lookupReasoncode(FormStringControl _formStringControl, DlvReasonId _dlvReason) { Query query = new Query(); QueryBuildDataSource queryBuildDataSource = query.addDataSource(tableNum(ReasonTable)); queryBuildDataSource.addSelectionField(fieldnum(ReasonTable, Reason)); if (SM_CustParameters::find().ActivateReasonCode) { container conReasoncode; ReasonTable reasonTable; SM_DeliveryReasonReasonCodeCombination deliveryReasonReasonCodeCombination; while select ReasonCode from deliveryReasonReasonCodeCombination exists join reasonTable where reasonTable.Reason == deliveryReasonReasonCodeCombination.ReasonCode && deliveryReasonReasonCodeCombination.DlvReasonId == _dlvReason && reasonTable.SM_ActivateReasonCode == NoYes::Yes { conReasoncode += deliveryReasonReasonCodeCombination.ReasonCode; } str reasoncodes = conReasoncode != conNull() ? con2Str(conReasoncode) : SysQuery::valueEmptyString(); queryBuildDataSource.addRange(fieldnum(ReasonTable, Reason)).value(reasoncodes); } SysTableLookup lookup = SysTableLookup::newParameters(tablenum(ReasonTable), _formStringControl); lookup.addLookupfield(fieldnum(ReasonTable, Reason)); lookup.addLookupfield(fieldnum(ReasonTable, Description)); lookup.parmQuery(query); lookup.performFormLookup(); }
Sunday, April 11, 2021
Access public variables in extension class using chain of command
When you wrap a method, you can also access public and protected methods and variables of the base class. CustInvoiceJour is a base class variable hence you will be able to access it. Eg. [ExtensionOf(classStr(SalesConfirmJournalCreate))] Final class SalesConfirmJournalCreate_Extension { protected void createJournalHeader() { next createJournalHeader(); //It's as simple as this: custConfirmJour.SalesBalance = 0; } if gets an error, It's an old bug with variable names. Declare new one and use it: protected void createJournalHeader() { next createJournalHeader(); CustConfirmJour custConfirmJourLocal = custConfirmJour; custConfirmJourLocal.MyField = 'blah-blah'; } }
Add new fields in sysoperation dialog and get the values in controller class in AX
UIBuilder class
[ExtensionOf(classstr(ExchangeRateImportUIBuilder))] final class PDPExchangeRateImportUIBuilder_Extension { public FormBuildIntControl intCtrl; public FormBuildCheckBoxControl booleanCtrl; public void build() { next build(); DialogField dialogField; DialogField dialogFieldNoYesId; ExchangeRateImportRequest dataContract1; FormBuildCheckBoxControl exchangeRateFromPreviousDayControl; dataContract1 = this.dataContractObject(); // creating this field if standared code skips it to avoid type cast error in contoller at runtime if(exchangeRateFromPreviousDayControl == null) { dialogField = dialog.addField(extendedtypestr(ExchangeRateFromPreviousDay)); exchangeRateFromPreviousDayControl = dialogField.control(); exchangeRateFromPreviousDayControl.value(dataContract1.parmExchangeRateFromPreviousDay()); exchangeRateFromPreviousDayControl.allowEdit(false); exchangeRateFromPreviousDayControl.visible(false); } dialogField = dialog.addField(extendedtypestr(NumberOf),"integer","integer"); intCtrl = dialogField.control(); intCtrl.value(dataContract1.parmInteg()); dialogField = dialog.addField(extendedtypestr(NoYesId),"boolean","boolean"); booleanCtrl = dialogField.control(); booleanCtrl.value(dataContract1.parmNoYesId()); } }
Contract class
[ExtensionOf(ClassStr(ExchangeRateImportRequest))] [DataContractAttribute] final class PDPExchangeRateImportRequest_Extension { public int integ; public NoYesId noYesValue; /// <summary> /// data memeber attribute of Integ field /// </summary> /// <param name = "_integ">integ</param> /// <returns>int</returns> [DataMemberAttribute] public int parmInteg(int _integ = 0) { if (!_integ) { integ = _integ; } return integ; } /// <summary> /// NoyesId field /// </summary> /// <param name = "_noYesValue">NoYesValue</param> /// <returns>boolean</returns> [DataMemberAttribute] public NoYesId parmNoYesId(NoYesId _noYesValue = NoYes::No) { if (!_noYesValue) { noYesValue = _noYesValue; } return _noYesValue; } }
Controller class
[ExtensionOf(ClassStr(ExchangeRateImportController))] final class PDPExchangeRateImportController_Extension { public const str numberof = 'Fld11_1'; public const str noYesValue = 'Fld12_1'; public void getFromDialog() { next getFromDialog(); FormRun theDialogForm; ExchangeRateImportRequest exchangeRateImportRequest; ExchangeRateProviderFactory factory; FormIntControl intCtrl; FormCheckBoxControl booleanCtrl; FormCheckBoxControl exchangeRateFromPreviousDayControl; exchangeRateImportRequest = this.getDataContractObject(classStr(ExchangeRateImportRequest)); theDialogForm = this.dialog().formRun(); intCtrl = theDialogForm.control(theDialogForm.controlId(numberof)); booleanCtrl = theDialogForm.control(theDialogForm.controlId(noYesValue)); exchangeRateImportRequest.parmInteg(intCtrl.value()); exchangeRateImportRequest.parmExchangeRateTypeRecId(booleanCtrl.value()); Info(strFmt("%1--%2",intCtrl.value(), booleanCtrl.value())); } }
Subscribe to:
Posts (Atom)