Thursday, April 16, 2020

How to create Lookups through x++ in D365 FO


Lookup is one of the most commonly used  functionalities in X++ for populating the desired values from a particular master depending on the requirements given.

In this post we will be discussing about different types of Lookup.


1) Lookup without Join

            Query                                    query = new Query();
            QueryBuildDataSource        queryBuildDataSource;
            QueryBuildRange                 queryBuildRange;
            SysTableLookup                  sysTableLookup =                                                                         
            SysTableLookup::newParameters(tableNum(Table1), sender);

            sysTableLookup.addLookupField(fieldNum(Table1, Field1));
            sysTableLookup.addLookupField(fieldNum(Table1,Field2));
           
            queryBuildDataSource = query.addDataSource(tableNum(Table1));
            sysTableLookup.parmQuery(query);
            sysTableLookup.performFormLookup();


2) Lookup with Join


          Query                                      query = new Query();
          QueryBuildDataSource           qbds;
          QueryBuildDataSource           qbdsJoin;
          SysTableLookup                      sysTableLookup = sysTableLookup::newParameters(                                                                                                                       tableNum(VendTable), this);
   

         qbds= query.addDataSource( tableNum(VendTable));
         qbdsJoin= qbds.addDataSource( tableNum(DirPartyTable));
         qbdsJoin.relations( false);
         qbdsJoin.fields().dynamic(NoYes::Yes);
         qbdsJoin.addLink( fieldNum(VendTable, Party), fieldNum(DirPartyTable, RecId));
         qbdsJoin.joinMode(JoinMode::InnerJoin);

         sysTableLookup.parmQuery(query);
         sysTableLookup.addLookupfield( fieldNum(VendTable, AccountNum), true);
         sysTableLookup.addLookupfield( fieldNum(VendTable, VendGroup), true);
         sysTableLookup.addLookupfield( fieldNum(VendTable, Party));
         sysTableLookup.performFormLookup();


3) Lookup with Multiple Joins

   
    Query                   query = new Query();
    QueryBuildDataSource    qbdsPurchTable,QbdsInvntQO, qbdsInventDim;
    QueryBuildRange         qbrVendId,qbrPurchStatus,qbrPurchType;
    QueryBuildLink          qblink1, QbLink2;

    SysTableLookup  sysTableLookup = sysTableLookup::newParameters(tableNum(PurchTable),                                                                                                                                                           this);
   
    qbdsPurchTable = query.addDataSource(tableNum(PurchTable));

    QbdsInvntQO = qbdsPurchTable.addDataSource(tableNum(InventQuarantineOrder));
    QbdsInvntQO.relations(false);
    QbdsInvntQO.joinMode(JoinMode::NoExistsJoin);
    qblink1 =  QbdsInvntQO.addLink(FieldNum(PurchTable,PurchId),FieldNum(InventQuarantineOrder,TransRefId));

    qbdsInventDim = QbdsInvntQO.addDataSource(tableNum(InventDim));
    qbdsInventDim.relations(false);
    qbdsInventDim.joinMode(JoinMode::NoExistsJoin);
    QbLink2 = qbdsInventDim.addLink(FieldNum(InventQuarantineOrder,InventDimId),FieldNum(InventDim,InventDimId));

    qbdsPurchTable.addRange(fieldNum(PurchTable, OrderAccount)).value(PurchTable_InvoiceAccountGrid.valueStr());
    qbdsPurchTable.addRange(FieldNum(PurchTable, PurchStatus)).value("Invoiced,Received");
    QbdsInvntQO.addRange(fieldNum(InventQuarantineOrder, Status)).value(queryValue(InventQuarantineStatus::Ended));
    qbdsInventDim.addRange(fieldNum(InventDim, InventLocationId)).value("102018");

    sysTableLookup.addLookupfield(fieldNum(PurchTable,OrderAccount));
    sysTableLookup.addLookupfield(fieldNum(PurchTable,PurchId),true);
    sysTableLookup.addLookupfield(fieldNum(PurchTable,PurchStatus));

    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();



Happy Coding !!!

How to create and post Inventory Movement Journal through x++ in D365 FO


One of the most common requirements these days is to create Inventory Movement Journal through code. Mostly when the input is coming from another 3rd Party application.

