Wednesday, October 27, 2021

Set Dynamic field property in Dynamic query in D365fo.

Set Dynamic field property in Dynamic query.

    Query query = new Query(); QueryBuildDataSource qbds,qbds1; QueryBuildFieldList fieldList; QueryRun queryRun; VendTable vendTable; DirPartyTable dirPartyTable; ; qbds = query.addDataSource(tableNum(VendTable)); qbds1 = qbds.addDataSource(tableNum(DirPartyTable)); qbds1.relations(True); qbds1.fields().clearFieldList(); fieldList = qbds.fields(); fieldList.addField(fieldNum(DirPartyTable, Name)); fieldList.dynamic(QueryFieldListDynamic::No); queryRun = new QueryRun(query); queryRun.prompt(); while (queryRun.next()) { vendTable = queryRun.GetNo(1); dirPartyTable = queryRun.GetNo(2); }


Keep daxing!!

Friday, October 22, 2021

Multi select lookup parameter using UI Builder class In D365fo using x++

 Today we see how to get multi-select lookup in the report dialog.  This is used to sys operation Framework also. We have to fetch selected records in dp class or service class. For this, I wrote logic in the below classes.


Contract Class :

    [ DataContractAttribute, SysOperationContractProcessingAttribute(classstr(TestUIBuilderClass)) ] class TestContractClass { List vendAccountList; [ DataMemberAttribute("Vendor"), AifCollectionTypeAttribute("Vendor", Types::String), SysOperationLabelAttribute(literalstr("Vend account")), SysOperationHelpTextAttribute(literalstr("Vend account.")), //SysOperationGroupMemberAttribute('Group'), SysOperationDisplayOrderAttribute('1') ] public List parmVendorList(List _vendAccountList = vendAccountList) { vendAccountList = _vendAccountList; return vendAccountList; } }

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

UI Builder Class:

    class TestUIBuilderClass extends SrsReportDataContractUIBuilder { TestContractClass myContractClass; DialogField dialogField; container con; public void build() { // super(); // Add group to dialog //Dialog dialogObject = this.dialog(); // dialogObject.addGroup('Group'); myContractClass = this.dataContractObject() as TestContractClass; dialogField = this.addDialogField(methodStr(TestContractClass, parmVendorList), TestContractClass); } public void postBuild() //or postRun() we can use any method. { super(); myContractClass = this.dataContractObject() as TestContractClass; dialogField = this.bindInfo().getDialogField(TestContractClass, methodStr(TestContractClass, parmVendorList)); dialogField.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(TestUIBuilderClass, VendorLookup), this); //dialogField.registerOverrideMethod(methodStr(FormStringControl, modified), methodStr(TestUIBuilderClass, Vendormodified), this); // modified method. //if (dialogField) //{ // dialogField.lookupButton(2); //} } public void VendorLookup(FormStringControl _control) { Query query = new Query(); QueryBuildDataSource vendQBD; // QueryBuildFieldList fieldList; vendQBD = query.addDataSource(tableNum(VendTable)); //qbds1 = qbds.addDataSource(tableNum(DirPartyTable)); //qbds1.relations(True); //qbds1.fields().clearFieldList(); //fieldList = qbds.fields(); //fieldList.addField(fieldNum(DirPartyTable, Name)); //fieldList.dynamic(QueryFieldListDynamic::No); vendQBD.addSelectionField(fieldNum(VendTable, AccountNum)); SysLookupMultiSelectGrid::lookup(query, _control, _control, _control, con); } }

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

DP Class

    [ SRSReportQueryAttribute (querystr(Myquery)), SRSReportParameterAttribute(classstr(TestContractClass)) ] class TestDPClass extends SRSReportDataProviderBase //SrsReportDataProviderPreProcess { MyTable myTable; List vendorList; Vendtable vendTable; [SRSReportDataSetAttribute(tableStr('MyTable'))] public MyTable getTempMyTable() { select MyTable; return MyTable; } private Query buildQuery(Query _query,List _vendorList) { ListIterator listIterator = new ListIterator(_vendorList); while(listIterator.more()) { _query.dataSourceTable(tablenum(VendTable)).addRange(fieldnum(VendTable, AccountNum)).value(queryValue(listIterator.value())); listIterator.next(); } return _query; } public void processReport() { QueryRun queryRun; TestContractClass contract = this.parmDataContract() as TestContractClass; Query query = this.parmQuery(); ; vendorList = contract.parmVendorList(); queryRun = new QueryRun(vendorList.empty() ? query : this.buildQuery(this.parmQuery(), vendorList)); while(queryRun.next()) { vendTable = queryRun.get(tablenum(VendTable)); this.insertIntoTempTable(); } } private void insertIntoTempTable() { myTable.AccountNum = vendTable.AccountNum; myTable.VendGroup = vendTable.VendGroup; myTable.insert(); } }


Keep Daxing!!

Wednesday, October 13, 2021

Settle customer Invoice through X++ in D365FO

 Settle customer Invoice through X++.         

    CustTable custTable; CustTrans invCustTrans, payCustTrans; SpecTransManager manager; CustVendTransData custVendTransData; CustVendOpenTransManager manager; CustTransOpen custTransOpen; ; custTable = CustTable::find(Accnum); // Find the oldest unsettled invoice select firstonly invCustTrans order by TransDate asc where invCustTrans.AccountNum == custTable.AccountNum && invCustTrans.TransType == LedgerTransType::Sales && !invCustTrans.closed; //!invCustTrans.LastSettleDate; // Find the oldest unsettled payment select firstonly payCustTrans order by TransDate asc where payCustTrans.AccountNum == custTable.AccountNum && payCustTrans.TransType == LedgerTransType::Payment && !payCustTrans.closed; //!payCustTrans.LastSettleDate; select firstonly custTransOpen where custTransOpen.RefRecId == payCustTrans.RecId && custTransOpen.AccountNum == payCustTrans.AccountNum; if (invCustTrans.RecId && payCustTrans.RecId && custTransOpen.RecId) { //manager = CustVendOpenTransManager::construct(ledgerJournalTrans); manager = CustVendOpenTransManager::construct(custTable); manager.updateTransMarked(custTransOpen,true); //manager.updateSettleAmount(custTransOpen, Amount); //manager.settleMarkedTrans(); ttsbegin; // Mark it for settlement custVendTransData = CustVendTransData::construct(invCustTrans); custVendTransData.markForSettlement(CustTable); custVendTransData = CustVendTransData::construct(payCustTrans); custVendTransData.markForSettlement(CustTable); // Settle all marked transactions //CustTrans::settleTransact(custTable, null, true, SettleDatePrinc::SelectDate, systemdateget()); CustTrans::settleTransact(custTable, null, true, SettleDatePrinc::DaysDate, systemdateget()); ttscommit; }

Keep Daxing!!

Tuesday, October 12, 2021

Update the vendor open trans to mark and update the amount in D365FO

 Update the vendor open trans to mark and update the amount using x++.

 

    VendTransOpen vendTransOpen; VendTrans vendTrans; SpecTransManager specTransManager; boolean check; SpecTrans specTrans; ; CustVendOpenTransManager managerLoc = CustVendOpenTransManager::construct(ledgerJournalTrans); select firstonly vendTrans where vendTrans.Invoice == ledgerJournalTrans.Invoice join firstonly vendTransOpen where vendTransOpen.RefRecId == vendTrans.RecId; specTransManager = SpecTransManager::construct(ledgerJournalTrans); check = SpecTrans::existByRef(vendTransOpen.DataAreaID,tableNum(VendTransOpen),vendTransOpen.RecId); if(!check) { managerLoc.updateTransMarked(vendTransOpen,NoYes::Yes); ttsbegin; specTrans = SpecTrans::findByRef(vendTransOpen.DataAreaID,tableNum(VendTransOpen),vendTransOpen.RecId,true); specTrans.Balance01 = -ledgerJournalTrans.AmountCurDebit; specTrans.update(); ttscommit; } else { warning(strFmt("%1 Record already marked.",ledgerJournalTrans.Invoice)); }

Keep Daxing!!

checks if the invoice is already marked with some payment or not in D365FO using X++

 checks if the invoice is already marked with some payment or not  using X++


    CustTable custTable; CustTrans payCustTrans; CustVendOpenTransManager manager; CustTransOpen custTransOpen; boolean check; ; custTable = CustTable::find(Accnum); select firstonly payCustTrans order by TransDate asc where payCustTrans.AccountNum == custTable.AccountNum && payCustTrans.TransType == LedgerTransType::Payment && !payCustTrans.closed; //!payCustTrans.LastSettleDate; select firstonly custTransOpen where custTransOpen.RefRecId == payCustTrans.RecId && custTransOpen.AccountNum == payCustTrans.AccountNum; if (payCustTrans.RecId && custTransOpen.RecId) { specTransManager specTransManager = specTransManager::construct(custTransOpen); //specTransManager manager = CustVendOpenTransManager::construct(custTable); check = specTransManager.existForOtherSpec(custTransOpen.company(), custTransOpen.TableId, custTransOpen.RecId); // Retun true or false. }


Keep Daxing!!

Auto Settle Vendor Invoice/Payment from same location In D365FO using X++.

 Hi guys, Today we see how to Auto Settle Vendor Invoice/Payment from the same location In D365FO using X++.


I have a requirement like first I have to fetch the invoice records of vendor and I have to settle that invoice with payment voucher which is from the same location. Example: INV001(from HYD) with PAY001(from Hyd). 

      VendTable VendTable;

VendTrans invVendTrans, payVendTrans; CustVendTransData custVendTransData; LedgerJournalTrans ledgerJournalTrans, payLedgerJournalTrans; CustVendOpenTransManager manager; VendTransOpen vendTransOpen; DimensionAttributeValueSetStorage invDimensionAttributeValueSetStorage ; DimensionAttribute invDimensionAttribute; DimensionValue dimensionValue; date payDate = mkDate(30,08,2021); ; #define.DimensionName("Location") // Find the oldest unsettled invoice while select invVendTrans order by TransDate asc where invVendTrans.AccountNum == VendAccount && invVendTrans.AmountMST <= 0 && //invVendTrans.TransType == LedgerTransType::Vend && invVendTrans.TransDate <= payDate && invVendTrans.TransType != LedgerTransType::Settlement && !invVendTrans.closed join ledgerJournaltrans where ledgerJournaltrans.Voucher == invVendTrans.Voucher && (ledgerJournalTrans.AccountType == LedgerJournalACType::Vend || ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Vend) { try { invDimensionAttributeValueSetStorage = dimensionAttributeValueSetStorage::find(ledgerJournaltrans.DefaultDimension); invDimensionAttribute = dimensionAttribute::findbyname(#DimensionName); dimensionValue = invDimensionAttributeValueSetStorage.getDisplayValueByDimensionAttribute(invDimensionAttribute.recId); if (!dimensionValue) { continue; } ttsBegin; VendTable = VendTable::find(invVendTrans.AccountNum); DimensionAttributeValueSetItem dimensionAttributeValueSetItem; DimensionAttributeValue dimensionAttributeValue; DimensionAttribute dimensionAttribute; // Find the oldest unsettled payment of same location while select firstonly payVendTrans order by TransDate asc where payVendTrans.AccountNum == vendTable.AccountNum && payVendTrans.AmountMST >= 0 && //payVendTrans.TransType == LedgerTransType::Payment && payVendTrans.TransDate <= payDate && payVendTrans.TransType != LedgerTransType::Settlement && !payVendTrans.closed join payLedgerJournalTrans where payLedgerJournalTrans.Voucher == payVendTrans.Voucher join dimensionAttributeValueSetItem where dimensionAttributeValueSetItem.DimensionAttributeValueSet == payLedgerJournalTrans.DefaultDimension || dimensionAttributeValueSetItem.DimensionAttributeValueSet == payLedgerJournalTrans.OffsetDefaultDimension // We can use DefaultDimension from vend Trans table also. //join dimensionAttributeValueSetItem // where dimensionAttributeValueSetItem.DimensionAttributeValueSet == payVendTrans.DefaultDimension join dimensionAttributeValue where dimensionAttributeValue.RecId == dimensionAttributeValueSetItem.DimensionAttributeValue && dimensionAttributeValue.DisplayValue == dimensionValue join dimensionAttribute where dimensionAttribute.RecId == dimensionAttributeValue.DimensionAttribute && dimensionAttribute.Name == #DimensionName join vendTransOpen where vendTransOpen.RefRecId == payVendTrans.RecId && vendTransOpen.AccountNum == payVendTrans.AccountNum { manager = custvendopentransmanager::construct(vendtable); manager.updatetransmarked(vendtransopen,true); // manager.updateSettleAmount(vendTransOpen, invVendTrans.AmountMST); // manager.settleMarkedTrans(); custVendTransData = CustVendTransData::construct(invVendTrans); custVendTransData.markForSettlement(VendTable); custVendTransData = CustVendTransData::construct(payVendTrans); custVendTransData.markForSettlement(VendTable); // Settle all marked transactions //VendTrans::settleTransact(VendTable, null, true, SettleDatePrinc::DaysDate, systemdateget()); VendTrans::settleTransact(VendTable, null, true, SettleDatePrinc::SelectDate, systemdateget()); invVendTrans.reread(); if (invVendTrans.Closed) { break; } } ttscommit; } catch (Exception::Error) { ttsAbort; continue; } catch (Exception::Deadlock) { ttsAbort; continue; } catch (Exception::Warning) { CLRInterop::getLastException(); continue; } catch (Exception::CLRError) { ttsAbort; CLRInterop::getLastException(); continue; } }

Keep daxing!!

Settle Vendor Invoice/Payment In D365FO using X++.

 To day we see how to auto settle vendor transactions using x++.

        VendTable VendTable;

VendTrans invVendTrans, payVendTrans; CustVendTransData custVendTransData; CustVendOpenTransManager manager; VendTransOpen vendTransOpen; try { ttsBegin; VendTable = VendTable::find(AccountNum); // Find the oldest unsettled invoice select firstonly invVendTrans order by TransDate asc where invVendTrans.AccountNum == VendTable.AccountNum && invVendTrans.TransType == LedgerTransType::Vend && !invVendTrans.closed; // Find the oldest unsettled payment select firstonly payVendTrans order by TransDate asc where payVendTrans.AccountNum == VendTable.AccountNum && payVendTrans.TransType == LedgerTransType::Payment && !payVendTrans.closed; select firstonly vendTransOpen where vendTransOpen.RefRecId == payVendTrans.RecId && vendTransOpen.AccountNum == payVendTrans.AccountNum; if (invVendTrans.RecId && payVendTrans.RecId && vendTransOpen.RecId) { manager = CustVendOpenTransManager::construct(VendTable); manager.updateTransMarked(vendTransOpen,true); // manager.updateSettleAmount(vendTransOpen, Amount); //manager.settleMarkedTrans(); custVendTransData = CustVendTransData::construct(invVendTrans); custVendTransData.markForSettlement(VendTable); custVendTransData = CustVendTransData::construct(payVendTrans); custVendTransData.markForSettlement(VendTable); // Settle all marked transactions //VendTrans::settleTransact(VendTable, null, true, SettleDatePrinc::DaysDate, systemdateget()); VendTrans::settleTransact(VendTable, null, true, SettleDatePrinc::SelectDate, systemdateget()); } ttscommit; } catch (Exception::Error) { ttsAbort; continue; } catch (Exception::Deadlock) { ttsAbort; continue; } catch (Exception::Warning) { CLRInterop::getLastException(); continue; } catch (Exception::CLRError) { ttsAbort; CLRInterop::getLastException(); continue; }


Keep daxing!!

Import data from excel to D365fo using x++.

 I got a requirement like I have to import vendors in to my custom table. I write the below code to cmp the reqirement.


    using System.IO; using OfficeOpenXml; using OfficeOpenXml.ExcelPackage; using OfficeOpenXml.ExcelRange; class ImportVendorsForAutoSettlement { /// <summary> /// excelimport used to import the invoice numbers. /// </summary> public void excelImport() { System.IO.Stream stream; DialogGroup dlgUploadGroup; FileUploadBuild fileUploadBuild; FormBuildControl formBuildControl; AutoSettlementVendorList autoSettlementVendorList; VendAccount vendAccount; Dialog dialog = new Dialog("ImportDataFromExcel"); ; dlgUploadGroup = dialog.addGroup("@SYS54759"); formBuildControl = dialog.formBuildDesign().control(dlgUploadGroup.name()); fileUploadBuild = formBuildControl.addControlEx(classstr(FileUpload), "Upload"); fileUploadBuild.style(FileUploadStyle::MinimalWithFilename); fileUploadBuild.fileTypesAccepted('.xlsx'); if (dialog.run() && dialog.closedOk()) { FileUpload fileUploadControl = dialog.formRun().control(dialog.formRun().controlId("Upload")); FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult(); if (fileUploadResult != null && fileUploadResult.getUploadStatus()) { stream = fileUploadResult.openResult(); using (ExcelPackage Package = new ExcelPackage(stream)) { int rowCount, i; Package.Load(stream); ExcelWorksheet worksheet = package.get_Workbook().get_Worksheets().get_Item(1); OfficeOpenXml.ExcelRange range = worksheet.Cells; rowCount = worksheet.Dimension.End.Row - worksheet.Dimension.Start.Row + 1; try { for (i = 2; i<= rowCount; i++) { ttsbegin; vendAccount = range.get_Item(i, 1).value; //supplierID = range.get_Item(i, 2).value; // transType = range.get_Item(i, 3).value; autoSettlementVendorList = AutoSettlementVendorList::find(vendAccount, true); if (!autoSettlementVendorList && vendAccount) { autoSettlementVendorList.clear(); autoSettlementVendorList.VendAccount = vendAccount; autoSettlementVendorList.insert(); } else if (autoSettlementVendorList && autoSettlementVendorList.IsProcess) { autoSettlementVendorList.IsProcess = false; autoSettlementVendorList.update(); } ttscommit; } } catch(Exception::Error) { info("Error"); } } Info("Sucessed"); } else { error("Error"); } } } }


Keep Daxing!!

Monday, October 4, 2021

Reset Number sequence using x++

Reset Number sequence using x++


    NumberSequenceTable numseqtable; ttsbegin; //numseqtable = NumberSequenceTable::find(SalesParameters::numRefMyId().NumberSequence); select forupdate numseqtable where numseqtable.Recid == //RecId value\\; if (numseqtable ) { numseqtable.NextRec = numseqtable.Lowest; numseqtable.update(); } ttscommit;


Keep daxing!!


How to recover a number sequence just used in D365Fo using X++

 Customer creating new record in table. Once he deleted the last record of table and he inserting a new record at that time he want to apply last deleted record number to newly created record.

I wrote the code in table level deleted method.

    public void delete() { NumberSequenceTable numSeqTable; MyId myId; ; myId= MyTable.MyId; numSeqTable = NumberSequenceTable::find( SalesParameters::numRefMyId().NumberSequence); super(); if (numSeqTable.Continuous) { NumberSeq::release(SalesParameters::numRefMyId().NumberSequence, myId); } else { if (NumberSeq::numInsertFormat(numSeqTable.NextRec - 1, numSeqTable.Format) == myId) { ttsbegin; numSeqTable = NumberSequenceTable::find( numSeqTable.NumberSequence, true); numSeqTable.NextRec--; numSeqTable.doUpdate(); ttscommit; } } }

Ref : https://stackoverflow.com/questions/35247361/how-to-recover-a-number-sequence-just-used
Keep daxing!!

How to roll back a number sequence in D365FO

 Today we discuss, how to roll back number sequence if any validation failed in D365FO.

If number sequence is creating without using NumberSeq class. we can use 

ttsbegin;

// our logic

ttscommit;

If any validation failed the system roll back everything.


If we creating number sequence using NumberSeq class by abort() method we can recover that number. This only works if in the same transaction scope as NumberSeq and if the number sequence is continuous. if not, both calls are no-operations.


        NumberSeq numSeq = NumberSeq::newGetNum(Parameters::numRefMyId(), true);

// NumberSeq numSeq = NumberSeq::newGetNumFromId(Table.AutoNumberSequenceTable, true); MyTable myTable; ; try { myTable.clear(); myTable.myId = numSeq.num(); if (myTable.validateWrite()) { myTable.insert(); numSeq .used(); } } catch (Exception::Error) { numSeq .abort(); }


Keep daxing!!

Create Multiple number sequence for one EDT In D365FO using X++

I got a requirement in order to create Multiple number sequence based on type for newly created purchase order in D365FO.

The similar requirement is already exists in fixed assets. Same way I followed here.


1. I created new table with 3 fields.

  •         Purch type.
  •         Description.
  •         Number sequence code.(Organization module --> Number sequences(form) --> Number sequence code(field)).
                                                




Organization module --> Number sequences(form) 
    Create new number sequence as per you requirement.


2.  Added "Purch type" field in purchase order and added relation to purch table and my table.


3. written code in below classes.

Form data source field(PurchaseType) modified method:

    [ExtensionOf(formDataFieldStr(PurchCreateOrder, PurchTable, PurchaseType))] final class PurchCreateOrderFormControl_Extension { public void modified() { FormDataObject formDataObject = any2Object(this) as FormDataObject; PurchTable purchTable = formDataObject.datasource().cursor(); NumberSeq purchaseOrderNumberSeq = element.purchaseOrderNumberSeq as NumberSeq; ; next modified(); if(purchaseOrderNumberSeq) { purchaseOrderNumberSeq.abort(); } purchaseOrderNumberSeq = purchTable.initPONumberSeq(); element.purchaseOrderNumberSeq = purchaseOrderNumberSeq; purchTable.PurchId = purchaseOrderNumberSeq ? purchaseOrderNumberSeq.num() : nullValueFromType(Types::String); purchId = purchTable.PurchId; FormDataUtil::getFormDataSource(purchTable).refresh(); } }


Purch table method:

    [ExtensionOf(tableStr(PurchTable))] final class PurchTable_Extension { public NumberSeq initPONumberSeq(PurchaseType _purchaseType = " ") { NumberSeq purchaseOrderNumberSeq = PurchaseTypeTable::getNumberSeqForType( _purchaseType ? _purchaseType : this.PurchaseType); return purchaseOrderNumberSeq; } }

PurchaseTypeTable(My table) method: 

    public class PurchaseTypeTable extends common { public static NumberSeq getNumberSeqForType(PurchaseType _purchaseType) { PurchaseTypeTable purchaseTypeTable = PurchaseTypeTable::find(_purchaseType); NumberSeq purchaseOrderSeq; PurchTable purchTable; if (purchaseTypeTable.AutoNumberSequenceTable) { purchaseOrderSeq = NumberSeq::newGetNumFromId(purchaseTypeTable.AutoNumberSequenceTable, true); } return purchaseOrderSeq; } }

Form close method:

    [ExtensionOf(formStr(PurchCreateOrder))] final class PurchCreateOrderForm_Extension { public numberseq purchaseordernumberseq; public PurchId purchId; public void close() { if (!purchtable.recid && purchaseordernumberseq) { purchaseordernumberseq.abort(); } } }

Form data source write method:

    public void write() { if (purchaseordernumberseq) { purchaseordernumberseq.onNumberUsed(purchTable.PurchId, purchId); } }

Keep daxing!!

Friday, October 1, 2021

Generate the report through code and send Email to customer using x++ in D365FO.

 Here I am generating the report through code and sending that report to cusomer using X++.


    class ConfirmSalesOrdersService extends SysOperationServiceBase { public void cnfOrdersAndSendMail() { SalesTable salesTable; SalesFormLetter salesFormLetter; CustConfirmJour custConfirmJour; while select salesTable where salesTable.DocumentStatus == DocumentStatus::None && salesTable.SalesType == SalesType::Sales && salesTable.AutoOrderCnfirm == NoYes::Yes { if(salesTable.RecId) { try { salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation); salesFormLetter.update(salesTable, DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()), SalesUpdate::All); select firstonly custConfirmJour where custConfirmJour.SalesId == salesTable.SalesId; this.getReport(custConfirmJour.RecId,salesTable.customerEmail(),salesTable.SalesId); } catch { //Error("%1",infolog.text()); this.getErrorStr(); continue; } } } } public void getReport(RecId recId,Email custEmail,SalesId salesId) { Filename fileName = strFmt("%1_%2",salesId,"ConfirmationJournal.pdf"); SrsReportRunController controller = new SrsReportRunController(); SalesConfirmContract contract = new SalesConfirmContract(); SRSPrintDestinationSettings settings; Array arrayFiles; System.Byte[] reportBytes = new System.Byte[0](); SRSProxy srsProxy; SRSReportRunService srsReportRunService = new SrsReportRunService(); Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] parameterValueArray; Map reportParametersMap; SRSReportExecutionInfo executionInfo = new SRSReportExecutionInfo(); contract.parmRecordId(recId); // Provide details to controller and add contract controller.parmArgs(new Args()); controller.parmReportName(ssrsReportStr(SalesConfirm, Report)); controller.parmShowDialog(false); controller.parmLoadFromSysLastValue(false); controller.parmReportContract().parmRdpContract(contract); // Provide printer settings settings = controller.parmReportContract().parmPrintSettings(); settings.printMediumType(SRSPrintMediumType::File); settings.fileName(fileName); settings.fileFormat(SRSReportFileFormat::PDF); // Below is a part of code responsible for rendering the report controller.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration()); controller.parmReportContract().parmReportExecutionInfo(executionInfo); srsReportRunService.getReportDataContract(controller.parmreportcontract().parmReportName()); srsReportRunService.preRunReport(controller.parmreportcontract()); reportParametersMap = srsReportRunService.createParamMapFromContract(controller.parmReportContract()); parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap); srsProxy =SRSProxy::constructWithConfiguration(controller.parmReportContract().parmReportServerConfig()); // Actual rendering to byte array reportBytes = srsproxy.renderReportToByteArray(controller.parmreportcontract().parmreportpath(), parameterValueArray, settings.fileFormat(), settings.deviceinfo()); // You can also convert the report Bytes into an xpp BinData object if needed container binData; Binary binaryData; System.IO.MemoryStream mstream = new System.IO.MemoryStream(reportBytes); binaryData = Binary::constructFromMemoryStream(mstream);              // download file             //System.IO.StreamReader sReader = new System.IO.StreamReader(stream);     //fileContent = sReader.ReadToEnd();     //File::SendStringAsFileToUser(fileContent, fileName); // System.IO.File::WriteAllBytes("C:\\backup\\"+fileName,reportBytes); // You can save the file on your local instance for verification if(binaryData) { binData = binaryData.getContainer(); } System.Byte[] binData1; System.IO.Stream stream1; // Turn the Bytes into a stream for(int i = 0; i < conLen(binData); i++) { binData1 = conPeek(binData,i+1); stream1 = new System.IO.MemoryStream(binData1); } this.sendEmail(custEmail,"Order Confirmation",stream1,salesId,fileName);//custEmail } public void sendEmail(Description _emailTo, Description _Subject,System.IO.MemoryStream stream1,SalesId _salesId,FileName _filename) { SysMailerSMTP mailer = new SysMailerSMTP(); SysMailerMessageBuilder builder = new SysMailerMessageBuilder(); SysEmailParameters parameters = SysEmailParameters::find(); Filename fileName = _filename; //you will have to setup the below parameters in sysadmin module if (parameters.SMTPRelayServerName) { mailer.SMTPRelayServer(parameters.SMTPRelayServerName, parameters.SMTPPortNumber, parameters.SMTPUserName, SysEmailParameters::password(), parameters.SMTPUseNTLM); } else { warning("SERVER NOT FOUND"); } builder.setFrom(SysEmailParameters::find().SMTPUserName); builder.addTo(_emailTo); builder.setSubject(_Subject); builder.setBody(strFmt("%1,%2","Order id:",_salesId)); if(stream1 != null) { builder.addAttachment(stream1, fileName); } SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(builder.getMessage()); } private str getErrorStr() { SysInfologEnumerator enumerator; SysInfologMessageStruct msgStruct; Exception exception; str error; ; enumerator = SysInfologEnumerator::newData(infolog.cut()); while (enumerator.moveNext()) { msgStruct = new SysInfologMessageStruct(enumerator.currentMessage()); exception = enumerator.currentException(); error = strfmt("%1 - %2", error, msgStruct.message()); } return error; } }


Keep Daxing!!

upload Image File to D365FO using X++

 I got a requirement like I have to add signature image to company and I have to populate in my custom report.

Steps:

1.Added "container field" in table.

2.Added New fast tab, buttons and Image control in form as shown below.



3. Written the code in below class. By Event handler methods I written the code.

    public class OMLegalEntityEventHandler { // Change button clicked method { FormDataSource companyInfo_ds = sender.formRun().dataSource(1) as FormDataSource; CompanyInfo companyInfo = companyInfo_ds.cursor() as CompanyInfo; str imageFilePathName; ; imageFilePathName = OMLegalEntityEventHandler::uploadImageFile(); if (imageFilePathName) { ttsbegin; companyInfo.selectForUpdate(true); companyInfo.CompanySignature = ImageReference::GetPackedBinaryData(imageFilePathName); companyInfo.update(); ttscommit; } companyInfo_ds.research(true); } //Remove button clicked method { FormDataSource companyInfo_ds = sender.formRun().dataSource(1) as FormDataSource; CompanyInfo companyInfo = companyInfo_ds.cursor() as CompanyInfo; ; ttsbegin; companyInfo.selectForUpdate(true); companyInfo.CompanySignature = conNull(); companyInfo.update(); ttscommit; companyInfo_ds.research(true); } // Data source activate method { CompanyInfo companyInfo = sender.cursor() as CompanyInfo; FormWindowControl logoImage = sender.formRun().design().controlName(formControlStr(OMLegalEntity, DashboardSignatureImage)) as FormWindowControl; Image _image; ; if (companyInfo.CompanySignature) { _image = new Image(); _image.setData(companyInfo.CompanySignature); logoImage.image(_image); } else { logoImage.image(null); } } // File upload from this method public static str uploadImageFile() { FormRun visualForm; FileUpload fileUploadControl; str imageFilePathName; ; visualForm = classFactory::formRunClassOnClient(new Args(formstr(SysGetFileFromUser))); visualForm.init(); visualForm.design().caption("@ApplicationPlatform:GetFileImageCaption"); fileUploadControl = visualForm.design().controlName('FileUpload1'); visualForm.run(); visualForm.wait(); FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult(); if (fileUploadResult != null && fileUploadResult.getUploadStatus()) { imageFilePathName = fileUploadResult.getDownloadUrl(); } return imageFilePathName; } }

Keep daxing!!

How to use form global variables in Form DS/Form control extension class in D365fo using x++.

 One Table is declared in the form 'class declaration' method (Global). I want to access that table buffer in my form control extension class(COC). For achieving that I used the below code.

     [ExtensionOf(formControlStr(MyForm, MyControl))]

public final class MyFormMyControl_Extension { public boolean modified() { // FormCheckBoxControl control = any2Object(this) as FormCheckBoxControl; // FormRun control = tax.formRun(); FormRun FormRun = salesTable_ds.Formrun(); boolean ret; MyTable myTable = element.myTable;
            // My table buffer declared in "class declaration" method.(Global) ret = next modified(); myTable.parmmethod(this.value()); //element.enableSearch(); return ret; } }


Keep daxing!!