Thursday, July 20, 2023

How to send SalesPackingSlip report over the email to Customer in D365FO using X++ code

Hi All,
In this blog we are going to learn about how to generate SalesPacking slip report and send it over the customers primary email address.



X++ Code.

Step 1 :Create new class.

internal final class TestPackingSlipJournalExportService
{

    SRSCatalogItemName          reportDesignLocal;
    str                         documentTitle;
    System.IO.MemoryStream      reportMemoryStream;
    SRSPrintMediumType          printMedium;
    LanguageId                  languageId;
    System.Byte[]               reportBytes;

public static TestPackingSlipJournalExportService construct(SRSPrintMediumType _printMedium)
{

        TestPackingSlipJournalExportService    service = new TestPackingSlipJournalExportService();

        service.parmPrintMedium(_printMedium);

        return service;

}

public SRSPrintMediumType parmPrintMedium(SRSPrintMediumType _printMedium = printMedium){

        printMedium = _printMedium;
        return printMedium;
 }

   /// <summary>
    /// Export packing slip journal.
    /// </summary>
    /// <param name = "_custPackingSlipJourRecId"></param>
    /// <param name = "_fileName">File name</param>
    /// <returns>Report in byte</returns>

public System.Byte[] exportPackingSlipJournal(RecId _custPackingSlipJourRecId, str _fileName)
{

        SalesPackingSlipContract    salesPackingSlipContract;
        SalesPackingSlipController  formLetterController        = SalesPackingSlipController::construct();        CustPackingSlipJour         custPackingSlipJour  = CustPackingSlipJour::findRecId(_custPackingSlipJourRecId);

        Common                      printMgmtReferencedTable;
        FormLetterReport            formLetterReport;
        PrintMgmtPrintSettingDetail printSettingDetail;
        SalesTable                  salesTable = custPackingSlipJour.salesTable();

        PrintMgmtReportFormatName   printMgmtReportFormatName   = PrintMgmtDocType::construct(PrintMgmtDocumentType::SalesOrderPackingSlip).getDefaultReportFormat();

        reportDesignLocal = printMgmtReportFormatName;

     if (!reportDesignLocal)
    {
            reportDesignLocal = ssrsReportStr(SalesPackingSlip, Report)
     }

      formLetterReport = FormLetterReport::construct(PrintMgmtDocumentType::SalesOrderPackingSlip);

        // Determine where to start looking for Print Mgmt settings
        printMgmtReferencedTable = salesTable;

        languageId = salesTable.LanguageId ? salesTable.LanguageId : custPackingSlipJour.LanguageId;

        formLetterReport.loadPrintSettings(custPackingSlipJour, printMgmtReferencedTable, custPackingSlipJour.LanguageId);

         if (formLetterReport.moveNextPrintSetting())
        {

            printSettingDetail = formLetterReport.getCurrentPrintSetting();

            formLetterReport.parmReportRun().loadSettingDetail(printSettingDetail);

        }

        formLetterReport.parmPrintType(PrintCopyOriginal::Original);
       salesPackingSlipContract = new SalesPackingSlipContract();


        salesPackingSlipContract.parmRecordId(custPackingSlipJour.RecId);
        salesPackingSlipContract.parmTableId(custPackingSlipJour.TableId);

        salesPackingSlipContract.parmDocumentTitle("@ExtendedItallianLocalization:DeliveryNote");

        this.generateReport(salesPackingSlipContract, _fileName);

        return this.getReportBytes();

    }

    private void generateReport(Object _rdpContract, str _fileName)
    {

        SrsReportRunController  srsReportRunController = new SrsReportRunController();
        srsReportRunController.parmReportName(reportDesignLocal);
        srsReportRunController.parmExecutionMode(SysOperationExecutionMode::Synchronous);
        srsReportRunController.parmShowDialog(false);
        srsReportRunController.parmReportContract().parmRdpContract(_rdpContract);

        if (languageId)
        {            srsReportRunController.parmReportContract().parmRdlContract().parmLanguageId(languageId);            srsReportRunController.parmReportContract().parmRdlContract().parmLabelLanguageId(languageId);       }

        srsReportRunController.parmReportContract().parmReportExecutionInfo(new SRSReportExecutionInfo());
       srsReportRunController.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration());