Here is the code show below :-



       InventJournalTable              inventJournalTable;
       InventJournalTrans              inventJournalTrans;
       InventJournalNameId             inventJournalName;
       InventDim                            inventDim;
       JournalCheckPost               journalCheckPost;
     

       // Creation of Inventory Journal Header     

        inventJournalTable.clear();

        inventJournalName =                                                                                                         InventJournalName::standardJournalName(InventJournalType::Movement);
        inventJournalTable.initFromInventJournalName(InventJournalName::find(inventJournalName ));

        inventJournalTable.insert();

     

        //Creation of Inventory Journal Lines

        inventJournalTrans.clear();

        inventJournalTrans.initFromInventJournalTable(inventJournalTable);

        inventJournalTrans.TransDate = systemDateGet();

        inventJournalTrans.ItemId = “Product88987”;

        inventJournalTrans.initFromInventTable(InventTable::find(“Item0001”));

        inventJournalTrans.Qty = 11;

        inventDim.InventSiteId  = 'A1';

        inventDim.InventLocationId = 'Loc1';

        inventDim.wMSLocationId = ‘WS1’;

        inventJournalTrans.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;

        inventJournalTrans.insert();

     

        //Posting the journal

        journalCheckPost = InventJournalCheckPost::newPostJournal(inventJournalTable);
        journalCheckPost.run();





How to manually deploy SSRS reports through Powershell in D365 FO


Many times we come across situations where even the standard reports in D365 FO does not work or open properly. These scenarios might be anything an On Premi Deployment or problem in SSRS services.

In those kind of scenarios we have to deploy the reports manually like we used to do in AX 2012 Release Implementations.

So here is a very basic and simple way of achieving the same through Windows Powershell.

We simply need to follow these steps :-

1) Open run prompt and type services.msc

2) Make sure IIS , Batch , DIXF , SSRS  , MR services are running.

3) Open Windows Powershell as Administrator

4) Type the below command :-

         K:\AosService\PackagesLocalDirectory\Plugins\AxReportVmRoleStartupTask\DeployAllReportsToSSRS.ps1 -PackageInstallLocation “K:\AosService\PackagesLocalDirectory”

To Deploy specific reports type the below command :-

K:\AosService\PackagesLocalDirectory\Plugins\AxReportVmRoleStartupTask\DeployAllReportsToSSRS.ps1 -Module ApplicationSuite -ReportName AssetDep*,TaxVatRegister.Report -PackageInstallLocation “K:\AosService\PackagesLocalDirectory”


Once done the SSRS Reports will start working fine.

Please feel free to post any questions or comments!!!


Happy Coding !!



Friday, January 24, 2020

How to dynamically save PDF generated by SSRS Report for Multiple Free Text Invoices using x++ in D365 FO

Hi all ,


Most of the times we struggle when we get the requirement for extracting PDF from SSRS Report not manually but automatically as the user does not want to export the PDF one by one.

In order to save time and effort we can do this programatically as well using the below code :-


using Microsoft.Dynamics.AX.Framework.DocumentContract;

class FreeTextInvoiceEventHandler
{

