Skip to main content

Notifications

Announcements

No record found.

Finance | Project Operations, Human Resources, ...
Suggested answer

How to email customer statement by code x++

(0) ShareShare
ReportReport
Posted on by 577

I can send email with customer statement pdf with no customer statement content. However, the content does exist by manually with the same parameters. The code is shown as below.

class AutoSendEmailInvoiceStatement extends RunBaseBatch
{
    public void run()
    {

        SysMailerMessageBuilder         mailer = new SysMailerMessageBuilder();
        SysMailerSMTP                   smtp = new SysMailerSMTP();
        str                             subject, contents, cc;
        SysEmailParameters              SysEmailParameters = SysEmailParameters::find();
        CustTable                       custTable = CustTable::find("US-001");
        str                             custEmail = custTable.InvoiceEmailAddress;
        CustAccountStatementExtContract contract = new CustAccountStatementExtContract();
        
        CustAccountStatementExtTmp      custAccountStatementExtTmp;
        
        try
        {
            if(custEmail)
            {
                mailer = new SysMailerMessageBuilder();
                mailer.setSubject("test d365 email");
                mailer.setFrom(SysEmailParameters.SMTPUserName);
                mailer.setBody(strReplace(CustParameters::find().ARStatementEmailBody, "\n", "
")); //mailer.addCc(UserInfo.networkAlias); mailer.addTo(custEmail); CustAccountStatementExtController controller = new CustAccountStatementExtController(); SRSPrintDestinationSettings settings; Filename fileName; SRSProxy srsProxy; SRSReportRunService srsReportRunService = new SrsReportRunService(); Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] parameterValueArray; Map reportParametersMap; SRSReportExecutionInfo executionInfo = new SRSReportExecutionInfo(); System.Byte[] reportBytes = new System.Byte[0](); controller.parmReportName(ssrsReportStr(CustAccountStatementExt, Report)); fileName = "CustAccountStatementExt.pdf"; controller.parmShowDialog(false); controller.parmLoadFromSysLastValue(false); // Provide printer settings settings = controller.parmReportContract().parmPrintSettings(); settings.printMediumType(SRSPrintMediumType::File); settings.fileName(fileName); settings.fileFormat(SRSReportFileFormat::PDF); // Rendering the report controller.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration()); controller.parmReportContract().parmReportExecutionInfo(executionInfo); //set parameters contract.parmFromDate(mkdate(1, mthofyr(today()), year(today()))); contract.parmToDate(today()); contract.parmOnlyOpen(true); contract.parmIncludeReversed(false); contract.parmPrintNonZero(true); contract.parmPrintPaymentSchedule(false); contract.parmPrintCreditLimit(true); contract.parmShowDNCN(custTable.ARStatementPrintDNCN); contract.parmShowNegative(custTable.ARStatementPrintNegative); contract.parmPrintAging(true); contract.parmAgingPeriod(true); contract.parmAgingBucket(CustParameters::find().ARStatementStatRepInterval); contract.parmAgingBucketPrintDescription(true); contract.parmCustAccount("US-001"); contract.parmCustAccountStatementExtTmp(custAccountStatementExtTmp.getPhysicalTableName()); controller.parmReportContract().parmRdlContract().parmLanguageId("en-us"); controller.parmReportContract().parmRdlContract().parmLabelLanguageId("en-us"); controller.parmReportContract().parmRdpContract(Contract); srsReportRunService.getReportDataContract(controller.parmReportContract().parmReportName()); // TODO 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()); if (reportBytes) { System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(reportBytes); mailer.addAttachment(memoryStream, fileName, "application/pdf"); } smtp.sendNonInteractive(mailer.getMessage()); } else { warning("No customer email"); } } catch(Exception::CLRError) { SysUserInfo SysUserInfo; str warningMsd; System.Exception netExcepn; netExcepn = CLRInterop::getLastException(); warningMsd = strFmt("Fail to send email %1. ") netExcepn.ToString(); warning(warningMsd); } } public static void main(Args _args) { AutoSendEmailInvoiceStatement instance; ; instance = new AutoSendEmailInvoiceStatement(); if (instance.prompt()) instance.run(); } }

  • Sathish_Chinnappan Profile Picture
    Sathish_Chinnappan 1,307 on at
    How to email customer statement by code x++
    Hi Tony Mok,
     
    Still I'm getting same issue mail sending with empty content. Can u send me full code.
  • Tony Mok Profile Picture
    Tony Mok 577 on at
    RE: How to email customer statement by code x++

    Hi Ludwig Reinhard,

    As the email is sent with not just customer statement, but also customer invoice, we need to code. By the way, what is standard ER customer account statement?

  • Suggested answer
    Ludwig Reinhard Profile Picture
    Ludwig Reinhard Microsoft Employee on at
    RE: How to email customer statement by code x++

    Hi Tony,

    Why don't you use the standard ER customer account statement that you can send without making a code adjustment?

    Best regards,

    Ludwig

  • Tony Mok Profile Picture
    Tony Mok 577 on at
    RE: How to email customer statement by code x++

    Thank you Judy Jee, Danilo Bambi.

    The pdf is finally generated by Print archive. The code is shown as below for reference:

    class AutoSendEmailInvoiceStatementCopy extends RunBaseBatch
    {
        public void run()
        {
            #SRSFramework
            CustAccountStatementExtContract         contract;
            CustInvoiceJour                         custInvoiceJourLocal;
            SRSPrintDestinationSettings             SRSPrintDestinationSettings;
            CustTable                               custTable = CustTable::find("US-001");
            str                                     custEmail = custTable.InvoiceEmailAddress;
            SysEmailParameters                      SysEmailParameters = SysEmailParameters::find();
            CustAccountStatementExtTmp              custAccountStatementExtTmp;
        
            CustAccountStatementExtController   controller = new CustAccountStatementExtController();
            controller.parmReportName(PrintMgmtDocType::construct(PrintMgmtDocumentType::CustAccountStatement).getDefaultReportFormat());
            str fileName = "CustAccountStatementExt.pdf";
            controller.parmShowDialog(false);
            controller.parmLoadFromSysLastValue(false);
    
            Args _args = new Args();
            _args.record(custTable);
            controller.parmArgs(_args);
        
            contract = controller.parmReportContract().parmRdpContract();
            contract.parmRecordId(custTable.RecId);  // Record id must be passed otherwise the report will be empty
    
            contract.parmFromDate(mkdate(1, mthofyr(today()), year(today())));
            contract.parmToDate(today());
            contract.parmOnlyOpen(true);
            contract.parmIncludeReversed(false);
            contract.parmPrintNonZero(true);
            contract.parmPrintPaymentSchedule(false);
            contract.parmPrintCreditLimit(true);
            contract.parmPrintAging(true);
            contract.parmAgingPeriod(true);
            contract.parmAgingBucket(CustParameters::find().ARStatementStatRepInterval);
            contract.parmAgingBucketPrintDescription(true);
    
    
            contract.parmDayMonth(DayMonth::Day);
            contract.parmManualSetup(false);
            contract.parmPrintAmountGiro(false);
            contract.parmPrintGiro(PaymentStub::None);
            contract.parmPrintingDirection(ForwardBackwardPrinting::Forward);
            contract.parmPrintType("");
            contract.parmSpecifyDueToDate(dateNull());
    
            contract.parmCustAccount("US-001");
            Query query;
            MapEnumerator enumerator;
    
            enumerator = controller.parmReportContract().parmQueryContracts().getEnumerator();
            enumerator.moveNext();
            query = enumerator.currentValue();
            query.dataSourceTable(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).value(queryValue(custTable.AccountNum));
    
            SrsReportDataContract srsReportDataContract = controller.parmReportContract();
            controller.parmReportContract(srsReportDataContract);
        
            SRSPrintDestinationSettings = new  SRSPrintDestinationSettings();
            SRSPrintDestinationSettings.overridePrintContractSettings(true);
            SRSPrintDestinationSettings.printMediumType(SRSPrintMediumType::Archive);
            SRSPrintDestinationSettings.parmOverwriteFileIsSet(true);
            SRSPrintDestinationSettings.fileFormat(SRSReportFileFormat::PDF);
    
            SRSPrintArchiveContract SRSPrintArchiveContract = new SRSPrintArchiveContract(SRSReportFileFormat::PDF);
            SRSPrintDestinationSettings.parmSRSPrintArchiveContract(SRSPrintArchiveContract);
            str archiveName = strFmt('%1-%2', curUserId(), timeNow());
            controller.parmReportContract().parmReportCaption(archiveName);//**This is the 'Description' field in the archive
        
            controller.parmReportContract().parmPrintSettings(SRSPrintDestinationSettings);
        
            controller.run();
    
            PrintJobHeader printJobHeader;
    
            select firstonly forupdate printJobHeader where printJobHeader.jobDescription == archiveName;
    
            info(strFmt("printJobHeader.RecId %1", printJobHeader.RecId));
    
            DocuRef docuRef;
    
            select firstonly forupdate docuRef where docuRef.RefRecId == PrintJobHeader.RecId;
    
            DocuValue docuValue;
            select firstonly forupdate docuValue where docuValue.RecId == docuRef.ValueRecId;
    
            info(strFmt("docuRef.RecId %1", docuRef.RecId));
            info(strFmt("docuValue.RecId %1", docuValue.RecId));
            
            System.IO.Stream stream = DocumentManagement::getAttachmentStream(docuRef);
    
            ttsbegin;
            printJobHeader.delete();
            docuRef.delete();
            docuValue.delete();
            ttscommit;
    
            
            infolog.clear();//Clear the message about archiving the report
    
            SysMailerMessageBuilder         mailer = new SysMailerMessageBuilder();
            mailer = new SysMailerMessageBuilder();
            mailer.setSubject("test d365 email..");
            mailer.setFrom(SysEmailParameters.SMTPUserName);
            mailer.setBody(strReplace(CustParameters::find().ARStatementEmailBody, "\n", "
    ")); //mailer.addCc(UserInfo.networkAlias); mailer.addTo(custEmail); if (stream != null) { mailer.addAttachment(stream, fileName, "application/pdf"); } SysMailerSMTP smtp = new SysMailerSMTP(); smtp.sendNonInteractive(mailer.getMessage()); } public static void main(Args _args) { AutoSendEmailInvoiceStatementCopy instance; ; instance = new AutoSendEmailInvoiceStatementCopy(); if (instance.prompt()) instance.run(); } }

  • Suggested answer
    greengrimms Profile Picture
    greengrimms 1,400 on at
    RE: How to email customer statement by code x++

    Hi Tony,

    Apart from what's suggested by Judy, check if the memoryStream object has any values when debugging. Also, is the pdf being attached to the email? Or are you just getting a blank pdf in your email?

    Depending on that, your issue could be on the report printing implementation or on the arguments you're sending to the addAttachment method.

  • huijij Profile Picture
    huijij 19,811 on at
    RE: How to email customer statement by code x++

    Hi Tony,

    Maybe you should turn the Bytes into a stream then call method of addAttachment():

        container binData;
            Binary binaryData;
            System.IO.MemoryStream mstream = new System.IO.MemoryStream(reportBytes);
            binaryData = Binary::constructFromMemoryStream(mstream);
            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);
            }
    
            mailer.addAttachment(stream1, fileName, "application/pdf");
    

    regards

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Congratulations 2024 Spotlight Honorees!

Kudos to all of our 2024 community stars! 🎉

Meet the Top 10 leaders for December!

Congratulations to our December super stars! 🥳

Get Started Blogging in the Community

Hosted or syndicated blogging is available! ✍️

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,661 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,379 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Product updates

Dynamics 365 release plans