        SRSPrintDestinationSettings printerSettings = srsReportRunController.parmReportContract().parmPrintSettings();

        printerSettings.printMediumType(printMedium);
        printerSettings.fileFormat(SRSReportFileFormat::PDF);
        printerSettings.parmFileName(_fileName);
        printerSettings.overwriteFile(true);
        SRSReportRunService srsReportRunService = new SrsReportRunService();

       srsReportRunService.getReportDataContract(srsReportRunController.parmReportContract().parmReportName());

     srsReportRunService.preRunReport(srsReportRunController.parmReportContract());

        Map reportParametersMap = srsReportRunService.createParamMapFromContract(srsReportRunController.parmReportContract());

        Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[]  parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap);

        SRSProxy srsProxy = SRSProxy::constructWithConfiguration(srsReportRunController.parmReportContract().parmReportServerConfig());

           // Actual rendering to byte array
        reportBytes = srsproxy.renderReportToByteArray(srsReportRunController.parmreportcontract().parmreportpath(),                                        parameterValueArray,
                                        printerSettings.fileFormat(),
                                        printerSettings.deviceinfo());
    }

    public System.Byte[] getReportBytes()
    {
        return reportBytes;
    }

}


Step 2: Call the above created class and get the report bytes.

Step 3: Covert the report byte into stream and pass it as attachment to email.

You can get below 3 parameters like below.

1)CustPackingSlipJour = CustPackingSlipJour::findRecId(_custPackingSlipJourRecId);
2)Email = CustPackingSlipJour.salesTable().customerEmail();
3)FileName = "Test.pdf"

public static void sendPackingSlipByEmail(CustPackingSlipJour _custPackingSlipJour, Email _ToEmail, Filename _fileName)
{
       TestPackingSlipJournalExportService service = TestPackingSlipJournalExportService::construct(SRSPrintMediumType::File);

      System.Byte[] reportBytes = service.exportPackingSlipJournal(_custPackingSlipJour.RecId,_fileName);

        if (reportBytes)
        {

            SysMailerMessageBuilder messageBuilder = new SysMailerMessageBuilder();

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

                stream.Position = 0;
                messageBuilder.setBody("Packing Slip id - " + _custPackingSlipJour.PackingSlipId);
                messageBuilder.setSubject("Packing slip journal confirmation");
                messageBuilder.addTo(_ToEmail);
                messageBuilder.addAttachment(stream, _filename);
                messageBuilder.setFrom('no-reply@Test.com');

               SysMailerFactory::sendNonInteractive(messageBuilder.getMessage());

            }
            catch
            {
                exceptionTextFallThrough();
            }

        }

    }

Step 4: Result in email



If condition in computed column.

If Condition in Computed Column

If Condition in Computed Column

Hi all,

Here, we will see how to use the if condition in a computed column. In my requirement, I want to return 0 if RefType is SaftyInvent; otherwise, the value of future days from the same view.

For detailed understanding about computed columns, please check the previous blog.

TestReqTransView is a view created using the ReqTrans table.

X++ Code

private static server str compColumnDelayDays()
{
    DictView reqTransView = new DictView(tableNum(TestReqTransView));
    str reqTransDs = reqTransView.query().dataSourceTable(tableNum(ReqTrans)).name();

    return SysComputedColumn::if(
        SysComputedColumn::equalExpression(
            SysComputedColumn::comparisonField(
                dataentityviewstr(TestReqTransView),
                reqTransDs,
                fieldStr(ReqTrans, Reftype)
            ),
            SysComputedColumn::comparisonLiteral(ReqRefType::SafetyInvent)
        ),
        '0',
        SysComputedColumn::returnField(
            tableStr(TestReqTransView),
            reqTransDs,
            fieldId2name(tableNum(TestReqTransView), fieldNum(TestReqTransView, FUTURESDAYS))
        )
    );
}
    

Mark invent quantity in D365FO using X++

   

Hi All,
Below is the code to mark sales line with correspond Purch line. I used this for completing the marking for migrated purchase line.

