i. Dataverseii. Operation resource
Search This Blog
July 16, 2024
How to Install 'Globalization Solution for Microsoft Dynamics 365 Finance' for ER reporting
February 04, 2023
QuickFix: [Solved] SSRS Report Deployment failed - The number of defined parameter is not equal to the number of cell definitions in the parameter panel
January 19, 2015
Run, Save and Email Purchase order report through X++ code
Sending SSRS Reports via Email in D365FO: Simplified Steps
Introduction
In some cases, customers may require the ability to send SSRS reports directly to their email addresses, such as Purchase Order or Sales Order reports. In this blog post, we will demonstrate how to achieve this functionality using simple and straightforward steps.
Step 1: Running the Report and Saving it Locally as PDF
To begin, create a new class and add a method that runs the report and saves it to a local or shared path. Here is an example code snippet:
public str runAndSaveSSRSReport(PurchTable _purchTable)
{
// Initialize variables
SrsReportRunController ssrsController = new SrsReportRunController();
PurchPurchaseOrderContract contract = new PurchPurchaseOrderContract();
SRSPrintDestinationSettings printerSettings;
VendPurchOrderJour vendPurchOrderJour;
str reportPath;
// Retrieve the latest purchase order for the specified PurchTable
select firstOnly vendPurchOrderJour
order by vendPurchOrderJour.createdDateTime DESC
where vendPurchOrderJour.PurchId == _purchTable.PurchId;
// Set the report path to save the PDF
reportPath = "C:\\" + _purchTable.PurchId + ".pdf";
// Configure the report controller
ssrsController.parmReportName(ssrsReportStr(PurchPurchaseOrder, Report));
ssrsController.parmExecutionMode(SysOperationExecutionMode::Synchronous);
ssrsController.parmShowDialog(false);
contract.parmRecordId(vendPurchOrderJour.RecId);
ssrsController.parmReportContract().parmRdpContract(contract);
// Link the printer settings to the controller
printerSettings = ssrsController.parmReportContract().parmPrintSettings();
printerSettings.printMediumType(SRSPrintMediumType::File);
printerSettings.fileFormat(SRSReportFileFormat::PDF);
printerSettings.overwriteFile(true);
printerSettings.fileName(@reportPath);
// Run and save the report
ssrsController.runReport();
return reportPath; // Return the file location where the PDF is saved
}
Step 2: Emailing the Report
Once the report is saved locally, you can proceed with attaching and sending it via email. Add the following method to your class:
public void POConfirmationEmail(PurchTable _purchTable)
{
// Initialize variables
PurchTable purchTable;
Map parameterMap = new Map(Types::String, Types::String);
Email requester;
SysEmailId ApprovalEmailTemplate;
SysEmailId ReopenEmailTemplate;
str companyDetails;
FilenameOpen attachmentFilename;
companyDetails = curext();
parameterMap.insert('CompanyDetails', companyDetails);
purchTable = _purchTable;
attachmentFilename = this.runAndSaveSSRSReport(purchTable);
// Set email parameters
parameterMap.insert('VendorName', VendTable::find(purchTable.OrderAccount).name());
parameterMap.insert('PurchaseID', purchTable.PurchId);
requester = LogisticsElectronicAddress::findRecId(DirPartyTable::findRec(VendTable::find(purchTable.OrderAccount).Party).PrimaryContactEmail).Locator;
if (!requester)
{
throw error("No Email address is available");
}
else
{
// Send email using the "PoEmail" template and delete the report file after sending
SysEmailTable::sendMail("PoEmail", companyinfo::languageId(), requester, parameterMap, attachmentFilename);
this.deleteReportFile(attachmentFilename);
}
}
Step 3: Deleting the Report File
Finally, add the following method to your class to delete the report file from the local drive:
public void deleteReportFile(str _reportPath)
{
str reportPath = _reportPath;
if (!reportPath)
warning("No file in local drive to remove");
else
WinAPI::deleteFile(@reportPath);
}
Conclusion
By following the above three steps, you can easily send SSRS reports via email in D365FO. Consolidating the code into a single class enhances reusability and simplifies maintenance. Feel free to leave your feedback, questions, or queries in the comments section.
Enjoy the streamlined process!
- Harry
September 02, 2014
Error while deploying SSRS report in Dynamics AX 2012 R3- An error occurred : The network path was not found. If User Account Control (UAC) is enabled on the machine, close the application, right-click the application, and then click Run as administrator.
August 31, 2014
Error While deplying SSRS report DAX 2012 R2/R3
Select BIServices port and activate it.
June 04, 2014
Debugger is not working on RDP class – SSRS report-AX 2012
March 30, 2013
How to handle SSRS reports which will take long time
How to handle SSRS reports which will take long time
We know that there are/will be some reports which will take
more time to render due to the many rows/transactions. This post will help you
to show appropriate warning/error messages to the end user while running the
report.
The number of records that are processed by report might be large and the user
experience will be affected, because the client will be locked up if printing
to the screen.
In this case, you might want to return a warning message to the user that
indicates that time to process the report might be long and confirm that they
want to run the report.
Another case could be where the number of records being processed is very large
and a time-out might occur in report processing and clearly, we should not run
this report.
In this case, we should not run the report and therefore,
should return anSrsReportPreRunState::Error enumeration value with the error
message.
In AX 2012, SSRS reports, through SrsReportRunController we can easily let the user know the
report will take more time with warnings or error messages through preRunValidate method.
Example : General Journals
report
Take the standard example of Print journal from General Ledger >> Reports
>> Journal >> Print journal.
Use standard LedgerJournalController class to help you understand preRunValidate method: this validates container
before running the report. Override this method to do custom pre-validation for
any report. Typical use of this method will be to validate if the time taken to
run the report is acceptable.
In this standard example: If the query is going to retrieve
more than 1000 rows, a confirmation Box will be displayed to the user as shown
below.
To get the confirmation box and for the sake of the demo/understanding: I have hardcoded the rows count to 1001 as shown below. There is a new static
method in QueryRun::getQueryRowCount that
will get the row Count of the query.
Please note: Remove hardcoded values
later. This is hardcoded only for the sake of demo/Walk through
Clearly in the below standard example : warning limit is
1000 and error limit is 100000.
The number of records that are processed by report might be large and the user experience will be affected, because the client will be locked up if printing to the screen.
In this case, you might want to return a warning message to the user that indicates that time to process the report might be long and confirm that they want to run the report.
Another case could be where the number of records being processed is very large and a time-out might occur in report processing and clearly, we should not run this report.
Example : General Journals report
Take the standard example of Print journal from General Ledger >> Reports >> Journal >> Print journal.
Use standard LedgerJournalController class to help you understand preRunValidate method: this validates container before running the report. Override this method to do custom pre-validation for any report. Typical use of this method will be to validate if the time taken to run the report is acceptable.
To get the confirmation box and for the sake of the demo/understanding: I have hardcoded the rows count to 1001 as shown below. There is a new static method in QueryRun::getQueryRowCount that will get the row Count of the query.
Please note: Remove hardcoded values later. This is hardcoded only for the sake of demo/Walk through
Run this report as shown below...
Note: In order to resolve/by pass this confirmation Box, a developer can change the macro #define.warningLimit to greater value
you can increase the row count : to 1000001.
Let us run the report One more time as shown below.
Example : #define.ErrorLimit(150000);
February 11, 2013
How to pass values between form and report
How to pass values between form and report
Here is for example the code of the button that calls the
report:
void clicked ()
{
Args args;
ReportRun reportRun;
;
super();
args = new Args();
args.name(Reportstr(HistoryHolidays));
args.parm( LogId );
reportRun = classfactory.reportRunClass(args);
reportRun.init();
reportRun.run();
reportRun.wait();
args.parmObject( args );
}
in the init method of your report try this:
public void init()
{
if( element.args() )
{
logId = element.args().parm();
}
super();
}
then you can use this parameter in your report form
example:
public void executeSection()
{
;
if ( employee_1.LogId == logId)
{
emplId = employee_1.empId;
super();
}
if ( logid == "1")
{
emplId = DropHoliday_1.EmpId;
super();
}
}
You can use this logic in your code for many purpose.
-Harry
void clicked ()
{
Args args;
ReportRun reportRun;
;
super();
args = new Args();
args.name(Reportstr(HistoryHolidays));
args.parm( LogId );
reportRun = classfactory.reportRunClass(args);
reportRun.init();
reportRun.run();
reportRun.wait();
args.parmObject( args );
}
in the init method of your report try this:
public void init()
{
if( element.args() )
{
logId = element.args().parm();
}
super();
}
then you can use this parameter in your report form example:
public void executeSection()
{
;
if ( employee_1.LogId == logId)
{
emplId = employee_1.empId;
super();
}
if ( logid == "1")
{
emplId = DropHoliday_1.EmpId;
super();
}
}
You can use this logic in your code for many purpose.
-Harry
January 12, 2013
How to pass values from form to report
How to pass
values from form to report
Hi Folks,
Follow below steps to understand this,
1. Make the report as Interactive
2. Create Method initFromCaller and pass the args to it.
3. Set the report caption (it will appear in dialog).