    [FormControlEventHandler(formControlStr(CustFreeInvoice, BulkInvoiceSave), FormControlEventType::Clicked)]
    public static void BulkInvoiceSave_OnClicked(FormControl sender, FormControlEventArgs e)
    {
        int                                                    loop;
        str                                                    url;
        FormDataSource                             fds;
        MultiSelectionHelper                      selectionHelper = MultiSelectionHelper::construct();
        Set                                                    selectedRecords = new Set(Types::Record);
        CustPrintOutInvoice                        custPrintOutInvoice;
        NoYes                                              usePrintManagement;
        RecordSortedList                            recordSortedList;
        CustInvoiceTable                            currentCustInvoiceTable;
        SalesInvoiceJournalPrint                salesInvoiceJournalPrint;
        CustInvoiceJour                             custInvoiceJour;
        CustInvoiceTable                           currCustInvoiceTable;
        SRSPrintDestinationSettings         srsPrintDestinationSettings;
        RecordSortedList                           custInvoiceJourList;
        RecordSortedList                           rsl, rs2;
        SrsReportRunController                controller = new SrsReportRunController();
        FreeTextInvoiceContract               rdpContract = new FreeTextInvoiceContract();
        SysCorpNetPrinters                       netPrinters;
        Filename                                       _filename;

        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();

        fds = sender.formRun().dataSource('CustInvoiceTable');

        rsl = FreeTextInvoiceEventHandler::getSelectedRecords(fds);
        rs2 = FreeTextInvoiceEventHandler::getSelectedRecords(fds);

        Args args = new Args();

        select firstonly netPrinters where
        netPrinters.Active == NoYesCombo::Yes &&
            netPrinters.EnableSalesInvoiceDocumentPrint==NoYes::Yes;

        custInvoiceJourList = new RecordSortedList(tableNum(CustInvoiceJour));

        custInvoiceJourList.sortOrder(fieldNum(CustInvoiceJour, RecId));

        if (!WinAPI::pathExists("C:\\Temp\\Invoices\\"))
        {
            WinAPI::createDirectoryPath("C:\\Temp\\Invoices\\");
        }

        for (loop = rsl.len(); loop > 0; loop--)
        {
            rsl.next(currentCustInvoiceTable);

            custInvoiceJour = currentCustInvoiceTable.custInvoiceJour();

            if (custInvoiceJour.RecId)
            {
                selectedRecords.add(custInvoiceJour);

                _filename = strFmt("C:\\Temp\\Invoices\\%2 - %1.pdf"
                        ,custInvoiceJour.InvoiceId,CustTable::find(custInvoiceJour.InvoiceAccount).name());
               
                controller.parmReportName(ssrsReportStr(FreeTextInvoiceNew, Report));

                controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);

                controller.parmShowDialog(false);

                rdpContract.parmRefRecid(currentCustInvoiceTable.RecId);

                rdpContract.parmInvoiceId(currentCustInvoiceTable.InvoiceId);

                controller.parmReportContract().parmRdpContract(rdpContract);

                srsPrintDestinationSettings = controller.parmReportContract().parmPrintSettings();
                srsPrintDestinationSettings.printMediumType(SRSPrintMediumType::File);
                srsPrintDestinationSettings.fileFormat(SRSReportFileFormat::PDF);
                srsPrintDestinationSettings.fileName(_filename);
                srsPrintDestinationSettings.printerName(netPrinters.PrinterName);
                srsPrintDestinationSettings.numberOfCopies(1);
                srsPrintDestinationSettings.collate(false);
                srsPrintDestinationSettings.printAllPages(true);
                srsPrintDestinationSettings.overwriteFile(true);
                srsPrintDestinationSettings.landscape(false);
                srsPrintDestinationSettings.fromPage(0);
                srsPrintDestinationSettings.toPage(0);
                srsPrintDestinationSettings.parmSendToPrinterAsPdf(true);
                srsPrintDestinationSettings.pack();
               
               
                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,                                                                                                                              srsPrintDestinationSettings.fileFormat(SRSReportFileFormat::PDF),
                                                    srsPrintDestinationSettings.deviceinfo());

                if (reportBytes)
                {
                    System.IO.Stream            stream         = new System.IO.MemoryStream(reportBytes);

                    var fileStream = new System.IO.FileStream(_filename, System.IO.FileMode::Create,                                                                                                 System.IO.FileAccess::ReadWrite);
                    stream.CopyTo(fileStream);
                 
                    url = File::SendFileToTempStore(fileStream, _filename, classstr                                                                                                                   (FileUploadTemporaryStorageStrategy));
                    new Browser().navigate(url, true);

                }
               
            }
        }

    }

    public static  RecordSortedList getSelectedRecords(FormDataSource fds1)
    {
        RecordSortedList recordSortedList;
        CustInvoiceTable currentCustInvoiceTable;

        recordSortedList = new RecordSortedList(tableNum(CustInvoiceTable));
        recordSortedList.sortOrder(fieldNum(CustInvoiceTable,RecId));

        currentCustInvoiceTable = Global::getFirstSelection(fds1);

        while (currentCustInvoiceTable)
        {
            recordSortedList.ins(currentCustInvoiceTable);
            currentCustInvoiceTable = fds1.getNext() as CustInvoiceTable;
        }

        return recordSortedList;
    }
}

How to get financial dimension values of Customers with the help of Accounting Structure using x++ in D365 FO


Hi all ,


In my last post we used the names of financial dimensions in order to get the values from Customer Master.


In this post we will see how this can be achieved by using the name of the Accounting Structure configured to be used by the customer master.

Let's see how do we do it :-