X++ Code

 /// <summary>
 /// Mark sales line with purch line
 /// </summary>
 /// <param name = "_issueInventTransId">SalesLine inventrans Recid</param>
 /// <param name = "_receiptInventTransId">PurchLine inventtrans RecId</param>

 public static void completeInventMarking(InventTransId _issueInventTransId, InventTransId _receiptInventTransId)
    {

        InventTransId       issueInventTransId   = _issueInventTransId;
        InventTransId       receiptInventTransId = _receiptInventTransId;
        TmpInventTransMark  tmpInventTransMark;
        Map                 mapUpdated;

        InventTransOriginId receiptInventTransOriginId  =                         InventTransOrigin::findByInventTransId(receiptInventTransId).RecId;

        InventTrans         receiptInventTrans  = InventTrans::findByInventTransOrigin(receiptInventTransOriginId);

         InventTransOriginId issueInventTransOriginId    =   InventTransOrigin::findByInventTransId(issueInventTransId).RecId;

        InventTrans         issueInventTrans            =   InventTrans::findByInventTransOrigin(issueInventTransOriginId);

    InventTransMarkCollection collection = TmpInventTransMark::markingCollection(             InventTransOrigin::find(receiptInventTransOriginId),receiptInventTrans.inventDim(),         receiptInventTrans.Qty);

 collection.insertCollectionToTmpTable(tmpInventTransMark); 

 select firstonly tmpInventTransMark
            where tmpInventTransMark.InventTransOrigin == issueInventTrans.InventTransOrigin                            && tmpInventTransMark.InventDimId       == issueInventTrans.InventDimId;

 if (tmpInventTransMark.RecId != 0)
{
            Qty qtyToMark = issueInventTrans.Qty;

            tmpInventTransMark.QtyMarkNow =  qtyToMark;
            tmpInventTransMark.QtyRemain  -= tmpInventTransMark.QtyMarkNow;

            mapUpdated = new Map(Types::Int64, Types::Record);

            mapUpdated.insert(tmpInventTransMark.RecId, tmpInventTransMark);

             TmpInventTransMark::updateTmpMark(
                        receiptInventTransOriginId,
                        receiptInventTrans.inventDim(),
                        -qtyToMark,
                        mapUpdated.pack());
        }

    }

SalesPackingSlip Report and saving it as a PDF file using x++ code

Calling Sales Packing Slip Report through X++ Code

Hello Blogger Viewers,

Today, I am excited to share with you some X++ code that allows you to call the Sales Packing Slip report programmatically. This can be useful in scenarios where you need to automate the process of generating packing slip reports. Let's dive into the code!

        
SrsReportRunController ssrsController = new SrsReportRunController();
SalesPackingSlipContract salesPackingSlipContract = new SalesPackingSlipContract();
CustPackingSlipJour custPackingSlipJour;
SRSPrintDestinationSettings printerSettings;

select custPackingSlipJour where custPackingSlipJour.PackingSlipId == "200258-PAS-UK01";

// Define which report design to run.
ssrsController.parmReportName(ssrsReportStr(SalesPackingSlip, Report));

// Define how we want to execute the report (right now or batch style).
ssrsController.parmExecutionMode(SysOperationExecutionMode::Synchronous);

// Hide the report dialog.
ssrsController.parmShowDialog(false);

// Set the record and table IDs for the report contract.
salesPackingSlipContract.parmRecordId(custPackingSlipJour.RecId);
salesPackingSlipContract.parmTableId(custPackingSlipJour.TableId);

// Link the contract to the controller so we know how to run the data provider.
ssrsController.parmReportContract().parmRdpContract(salesPackingSlipContract);

// Link the printer settings to the controller.
printerSettings = ssrsController.parmReportContract().parmPrintSettings();

// Set the print medium type to HTML and always overwrite the file if it exists.
printerSettings.printMediumType(SRSPrintMediumType::File);
printerSettings.fileFormat(SRSReportFileFormat::PDF);
printerSettings.overwriteFile(true);
printerSettings.fileName(@'C:\'+'PackingListReport'+custPackingSlipJour.PackingSlipId+'.pdf');

// Start the report execution.
ssrsController.startOperation();
        
    

After executing this code, you will be able to see the generated PDF file in your "Downloads" folder. This approach provides a convenient way to automate the process of generating Sales Packing Slip reports.

I hope you find this code snippet helpful for your X++ development. If you have any questions or suggestions, feel free to leave a comment below.

Happy coding!

Post partial packing slip in D365FO

How to Post a Partial Packing Slip in D365FO and AX 2012 How to Post a Partial Packing Slip in D365FO and AX 2012 Understanding t...