D365 Sending Email with Docentric Template for SalesInvoice.Report report as attachment using X++
public final class SendEmailHelper
{
public static str CCEmail, Esender;
public static LogisticsElectronicAddressLocator GetPrimaryEmail(AccountNum ACCNum)
{
if (!ACCNum)
{
throw error("Account number cannot be null or empty.");
}
DirPartyTable dirPartyTable = DirPartyTable::findRec(CustTable::find(ACCNum).Party);
if (!dirPartyTable)
{
throw error("No party found for the provided account number.");
}
LogisticsElectronicAddress logisticsElectronicAddress;
DirPartyLocation dirLocation;
select logisticsElectronicAddress
join dirLocation
where dirLocation.Location == logisticsElectronicAddress.Location &&
logisticsElectronicAddress.IsPrimary &&
dirLocation.Party == dirPartyTable.RecId &&
logisticsElectronicAddress.Type == LogisticsElectronicAddressMethodType::Email;
if (!logisticsElectronicAddress)
{
warning("No primary email address found.");
}
return logisticsElectronicAddress.Locator;
}
public static container getEmailTemplate(SysEmailId _emailId, LanguageId _languageId)
{
// Info(_emailId);
SysEmailMessageSYSTEMTable messageTable = SysEmailMessageSYSTEMTable::find(_emailId, _languageId);
SysEmailSYSTEMTable emailTable = SysEmailSYSTEMTable::find(_emailId);
if (!messageTable && emailTable)
{
// Try to find the email message using the default language from the email parameters
messageTable = SysEmailMessageSYSTEMTable::find(_emailId, emailTable.DefaultLanguage);
}
if (messageTable)
{
//CCEmail = emailTable.EmailId;
return [messageTable.Subject, messageTable.Mail, emailTable.SenderAddr, emailTable.EmailId];
}
else
{
warning("We didn't find a template"); // Let the user know we didn't find a template
return ['', '', emailTable.SenderAddr, emailTable.SenderName, emailTable.EmailId];
}
}
public static str Email_Body(CustInvoiceJour _custinvoicejour)
{
str InvoiceId = _custinvoicejour.InvoiceId;
str salesid = _custinvoicejour.SalesId;
str invoiceDate = date2str(DateTimeUtil::date(_custinvoicejour.InvoiceDate), 123,DateDay::Digits2,DateSeparator::Slash,DateMonth::Digits2,DateSeparator::Slash,DateYear::Digits4);
str customerName = CustTable::find(_custinvoicejour.InvoiceAccount).name();
str orderDate = date2str(DateTimeUtil::date(SalesTable::find(_custinvoicejour.SalesId).CreatedDateTime), 123,DateDay::Digits2,DateSeparator::Slash,DateMonth::Digits2,DateSeparator::Slash,DateYear::Digits4);
//str trackingNumber
RetailConfigurationParameters _RetailConfigurationParameters = RetailConfigurationParameters::findByName("INVOICED_TEMPLATE_ID");
str sub,tmp,Sender,frm;
str EmailId = _RetailConfigurationParameters.Value;
[sub,tmp,Sender,frm] = SendEmailHelper::getEmailTemplate(EmailId,'en-us');
Esender = sender;
tmp = strReplace(tmp,'%salesid%','%1');
tmp = strReplace(tmp,'%invoiceId%','%2');
tmp = strReplace(tmp,'%invoiceDate%','%3');
tmp = strReplace(tmp,'%customername%','%4');
tmp = strReplace(tmp,'%orderDate%','%5');
str ret = strFmt(tmp,salesid,InvoiceId,invoiceDate,customerName ,orderDate);
return ret;
}
public static void Sendmail(CustInvoiceJour _custinvoicejour)
{
System.Exception ex;
try
{
if (!_custinvoicejour)
{
throw error("CustInvoiceJour parameter is null.");
}
str invoiceId = _custinvoicejour.InvoiceId;
str body = SendEmailHelper::Email_Body(_custinvoicejour);
str emailTo = SendEmailHelper::GetPrimaryEmail(_custinvoicejour.InvoiceAccount);
if (!emailTo)
{
throw error("No email address found for the customer.");
}
SysMailerMessageBuilder builder = new SysMailerMessageBuilder();
builder.setBody(body);
builder.setFrom(Esender);
builder.addTo(emailTo);
builder.setSubject("Your order has been invoiced - " + invoiceId);
System.IO.Stream stream = SendEmailHelper::generateReportStream(_custinvoicejour.RecId);
if (stream)
{
builder.addAttachment(stream, "Your order has been invoiced - " + invoiceId + ".pdf");
}
else
{
warning("Stream for the report attachment could not be generated.");
}
SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(builder.getMessage());
}
catch (Exception::CLRError)
{
ex = CLRInterop::getLastException();
throw error(ex.Message);
}
}
public static System.IO.MemoryStream generateReportStream(RecId invJournalRecId)
{
SalesInvoiceContract contract = new SalesInvoiceContract();
DocReportTemplate _DocReportTemplate ;
//Get Default Template to use from Docentric
select firstonly _DocReportTemplate
where _DocReportTemplate.Report == DOCREPORTTABLE::findReportId("SalesInvoice.Report").RecId
&& _DocReportTemplate.IsDefaultTemplate == NoYes::Yes;
//Get Invoice Record
CustInvoiceJour CustInvoiceJour = CustInvoiceJour::findRecId(invJournalRecId);
Filename fileName = _DocReportTemplate.TemplateId;
// Initialize the SalesInvoiceController
SrsReportRunController controller = new SrsReportRunController();
Args args = new Args();
// Attach the CustInvoiceJour record to the arguments
args.record(CustInvoiceJour);
controller.parmArgs(args);
// Set the report name
controller.parmReportName(ssrsReportStr(SalesInvoice, Report));
contract.parmRecordId(CustInvoiceJour.RecId);
controller.parmShowDialog(false);
controller.parmReportContract().parmRdpContract(contract);
// Use Docentric to generate the report
DocSrsReportGenerator docReportGenerator = new DocSrsReportGenerator(controller);
// Configure Docentric output settings directly in the generator
docReportGenerator.setPrintDestinationSettings_DocentricReport(DocOutputFileFormat::PDF, fileName);
// Generate the report as a container
container reportContainer = docReportGenerator.generateReport();
// Convert container to MemoryStream
System.IO.MemoryStream reportStream;
if (reportContainer)
{
reportStream = DocGlobalHelper::convertContainerToMemoryStream(reportContainer);
}
return reportStream;
}
}
Published on:
Learn moreRelated posts
New Feature in Dynamics 365 F&O 10.0.45 Preview: Customer Invoice Logging and Traceability Framework
Have you been posting Sales Order Invoices and Customer Free Text Invoices through batch jobs, only to struggle with tracking the status of th...
Part-10: Create your Custom Agent for D365 F&O[Chart of Account Agent]
Enough talk. Let’s see Copilot Studio in action. Over the weekend, I built something powerful – a custom AI agent for Microsoft Dynamics 365 F...
New Approved Customer List mapping for Items in Dynamics 365 Finance and operations
Take control of your sales process with the latest feature in Microsoft Dynamics 365 Finance – the Approved Customer List! This powerful new f...
Part-9: Connect and Query Dynamics 365 Finance and operations data with Copilot studio
In this video, we kick off an exciting new series focused on extending Copilot Studio capabilities by connecting it to real enterprise data! �...
How to Create Deep Links to D365 F&O Records with Dataverse Virtual Tables
It is a common requirement for SaaS platform that exposes form over data to be able to share a secure link (a.k.a. Deep Link) to access a give...
Simplifying License Management for Dynamics 365 Finance and Operations: Improved User License Validation
Starting April 30th, Dynamics 365 administrators will gain access to new license usage reporting tools, centralizing user license management. ...
D365FO Integration: Import Sales Orders from an External Web Application
Learn how to implement robust and efficient process to import complex documents into Dynamics 365 Finance and Operations from external Web ser...