class CalculateFinancialDimensionWActStruct
{
    public  Str1260 calculatefinancialdim(CustTable _custtable)
    {
        List                                                                                       dimensionAttributeList;
        ListEnumerator                                                                    listEnumerator;
        DimensionAttributeSetItem                                                 dimAttrSetItem;
        DimensionAttribute                                                             dimAttr;
        DimensionEnumeration                                                       dimensionSetId;
        DimensionService                                                                dimensionService;
        DimensionContract                                                              dimensionContract;
        AccountStructureContract                                                    accountStructureContract;
        Str1260                                                                                 dimvalue ;
        DefaultDimensionView                                                        defaultDimensionViewitem;

        dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

        dimensionService = new dimensionService();

        accountStructureContract = new AccountStructureContract();
        accountStructureContract.parmName("RevenueDim");

        dimensionAttributeList = dimensionService.getDimensions(accountStructureContract);
     
        listEnumerator = dimensionAttributeList.getEnumerator();

        while (listEnumerator.moveNext())
        {
            dimensionContract = listEnumerator.current();

            select dimAttr
            join RecId from dimAttrSetItem
            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&
                dimAttrSetItem.DimensionAttributeSet == dimensionSetId
                && dimAttr.Name==dimensionContract.parmDimensionName();

            select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name ==dimAttr.Name;

            if (defaultDimensionViewitem.RecId)
            {
                dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
            }
            else
            {
                dimvalue += '-' ;
            }
            defaultDimensionViewitem.clear();
         
        }
        return dimvalue;
    }

Happy Coding !!!

How to get financial dimension values of Customers without the use of Accounting Structure using x++ in D365 FO


Hi all ,


One of the most important requirements in D365 FO Projects is to get the financial dimension values and display it at various places.

In this scenario we are using the names of the specific Financial Dimensions.

Please take a look at the code written below :-


class CalculateFinancialDimension
{
 

    /// <summary>
    /// Return financial dimension values
    /// </summary>
    public  Str1260 calculatefinancialdim(CustTable _custtable)
    {
        Str1260                             dimvalue ;
        DefaultDimensionView    defaultDimensionViewitem;

        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name =='Dim1';

        if (defaultDimensionViewitem.RecId)
        {
            dimvalue += defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }

        defaultDimensionViewitem.clear() ;

        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name == 'Dim2';
        if(defaultDimensionViewitem.RecId)
        {
            dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }

        defaultDimensionViewitem.clear() ;
        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name == 'Dim3';

        if  (defaultDimensionViewitem.RecId)
        {
            dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }

        defaultDimensionViewitem.clear() ;
        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name == 'Dim4';

        if  (defaultDimensionViewitem.RecId)
        {
            dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }

        defaultDimensionViewitem.clear() ;
        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name == 'Dim5';

        if  (defaultDimensionViewitem.RecId)
        {
            dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }

        defaultDimensionViewitem.clear() ;
        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name == 'Dim6';

        if  (defaultDimensionViewitem.RecId)
        {
            dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }

        defaultDimensionViewitem.clear() ;
        select firstonly defaultDimensionViewitem
                where defaultDimensionViewitem.DefaultDimension ==  _custtable.DefaultDimension
                    && defaultDimensionViewitem.Name == 'Dim7';

        if  (defaultDimensionViewitem.RecId)
        {
            dimvalue += '-'+defaultDimensionViewitem.DisplayValue ;
        }
        else
        {
            dimvalue += '-' ;
        }
        return dimvalue ;
    }

}


Thursday, January 23, 2020

How to create a batch job for Runbase Class using x++ in D365 FO

Hi all ,

Either we can manually create the record in Batch Job Master in System Administration Module or we can create the same directly using x++.

Please view the code below written in a Runnable Class :-


    public static void main(Args _args)
    {
        BatchHeader                batHeader;
        BatchInfo                     batInfo;
        RunBaseBatch             rbbTask;
     
        str sParmCaption = "Free Text Invoice Creation Batch Job";

        rbbTask = new FreeTextInvoiceCreationBatchJob();
        batInfo = rbbTask .batchInfo();
        batInfo.parmCaption(sParmCaption);
        batInfo.parmGroupId("");
        batHeader = BatchHeader::construct();
        batHeader.addTask(rbbTask);
        batHeader.save();
        info(strFmt("%1 batch has been scheduled.", sParmCaption));
    }

    Happy Coding !!!

Importing Excel Dates in D365 F&O through X++ without the Apostrophe Trick

  We often get a requirement to create excel upload custom functionality in x++ . In this post we will see how to handle Excel OLE Automatio...