Create the SSRS Report in AX2012 using Report Data Provider (RDP) functionality.
RDP implments the standard MVC(Model View Controller) design pattern.
In this post I am building one report which is used in the production packing list report for production module.
What is MVC?
For this Report I am creating the Query,Contract,Controller,DataProvider classes in below.
In this I used lot of my custom fields that we created and used in the functionality
I am extending this functionality with adding builder class to the contract and adding the logic to lookup the data for the contract parmmethods.
for this I am writing the class which extending the SysOperationAutomaticUIBuilder.
TmpTable- ProdPackingSlipDetailsTmp
Query Name-ProdPackList
Contract class-ProdPacklistContract
Controller class-ProdPackListController Extends SRSReportRunController
Data ProvideClass-ProdPacklistDP Extends SRSReportDataProvidePreProcess
SSRS Report-ProdPackList
Starting with Query-Build the Query as the following data sources with the fields and relations.
Create the TMP table as below fields and properties of the table
define Properties of the table mainly createTransactionID=Yes
Create the Contract Class first,
This class is used to create parm methods for the reports, So if you have any parameters that you want to pass to report then create parm methods for those as datamembers.
for ex.-
[ DataMemberAttribute('UseQuantity')]
public ProdBOMJournalQty parmUseQuantity(ProdBOMJournalQty _useQuantity = useQuantity)
{
useQuantity = _useQuantity;
return useQuantity;
}
In my report I am using Query and adding two parm fields.
I am adding the contract processing through my builder with the following attribute of my contract class.
[DataContractAttribute,
SysOperationContractProcessingAttribute(classstr(ProdPackListUIBuilder)) ]
public class ProdPacklistContract
{
SalesId salesId;
LineNum lineNum
}
[ DataMemberAttribute('SalesId')]
public SalesId parmSalesId(SalesId _salesId=salesId)
{
salesId=_salesId;
return salesId;
}
[ DataMemberAttribute('LineNum')]
public LineNum parmLineNum(LineNum _lineNum=LineNum)
{
lineNum=_lineNum;
return lineNum;
}
Create Controller class which extends SrsReportRunController
/// <summary>
/// The <c>ProdPackListController</c> class is the controller class for <c>ProdPackList</c> SSRS report.
/// </summary>
public class ProdPackListController extends SrsReportRunController
{
}
Create the Main method where you have to define the reportname and design and this was the method which will calls the report to exectue...starting point of the report.
public static void main(Args _args)
{
SrsReportRunController controller = new ProdPackListController ();
controller.parmReportName("ProdPackList.Report");
controller.parmArgs(_args);
controller.startOperation();
}
Override the method preRunModifyContract method
protected void preRunModifyContract()
{
GNProdPacklistContract contract;
contract = this.parmReportContract().parmRdpContract() as GNProdPacklistContract;
}
if you want to handle the record count and no records then you can over ride this method and you can handle the no records warnings.
protected container preRunValidate()
{
// This report is only containing dynamic filters and via testing it's been determined
// that on warm box it performs under 10 seconds with a 500 records and under 10 minutes
// with 50000 records. The rest of the contract parameters just define layout and UI, so
// no additional filtering on those needs to be done in this method.
// The granularity of the query is determined by the join of ProdJournalBOM and ProdBOM tables.
#define.ErrorLimit(50000)
#define.WarningLimit(500)
container validateResult;
Query firstQuery = this.getFirstQuery();
int rowCount = QueryRun::getQueryRowCount(firstQuery, #ErrorLimit + 1);
if (rowCount > #ErrorLimit)
{
validateResult = [SrsReportPreRunState::Error];
}
else if (rowCount > #WarningLimit)
{
validateResult = [SrsReportPreRunState::Warning];
}
else if(rowCount <=0)
{
// validateResult = [SrsReportPreRunState::Error];
throw error("No records available for the Selected criteria");
}
else
{
validateResult = super();
}
return validateResult;
}
if you want to pass the values for the report before promting to user for input you can override this method
prePromptModifyContract
In my case I am overriding to pass the value and ranges for my query before showing the dialog to user.
/// <summary>
/// Sets query ranges based on the caller.
/// </summary>
/// <exception cref="M:Exception::Error">
/// The method is called from a invalid path.
/// </exception>
protected void prePromptModifyContract()
{
QueryBuildRange queryBuildRangeSerial;
QueryBuildRange queryBuildRangeProd,qbrTransStatus;
QueryBuildDataSource queryBuildDataSource,queryBuildDataSource1,queryBuildDataSource2;
ProdTable localProdTable;
Query query;
// get the report query
query = this.parmReportContract().parmQueryContracts().lookup(this.getFirstQueryContractKey());
queryBuildDataSource = SysQuery::findOrCreateDataSource(query, tableNum(ProdTable));
queryBuildDataSource1 = SysQuery::findOrCreateDataSource(query, tableNum(InventDim));
queryBuildDataSource2 = SysQuery::findOrCreateDataSource(query, tableNum(InventTrans));
queryBuildRangeProd = SysQuery::findOrCreateRange(queryBuildDataSource, fieldNum(ProdTable,ProdId));
queryBuildRangeSerial = SysQuery::findOrCreateRange(queryBuildDataSource1, fieldNum(InventDim,inventSerialId));
qbrTransStatus = SysQuery::findOrCreateRange(queryBuildDataSource2, fieldNum(InventTrans,StatusReceipt));
qbrTransStatus.value(queryValue(StatusReceipt::Received));
if (this.parmArgs().dataset() == tableNum(ProdTable))
{
localProdTable = this.parmArgs().record();
queryBuildRangeProd.value(queryValue(localProdTable.ProdId));
this.parmShowDialog(true);
}
else if ((this.parmArgs().menuItemName() == menuitemOutputStr(ProdPacklist)) && (this.parmArgs().dataset() ==0))
{
this.parmShowDialog(true);
}
else
{
throw error(strFmt("Packing list can only printed from Production",funcName()));
}
}
Create DataProvider class which extends SrsReportDataProviderPreProcess
In My report I am using the Barcode setup functionality for printing the serial numbers aswell.
{
boolean firstPage;
ProdTable prodTable;
ProdId prodId;
CompanyInfo companyInfo;
ProdBOM prodBOM;
InventDim inventDim;
ProdPackingSlipDetailsTmp prodPackingSlipDetailsTmp;
BarcodeSetup barCodeSetup;
BarcodeSetupId barcodeSetupId;
Barcode barcode;
}
Create the method which return the tmp table object
{
select prodPackingSlipDetailsTmp;
return prodPackingSlipDetailsTmp;
}
override the method ProcessReport where you will write the business logic to fill into thetmp table
ProdPacklistContract contract = this.parmDataContract() as ProdPacklistContract ;
// Set the userconnection to use on table.
// This is required to ensure that createdTransactionId of inserted record is different than default
transaction.
prodPackingSlipDetailsTmp.setConnection(this.parmUserConnection());
this.init();
this.setupBarcode();
queryRun = new QueryRun(this.parmQuery());
while (queryRun.next())
{
prodTable = queryRun.get(tableNum(ProdTable));
inventDim = queryRun.get(tableNum(InventDim));
prodId = prodTable.ProdId;
if(prodTable.InventRefType==InventRefType::Sales)
{
this.insertHeader();
this.insertDetails(prodId,inventDim.inventSerialId);
}
}
}
private void init()
{
companyInfo = CompanyInfo::find();
firstPage = true;
}
{
str jobId = strupr(_SerialNumber);
if (barcodeSetup.validateBarcode(jobId))
{
barcode.string(true, jobId);
barcode.encode();
}
else
{
throw(error(strfmt("@SYS41409", barcode.barcodeType(), jobId)));
}
return barcode.barcodeStr();
}
/// <summary>
/// Initialize barcode settings.
/// </summary>
protected void setupBarcode()
{
barcodeSetupId = JmgParameters::find().getBarcodeSetupId();
barcodeSetup = BarcodeSetup::find(barcodeSetupId);
barcode = barcodeSetup.barcode();
}
// assigns the data into header information first
private void insertHeader()
{
prodPackingSlipDetailsTmp.clear();
prodPackingSlipDetailsTmp.initValue();
prodPackingSlipDetailsTmp.SalesId=prodTable.InventRefId;
prodPackingSlipDetailsTmp.SerialNumber=inventDim.inventSerialId;
prodPackingSlipDetailsTmp.ProdItemId = prodTable.ItemId;
prodPackingSlipDetailsTmp.Description = prodTable.Name;
prodPackingSlipDetailsTmp.Customer = SalesTable::find(prodPackingSlipDetailsTmp.SalesId).CustAccount;
prodPackingSlipDetailsTmp.initValue();
prodPackingSlipDetailsTmp.barcodeSetupId=barCodeSetup.barcodeSetupId;
prodPackingSlipDetailsTmp.barcodeType=barCodeSetup.barcodeType;
prodPackingSlipDetailsTmp.fontName=barCodeSetup.fontName;
prodPackingSlipDetailsTmp.fontSize=barCodeSetup.fontSize;
prodPackingSlipDetailsTmp.maximumLength=barCodeSetup.maximumLength;
prodPackingSlipDetailsTmp.minimumLength=barCodeSetup.minimumLength;
prodPackingSlipDetailsTmp.SerialNumberBarCode=this.barcode(inventDim.inventSerialId);
}
private void insertDetails(ProdId _prodId,InventSerialId _inventSerialId)
{
SMAServiceObjectTable smaServiceObjectTable;
SMAServiceBOMTable smaServiceBOMTable;
ProdBOM prodBOMTable;
while select prodBOMTable order by InventTransId asc
where prodBOMTable.ProdId==_prodId
{
if(InventTable::Find(prodBOMTable.ItemId).PrintItemProduction)
{
prodPackingSlipDetailsTmp.ItemId=prodBOMTable.ItemId;
prodPackingSlipDetailsTmp.Qty=prodBOMTable.BOMQty;
prodPackingSlipDetailsTmp.Name=prodBOMTable.itemName();
if(prodBOMTable.SerialnoControlled())
{
select TemplateBOMId,ServiceObjectId from smaServiceObjectTable
where smaServiceObjectTable.InventSerialId==_inventSerialId
&& smaServiceObjectTable.ReferenceId==_prodId
&& smaServiceObjectTable.ReferenceCategory==InventTransType::Production
join InventSerialId from smaServiceBOMTable where
smaServiceBOMTable.ItemId==prodBOMTable.ItemId
&& smaServiceBOMTable.ObjectId==smaServiceObjectTable.ServiceObjectId
&& smaServiceBOMTable.ServiceBOMId==smaServiceObjectTable.TemplateBOMId;
prodPackingSlipDetailsTmp.SerialNo=smaServiceBOMTable.InventSerialId;
}
prodPackingSlipDetailsTmp.SalesFormNotes=FormLetterRemarks::find(companyInfo.LanguageId,FormTextType::ProductionPackingList).Txt;
prodPackingSlipDetailsTmp.insert();
prodPackingSlipDetailsTmp.SerialNo="";
}
}
}
Builder class
This was the new functionality for the adding the lookups for the fields using builder class.
After creation of all the classes above mentioned then we have to create the report,
Open .netDevelopment enviorment and create project and select Microsoft Dynamics AX from the Left pane and select the ReportModel Project from the list of project and give your project name and click ok.
select the project and right click and click add and select report.
It will create the new report as follow.Right click on report and select properties and give the name as ProdPackList.
Select DataSets and right click and click AddDataset and provide the DatasetName and select the dataset that you created and right click and properties.
click on Query it will opens the dialog with the DataProvider classes,in that select the DataProvider class that we built and click next. It will opens the fields selection window where we will select the list of fields that required to show in the report
based on your requirements you can select or deselect the fields and click on. Now the dataset with the fields are ready for the report.
Now you can drag and drop that dataset on to the designs node, It will generate auomatic design for those fields.
If you want to design your own format then create new precision Design by right click on the designnode and add precisionDesign and change that design name as we mentioned in the controller class main method(Report).
I Created the Precision design as follows.
This is how my report looks like above.
RDP implments the standard MVC(Model View Controller) design pattern.
In this post I am building one report which is used in the production packing list report for production module.
What is MVC?
- Model-view-controller (MVC) is a pattern used to isolate business logic from the user interface.
- Model: Responsible for retrieving data and for business logic, this can included queries, data methods, or other classes that are designed to retrieve data.
- View: Responsible for the User Interface, this can also be thought of as the design for the report.
- Controller: Orchestrates the flow between Model and View
For this Report I am creating the Query,Contract,Controller,DataProvider classes in below.
In this I used lot of my custom fields that we created and used in the functionality
I am extending this functionality with adding builder class to the contract and adding the logic to lookup the data for the contract parmmethods.
for this I am writing the class which extending the SysOperationAutomaticUIBuilder.
TmpTable- ProdPackingSlipDetailsTmp
Query Name-ProdPackList
Contract class-ProdPacklistContract
Controller class-ProdPackListController Extends SRSReportRunController
Data ProvideClass-ProdPacklistDP Extends SRSReportDataProvidePreProcess
SSRS Report-ProdPackList
Starting with Query-Build the Query as the following data sources with the fields and relations.
Create the TMP table as below fields and properties of the table
define Properties of the table mainly createTransactionID=Yes
Create the Contract Class first,
This class is used to create parm methods for the reports, So if you have any parameters that you want to pass to report then create parm methods for those as datamembers.
for ex.-
[ DataMemberAttribute('UseQuantity')]
public ProdBOMJournalQty parmUseQuantity(ProdBOMJournalQty _useQuantity = useQuantity)
{
useQuantity = _useQuantity;
return useQuantity;
}
In my report I am using Query and adding two parm fields.
I am adding the contract processing through my builder with the following attribute of my contract class.
[DataContractAttribute,
SysOperationContractProcessingAttribute(classstr(ProdPackListUIBuilder)) ]
public class ProdPacklistContract
{
SalesId salesId;
LineNum lineNum
}
[ DataMemberAttribute('SalesId')]
public SalesId parmSalesId(SalesId _salesId=salesId)
{
salesId=_salesId;
return salesId;
}
[ DataMemberAttribute('LineNum')]
public LineNum parmLineNum(LineNum _lineNum=LineNum)
{
lineNum=_lineNum;
return lineNum;
}
Create Controller class which extends SrsReportRunController
/// <summary>
/// The <c>ProdPackListController</c> class is the controller class for <c>ProdPackList</c> SSRS report.
/// </summary>
public class ProdPackListController extends SrsReportRunController
{
}
Create the Main method where you have to define the reportname and design and this was the method which will calls the report to exectue...starting point of the report.
public static void main(Args _args)
{
SrsReportRunController controller = new ProdPackListController ();
controller.parmReportName("ProdPackList.Report");
controller.parmArgs(_args);
controller.startOperation();
}
Override the method preRunModifyContract method
protected void preRunModifyContract()
{
GNProdPacklistContract contract;
contract = this.parmReportContract().parmRdpContract() as GNProdPacklistContract;
}
if you want to handle the record count and no records then you can over ride this method and you can handle the no records warnings.
protected container preRunValidate()
{
// This report is only containing dynamic filters and via testing it's been determined
// that on warm box it performs under 10 seconds with a 500 records and under 10 minutes
// with 50000 records. The rest of the contract parameters just define layout and UI, so
// no additional filtering on those needs to be done in this method.
// The granularity of the query is determined by the join of ProdJournalBOM and ProdBOM tables.
#define.ErrorLimit(50000)
#define.WarningLimit(500)
container validateResult;
Query firstQuery = this.getFirstQuery();
int rowCount = QueryRun::getQueryRowCount(firstQuery, #ErrorLimit + 1);
if (rowCount > #ErrorLimit)
{
validateResult = [SrsReportPreRunState::Error];
}
else if (rowCount > #WarningLimit)
{
validateResult = [SrsReportPreRunState::Warning];
}
else if(rowCount <=0)
{
// validateResult = [SrsReportPreRunState::Error];
throw error("No records available for the Selected criteria");
}
else
{
validateResult = super();
}
return validateResult;
}
if you want to pass the values for the report before promting to user for input you can override this method
prePromptModifyContract
In my case I am overriding to pass the value and ranges for my query before showing the dialog to user.
/// <summary>
/// Sets query ranges based on the caller.
/// </summary>
/// <exception cref="M:Exception::Error">
/// The method is called from a invalid path.
/// </exception>
protected void prePromptModifyContract()
{
QueryBuildRange queryBuildRangeSerial;
QueryBuildRange queryBuildRangeProd,qbrTransStatus;
QueryBuildDataSource queryBuildDataSource,queryBuildDataSource1,queryBuildDataSource2;
ProdTable localProdTable;
Query query;
// get the report query
query = this.parmReportContract().parmQueryContracts().lookup(this.getFirstQueryContractKey());
queryBuildDataSource = SysQuery::findOrCreateDataSource(query, tableNum(ProdTable));
queryBuildDataSource1 = SysQuery::findOrCreateDataSource(query, tableNum(InventDim));
queryBuildDataSource2 = SysQuery::findOrCreateDataSource(query, tableNum(InventTrans));
queryBuildRangeProd = SysQuery::findOrCreateRange(queryBuildDataSource, fieldNum(ProdTable,ProdId));
queryBuildRangeSerial = SysQuery::findOrCreateRange(queryBuildDataSource1, fieldNum(InventDim,inventSerialId));
qbrTransStatus = SysQuery::findOrCreateRange(queryBuildDataSource2, fieldNum(InventTrans,StatusReceipt));
qbrTransStatus.value(queryValue(StatusReceipt::Received));
if (this.parmArgs().dataset() == tableNum(ProdTable))
{
localProdTable = this.parmArgs().record();
queryBuildRangeProd.value(queryValue(localProdTable.ProdId));
this.parmShowDialog(true);
}
else if ((this.parmArgs().menuItemName() == menuitemOutputStr(ProdPacklist)) && (this.parmArgs().dataset() ==0))
{
this.parmShowDialog(true);
}
else
{
throw error(strFmt("Packing list can only printed from Production",funcName()));
}
}
Create DataProvider class which extends SrsReportDataProviderPreProcess
In My report I am using the Barcode setup functionality for printing the serial numbers aswell.
[
SRSReportQueryAttribute(queryStr(ProdPackList)),
SRSReportParameterAttribute(classStr(ProdPacklistContract))
]
class ProdPacklistDP extends SrsReportDataProviderPreProcess{
boolean showQuery;
boolean firstPage;
ProdTable prodTable;
ProdId prodId;
CompanyInfo companyInfo;
ProdBOM prodBOM;
InventDim inventDim;
ProdPackingSlipDetailsTmp prodPackingSlipDetailsTmp;
BarcodeSetup barCodeSetup;
BarcodeSetupId barcodeSetupId;
Barcode barcode;
}
Create the method which return the tmp table object
[
SRSReportDataSetAttribute(tableStr('ProdPackingSlipDetailsTmp'))
]
public ProdPackingSlipDetailsTmp getProdPacklistDetailsTmp(){
select prodPackingSlipDetailsTmp;
return prodPackingSlipDetailsTmp;
}
override the method ProcessReport where you will write the business logic to fill into thetmp table
/// <summary>
/// Processes the report business logic.
/// </summary>
/// <remarks>
/// Calls the sub methods to insert data into the temporary table.
/// </remarks>
[SysEntryPointAttribute(false)]
public void processReport()
{
QueryRun queryRun;ProdPacklistContract contract = this.parmDataContract() as ProdPacklistContract ;
// Set the userconnection to use on table.
// This is required to ensure that createdTransactionId of inserted record is different than default
transaction.
prodPackingSlipDetailsTmp.setConnection(this.parmUserConnection());
this.init();
this.setupBarcode();
queryRun = new QueryRun(this.parmQuery());
while (queryRun.next())
{
prodTable = queryRun.get(tableNum(ProdTable));
inventDim = queryRun.get(tableNum(InventDim));
prodId = prodTable.ProdId;
if(prodTable.InventRefType==InventRefType::Sales)
{
this.insertHeader();
this.insertDetails(prodId,inventDim.inventSerialId);
}
}
}
private void init()
{
companyInfo = CompanyInfo::find();
firstPage = true;
}
//BP Deviation documented
protected BarCodeString barcode(str _SerialNumber){
str jobId = strupr(_SerialNumber);
if (barcodeSetup.validateBarcode(jobId))
{
barcode.string(true, jobId);
barcode.encode();
}
else
{
throw(error(strfmt("@SYS41409", barcode.barcodeType(), jobId)));
}
return barcode.barcodeStr();
}
/// <summary>
/// Initialize barcode settings.
/// </summary>
protected void setupBarcode()
{
barcodeSetupId = JmgParameters::find().getBarcodeSetupId();
barcodeSetup = BarcodeSetup::find(barcodeSetupId);
barcode = barcodeSetup.barcode();
}
// assigns the data into header information first
private void insertHeader()
{
prodPackingSlipDetailsTmp.clear();
prodPackingSlipDetailsTmp.initValue();
prodPackingSlipDetailsTmp.SalesId=prodTable.InventRefId;
prodPackingSlipDetailsTmp.SerialNumber=inventDim.inventSerialId;
prodPackingSlipDetailsTmp.ProdItemId = prodTable.ItemId;
prodPackingSlipDetailsTmp.Description = prodTable.Name;
prodPackingSlipDetailsTmp.Customer = SalesTable::find(prodPackingSlipDetailsTmp.SalesId).CustAccount;
prodPackingSlipDetailsTmp.initValue();
prodPackingSlipDetailsTmp.barcodeSetupId=barCodeSetup.barcodeSetupId;
prodPackingSlipDetailsTmp.barcodeType=barCodeSetup.barcodeType;
prodPackingSlipDetailsTmp.fontName=barCodeSetup.fontName;
prodPackingSlipDetailsTmp.fontSize=barCodeSetup.fontSize;
prodPackingSlipDetailsTmp.maximumLength=barCodeSetup.maximumLength;
prodPackingSlipDetailsTmp.minimumLength=barCodeSetup.minimumLength;
prodPackingSlipDetailsTmp.SerialNumberBarCode=this.barcode(inventDim.inventSerialId);
}
private void insertDetails(ProdId _prodId,InventSerialId _inventSerialId)
{
SMAServiceObjectTable smaServiceObjectTable;
SMAServiceBOMTable smaServiceBOMTable;
ProdBOM prodBOMTable;
while select prodBOMTable order by InventTransId asc
where prodBOMTable.ProdId==_prodId
{
if(InventTable::Find(prodBOMTable.ItemId).PrintItemProduction)
{
prodPackingSlipDetailsTmp.ItemId=prodBOMTable.ItemId;
prodPackingSlipDetailsTmp.Qty=prodBOMTable.BOMQty;
prodPackingSlipDetailsTmp.Name=prodBOMTable.itemName();
if(prodBOMTable.SerialnoControlled())
{
select TemplateBOMId,ServiceObjectId from smaServiceObjectTable
where smaServiceObjectTable.InventSerialId==_inventSerialId
&& smaServiceObjectTable.ReferenceId==_prodId
&& smaServiceObjectTable.ReferenceCategory==InventTransType::Production
join InventSerialId from smaServiceBOMTable where
smaServiceBOMTable.ItemId==prodBOMTable.ItemId
&& smaServiceBOMTable.ObjectId==smaServiceObjectTable.ServiceObjectId
&& smaServiceBOMTable.ServiceBOMId==smaServiceObjectTable.TemplateBOMId;
prodPackingSlipDetailsTmp.SerialNo=smaServiceBOMTable.InventSerialId;
}
prodPackingSlipDetailsTmp.SalesFormNotes=FormLetterRemarks::find(companyInfo.LanguageId,FormTextType::ProductionPackingList).Txt;
prodPackingSlipDetailsTmp.insert();
prodPackingSlipDetailsTmp.SerialNo="";
}
}
}
Builder class
public class ProdPackListUIBuilder
extends SysOperationAutomaticUIBuilder
{
DialogField dialogSalesId;
DialogField dialogSalesLine;
SalesId
salesId;
LineNum lineNum;
ProdPacklistContract prodPacklistContract;
ProdPackListController packListcontroller;
QueryRun queryRun;
Query baseQuery;
ProdTable prodTable;
}
public void
build()
{
FormBuildGroupControl grp;
Dialog
dialogLocal = this.dialog();
;
prodPacklistContract =
this.dataContractObject();
if(this.validateCaller())
{
dialogLocal.addGroup("Sales");
this.addDialogField(methodStr(ProdPacklistContract,parmSalesId),
prodPacklistContract);
this.addDialogField(methodStr(ProdPacklistContract,parmSalesLine),
prodPacklistContract);
}
}
public
SysOperationController controller()
{
SysOperationController ret;
ret = super();
packListcontroller=ret;
return ret;
}
private str
getFirstQuery()
{
// this will just return the first
contract key in the Map
Map queryContracts =packListcontroller.parmReportContract().parmQueryContracts();
MapEnumerator mapEnum;
str firstQueryKey;
if(queryContracts)
{
mapEnum =
queryContracts.getEnumerator();
if(mapEnum.moveNext())
{
firstQueryKey =
mapEnum.currentKey();
}
}
return firstQueryKey;
}
public void
getFromDialog()
{
prodPacklistContract =
this.dataContractObject();
if(this.validateCaller())
{
salesId=dialogSalesId.value();
LineNum=dialogSalesLine.value();
this.validateData(salesId,LineNum);
}
super();
}
public void
initializeFields()
{
prodPacklistContract = this.dataContractObject();
}
private void
initquery()
{
baseQuery=packListcontroller.parmReportContract().parmQueryContracts().lookup(this.getFirstQuery());
QueryRun=new QueryRun(baseQuery);
while (queryRun.next())
{
prodTable=queryRun.get(tableNum(ProdTable));
if(prodTable)
break;
}
}
public void
lookupSalesId(FormStringControl _control)
{
Query query = new Query();
SysTableLookup sysTablelookup;
sysTablelookup
=SysTableLookup::newParameters(tableNum(SalesTable),_control);
sysTablelookup.addLookupfield(fieldNum(SalesTable,SalesId));
sysTablelookup.addLookupfield(fieldnum(SalesTable,CustAccount));
sysTablelookup.addLookupMethod(tableMethodStr(SalesTable,customerName));
query.addDataSource(tableNum(SalesTable));
if(ProdTable.InventRefType==InventRefType::Sales)
{
query.dataSourceTable(tableNum(SalesTable)).addRange(fieldNum(SalesTable,
SalesId)).value(queryValue(ProdTable.InventRefId));
}
sysTablelookup.parmQuery(query);
sysTablelookup.performFormLookup();
}
public void
lookupSalesLine(FormStringControl _control)
{
Query query = new Query();
SysTableLookup sysTablelookup;
sysTablelookup
=SysTableLookup::newParameters(tableNum(SalesLine),_control);
sysTablelookup.addLookupfield(fieldnum(SalesLine,LineNum));
sysTablelookup.addLookupfield(fieldnum(SalesLine,Itemid));
sysTablelookup.addLookupfield(fieldNum(SalesLine,SalesId));
query.addDataSource(tableNum(SalesLine));
query.dataSourceTable(tableNum(SalesLine)).addRange(fieldNum(SalesLine,
SalesId)).value(dialogSalesId.value());
query.dataSourceTable(tableNum(SalesLine)).addRange(fieldNum(SalesLine,
ItemId)).value(queryValue(prodTable.ItemId));
if(prodTable.InventRefType==InventRefType::Sales)
{
query.dataSourceTable(tableNum(SalesLine)).addRange(fieldNum(SalesLine,
InventtransId)).value(queryValue(prodTable.InventRefTransId));
}
sysTablelookup.parmQuery(query);
sysTablelookup.performFormLookup();
}
//Override the postbuild function to bind the lookups for the fields.
public void
postBuild()
{
super();
if(this.validateCaller())
{
prodPacklistContract=this.dataContractObject();
this.initquery();
// From binding info, get the dialog
field for racecode attribute and add button
dialogSalesId =
this.bindInfo().getDialogField(
this.dataContractObject(),
methodStr(ProdPacklistContract,parmSalesId));
if (dialogSalesId)
{
dialogSalesId.lookupButton(2);
}
dialogSalesId.value(" ");
// register override method for lookup
cust Group
dialogSalesId.registerOverrideMethod(methodStr(FormStringControl,
lookup), methodStr(ProdPackListUIBuilder, lookupSalesId), this);
// register override method for
modified
dialogSalesId.registerOverrideMethod(methodStr(FormStringControl,
modified), methodStr(ProdPackListUIBuilder, SalesIdModified), this);
//binding info for customer drop down
dialogSalesLine =
this.bindInfo().getDialogField(this.dataContractObject(),
methodStr(ProdPacklistContract,parmSalesLine));
dialogSalesLine.value(" ");
// register override method for lookup
customer
dialogSalesLine.registerOverrideMethod(methodStr(FormStringControl,
lookup), methodStr(ProdPackListUIBuilder, lookupSalesLine), this);
if (dialogSalesLine)
{
dialogSalesLine.lookupButton(2);
}
if(ProdTable.InventRefType==InventRefType::Sales)
{
dialogSalesId.value(prodTable.InventRefId);
dialogSalesLine.value(SalesLine::findInventTransId(prodTable.InventRefTransId).LineNum);
prodPacklistContract.parmSalesId(prodTable.InventRefId);
prodPacklistContract.parmSalesLine(SalesLine::findInventTransId(prodTable.InventRefTransId).LineNum);
dialogSalesId.enabled(false);
dialogSalesLine.enabled(false);
}
if(prodTable.RecId==0)
{
throw error(strFmt("please select
valid production order"));
}
}
else
{
prodPacklistContract.parmSalesId("");
}
}
// if the salesId is modified we have to load the sales lines
public boolean
SalesIdModified(FormStringControl _control)
{
dialogSalesId.value(_control.valueStr());
dialogSalesLine.value('');
return true;
}
private
boolean validateCaller()
{
if((packListcontroller.parmArgs().menuItemName()
== menuitemOutputStr(ProdPacklist)) &&
(packListcontroller.parmArgs().dataset() ==0))
return false;
else
return true;
}
private void
validateData(SalesId _salesId,LineNum _lineNum)
{
boolean ret=true;
SalesLine salesLine;
if(this.validateCaller())
{
if(_salesId=="")
throw error(strFmt("this
production is not linked to sales %1",prodTable.ProdId));
if(_lineNum==0)
throw error(strFmt("this
production is not linked to sales %1 ",_salesId,prodTable.ProdId));
if(ret)
{
salesLine=
SalesLine::find(_salesId,_lineNum);
if(salesLine &&
salesline.ItemId != prodTable.ItemId)
{
throw error(strFmt("this
production is not linked to sales %1 ,%2",salesLine.ItemId,prodTable.ItemId));
}
}
}
}
After creation of all the classes above mentioned then we have to create the report,
Open .netDevelopment enviorment and create project and select Microsoft Dynamics AX from the Left pane and select the ReportModel Project from the list of project and give your project name and click ok.
select the project and right click and click add and select report.
It will create the new report as follow.Right click on report and select properties and give the name as ProdPackList.
Select DataSets and right click and click AddDataset and provide the DatasetName and select the dataset that you created and right click and properties.
click on Query it will opens the dialog with the DataProvider classes,in that select the DataProvider class that we built and click next. It will opens the fields selection window where we will select the list of fields that required to show in the report
based on your requirements you can select or deselect the fields and click on. Now the dataset with the fields are ready for the report.
Now you can drag and drop that dataset on to the designs node, It will generate auomatic design for those fields.
If you want to design your own format then create new precision Design by right click on the designnode and add precisionDesign and change that design name as we mentioned in the controller class main method(Report).
I Created the Precision design as follows.
This is how my report looks like above.
Hi,
ReplyDeleteI have designed a report.Before printing the report, i need to select the values using a query.
i followed the way you created prePromptModifyContract().
But i am not able to find those query range values on dialog.
Am i missing something?
Can you please tell me if i need to do anything more?
Hi Jhansi,
DeleteDid you define the Member attribute of query on the class declaration of dp class. and your dpclass should be extend from srsreportdataprovidepreprocess class then only you can debug into the dp class...
and please keep the debugger in the contoller Main method of staroperation call...go into those methods...and it will call..prepromptmodifycontract...and check whether its hitting your method or not.
Regards,
krishna.
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hi Krishna,
ReplyDeleteI did the same steps as you mention for my custom packing slip. However, when I run the report, it shows only fixed layout but not the data querried in AX db. I had debugged already, it went to "process report" method and completed inserted data into details table, but after that, the data weren't shown in the report.
Do you have any suggestion for this issue?
Thank you very much.
Jane
Hi Hong,
Deletein your Report design you have build the dataset with this DP class, then in your report design table you have define the datasource for this Dataset and added the fields from this dataset right?-
Then you override the method preRunValidate and keep the debugger and see how many records its returning... from the query.
and your main method of the controller should have your reportName.Design
Still if not working please send me the whole project...I will check it.
Regards,
krishna
krishna.dynamics@gmail.com
Hi Krishna,
DeleteProblem sold. Just a silly mistake.
Thank for your help. I've learn a lot from your reply. I'll visit your blog frequently. Look forward to read new post.
Regards,
Trinh
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hi Krishna,
ReplyDeleteI have designed a report using RDP.
In fact, the report is a label printing with specific page size.
However, everytime when I change the page width bigger than page height, the orientation is set to Landscape.
This cause the label being printed side ways.
I have look through and still no solution yet.
Have you encounter this issue? Is there a ways to set the orientation using RDP class?
Thanks so much.
Vincent
crazysee@gmail.com
Hi Vincent,
DeleteYou can set anything related to page width and heights for the report,normally when you design the report you can go to the report properties and select the page type-A4,letter,tabloid etc based on your page type selection it will have its own sizes bye protrait and landscape, may be in your case your report is expanding more width than required portrait width, you can reduce the report deisgn to 19cm then you will get in the porttrait format.
I hope you understand now,if not please let me know.
Regards,
krishna.
krishna.dynamics@gmail.com
Hi Krishna,
DeleteThanks for the prompt reply.
The width is small than 19cm actually.
I'm trying to get it as 4in width and 2.4in height.
When I key in that value, the orientation is automatically set to landscape.
Thanks.
Vincent
crazysee@gmail.com
Sorry. To clarify, i need to print out the label in 4in width and 2.4in height in portrait mode.
DeleteHi vincent,
Deletethen decrease you design width to 5in and height to 2.3in
open your design and reduce your table or textbox to 4in and height to 2.4in and change your text properties as not to increase the height.
then it will works.
Regards,
krishna.
Hi Krishna,
DeleteI tried but it doesn't work.
As long as I set the width value higher than height, system auto set to landscape and the print out will always be side ways.
Vincent
Hi Vincent,
DeleteYes sorry, always the height of the report should be more than the width, I don't think you required to change the height of the design, only you have to set the width of the potrait to 5in and your text box size you can define to 4in and height 2.4in and uncheck the text box to increace the height, then i think it will works.
Regards,
krishna.
Hi Krishna,
DeleteThanks so much for all the replies.
I tried you method but it didn't work. The printer recognize the and shrink it to fit into the label paper.
Anyway, I'm using a RDP class. Is there any way to set the orientation programatically?
Thank you so much.
Vincent
Hi Vincent,
DeleteI got an idea, in you design create a new design as a ListStyleTemplate, select your design and define the template as ListStyleTemplate and provide the datasource as your dataset and provide your height as 2.4in. I hope then it will works.
Regards,
krishna.
Hi Krishna,
DeleteCan you tell me how to change / set report orientation from AX 2012's Class? like AX 2009
Thx & Regards,
Darwanto
Hi Darwanto,
DeleteWe can set it through controller, for ex take salesConfirm Report
SalesConfirmController have the method RunPrintMgmt,this method will be there only the document was managed by print management.
Delcare the following class objects
SRSPrintDestinationSettings srsPrintDestinationCopySettings,srsPrintDestinationOriginalSettings;
get the class object printdestination settings for the report
srsPrintDestinationCopySettings=formLetterReport.parmDefaultCopyPrintJobSettings();
srsPrintDestinationOriginalSettings=formLetterReport.parmDefaultOriginalPrintJobSettings();
Assign lanscape method as true
srsPrintDestinationCopySettings.landscape(true);
srsPrintDestinationOriginalSettings.landscape(true);
Then assign the printer settings again to formletterReport
formLetterReport.parmDefaultCopyPrintJobSettings(srsPrintDestinationCopySettings);
formLetterReport.parmDefaultOriginalPrintJobSettings(srsPrintDestinationOriginalSettings);
I hope you got how to do it.
regards,
krishna.
Hi Krishna,
DeleteThx for your reply.
I've tried your method (using RunPrintManagement) and i'm extend the RDP class with SRSReportDataProviderPreProcess.
Using SalesConfirm as an example, but now i got an error "Parameter 'paramName' does not exist on this report". The error shown after i press "OK" on the report dialog.
Although i've use controller.parmShowDialog(false) in the main controller class, but the error still exist.
Can you help me solve this problem?
Thx in advanced.
Regards,
Darwanto
Hi , Krishna , basically i want to know that you are using temp table and you mentioned the image below consisting of fields , i made the same query prodtable-inventtransorigin-inventtrans, maked al relations b/w them as you did. but i didn't find the fields when i am inserting in temp table by dragging them from the table????
ReplyDeleteHi,
ReplyDeleteYou blog was really help full i was able to create my SSRS report. However I had a question on formatting.
I have to create a report that has a detachable part in it i.e. once the report is printed the user can cut off a particular section manually.
I am facing two scenarios:
1)Report has 3 pages (both side printing) in this case the data will be printed on first two pages and the detachable section will start from third fresh page.
2) Report has 4 pages out of which 3 has data in it. in this case the first 3 pages will be printed back to back and the 4th page will be left blank. The detachable section should start from 5th page.
how can i achieve this
Hi,
ReplyDeleteI forgot to mention i am working in AX 2012.
To simplify this if the body section of a report takes even number of pages i need to add a page break: detachable section will go to a fresh page.
If the body section of the report takes odd number of page then i need two page breaks so that detachable section goes to a fresh page.
Sapna,
DeleteI'm also in a similar situation. Did you get a solution? Kindly assist.
Regards,
Sapna,
DeleteI got something that maybe sort your out. If you are using tables,you can insert the detachable section in a tablix then from the tablix property dialog, under page break options, check the Add a page break before options.
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hi Krishna!
ReplyDeleteI have a problem. I am new in SSRS riports and not to experienced in AX. I've tried to create a Report and I am pretty sure that I making an obvious mistake but I cannot realize.
So creted a query in AX2012. Created a project and a report in VS2010 but when I would like to choose my new query in the dataset query property, I just cannot because I cannot see any newly created query(what my collagues created earlier). But in the Application explorer there is my ( and all of the new objects) queries. So just don't know which property or configures doesn't set. Thanks
Hi Krishna
ReplyDeleteI have a problem in sales quotation report. The report run based on selected Quotation journal.I want to run the report for a sales quotation as well as to send a mail to the customer. i tried in Controller class it is not working.
Hi Krishna,
ReplyDeleteI am trying to add another design on the WMSPickingList_OrderPick report. (AX2012). It uses the WmsPickingList_OrderPickController class. So there will be two designs and I want to call the different designs from two different menu items.
controller.parmReportName((ssrsReportStr(WMSPickingList_OrderPick, Report)
The above line lets me specify the design. but i dont know how to do this depending on the menu item called from.
Any ideas?
Thanks
Thasha
Hi Thasha,
DeleteWhen you have multiple designs for the report, and you have two menuitems, then in your controller main method while passing parmReportName you have to validate from which caller is this from args and you have to pass different deisgns for each menuitem caller for parmreportname(reprtName.designname);
hope you understand otheriwise ping me on
krishna.dynamics@gmail.com
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hi Krishna.
ReplyDeleteI did the same steps, and when I run the report it shows only fixed layout but not the data. I'm trying use the debugger in the Controller Class, but the code don't pass in the controller class methods. How can I associate the DP with the Controller class?
Thank's!
I'm learning a lot from your blog
Hi Krishna,
ReplyDeletethis is chandru, i am facing problem in SSRS report,please help me on this.
i added new fields in existing Axapta standard SSRS reports. in UIbuilder and contract class, i added new parameter. in temp table also some fields added. in SSRS reports design those fileds added, while open Ax thick client enter values in parameters and click ok, i am getting this below error
parameter 'tmptableDS_newParameter' does not exist in the report.
i deployed the report,restarted AOS & SSRS services.
i am trying to add this in to existing group but it is giveing some compilation errors. how to resolved this. Please help me. my mail id chandru.mbs@gmail.com
Hi Krishna,
ReplyDeleteI understand more about SSRS Report form your blog.I have problem need your advice.
I am using DP class to generate data in temp table as follow:
Voucher Amount
V1 150
V2 200
V3 300
Could we use controller class to print each record in separate report viewer?
Hope you understand what i mean.
Thanks in advance
Hi Nguyen,
Deleteyou have to write the class to filter the data and for each record you have to call the controller,so in your Dp class you will fill only that record.
classmain.
Filter the data according in the main and for each record you call start operation.
I hope you got it, if not ping me on krishna.dynamics@gmail.com
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hi Krishna,
ReplyDeleteiwould like to show the position heirarchy tree in dialog lookup for SSRS reports generation Axapta think client. Please give me the solution how to show Position hierarchy in dailog lookp.
Thanks & Regards
Chandru
Hi Chandru,
Deleteif you want to do any lookups for parameters you have to create the builder class and there you have to write the lookup method and register for that contract parm method.
regards,
krishna.
Hi chandru,
DeleteI updated the post with the builder class to build the lookups for the parameters of report.
regards,
krishna.
hi Krishna,
DeleteThanks for your solution. if we are design SSRS report, using precision design, in that design, how we can group the items and shown in header level. for example, in the data set i have 1 customer, for this customer mulitple lines are available. group by customer, i want to show the data in details section, customer id needs to be showned in header level.in Auto design, we have the groupings option is there, but in precision design how we achieve this. Please give the solution how we can do in precision design.
Regards
Chandru
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hi Krishna,
ReplyDeleteafter i run the main method on the controller, when it executes the method this.prePromptModifyContract();
when gos there, i have this line 'this.setRange(this.parmReportContract().parmQueryContracts().lookup(this.getFirstQueryContractKey()));' and here i'm getting the following exception
Map Object not initialized, can you help why i'm getting this kind of exception?
Hi Krishna,
ReplyDeleteI am doing employee profit loss report customizations, in report model, prameters sections added the parameter group in that group i dragged the parameters. after that i try to deploy, it is showing below error
Error 2 The property 'Report parameter' on model element ':
CGS_EmplProfitableReport.ProjProfitLossDS(DataSets).TimeMaterial(Parameters)'
refers to target element 'Parameters.ProjProfitLossDS_TimeMaterial' which cannot be resolved.
Make sure that the property value is correct and that the target model element is within scope,
either in the project or in referenced projects or assemblies. \SSRS Reports\Reports\CGS_EmplProfitableReport 0 0 CGS_EMPProfitReport
without adding in to the parameter group, deployement done successfully.Please give me the solution.
Thanks & Regards
Sarat Chandra R
Hi Krishna.
ReplyDeleteIn AX 2009 reports we were able to write element.JobId() and get jobId. How can I find JobId in AX 2012 if I create SSRS Report using Data Provides Classes?
Regards,
Oksana
Hi Krishna,
ReplyDeleteThanks for the solution. I make two SSRS report, but, do you know how run two reports in one view? Because my client need print both reports in a printer with two sides paper wihtout removing paper.
Thanks and regards,
Yered
Hey all,
DeleteI am sending out a note to those of you that have taken advantage of my Blog(http://krishhdax.blogspot.com),through skype,Chat..etc, that I have been making over the past couple of years, asking for a favor.
It is that time of year 2013, and we are now announcing the nomination process for The Most Influential People in Microsoft Dynamics for 2013. I would really like to make the list this year, and I hope that I have influenced you all in my own little way.
If you feel inclined, you can nominate me by sending an email with a persuasive explanation for the nomination to top100@dynamicsworld.co.uk or through Twitter using the #dwtop100 tag.
You can find more on the nomination process can be found here: http://www.dynamicsworld.co.uk/top100nominationprocess/
Thanks in advance.
Krishna Reddy Modugula | CGI |AX Technical Manager | Microsoft Solutions
Lautrupvang 10, DK-2750 Ballerup | Denmark
Phone: +45 44 78 40 00 | Mobile: +45 41 88 23 35
www.cgi.com | www.cgi.dk
http://krishhdax.blogspot.com
http://www.linkedin.com/in/krishhprofile
Hello Krishna,
ReplyDeletethanks for your comprehensive tutorial.
I tried to follow it, but I don't see the newly created data provider class in the dialog of Report / Datasets / Query. I see other DP classes, but not mine. I tried incremental CIL but without any change.
this is the class declaration
[
SRSReportParameterAttribute(classStr(LedgerTransOpenContract)),
SRSReportQueryAttribute(queryStr(LedgerTransOpen))
]
public class LedgerTransOpenDP extends SRSReportDataProviderPreProcess
{
LedgerTransOpenTmp ledgerTransOpenTmp;
}
do you have any idea, what is wrong?
Hi Krishna
ReplyDeleteI desinged a SSRS report in Ax2012 using contract and DP classes.
I have a small label update issue in contract class.
I imported all the report related objects and deployed the report.Report is working fine.
But i changed the label id in the SysOperationLabelAttribute, SysOperationHelpTextAttribute properties for my parameter fields. After changing this, the labels for the parameter fields didnt get updated to the new label.The label for the parameter fields is still pointing to the old label id which was there when i imported. But the help text label got updated.
I have tried deploying the report again in Visual studio, restarting reporting services, restarting Ax service, clearing usage data, even full cil was done.
But the label for the parameter field didnot get updated.
I see the old label when the parameters screen gets opened before printing the report.
Is there any way that i can update the label for the parameter fields ?
Thanks in advance
Hi Gandadhar,
DeleteNormally it should work if not try to open the design and change in the parameter label value with that label id and deploy it and see...if not some cache problem. restart SSRS,AOS,Clear the AUC files and try..
Thanks Krishna
DeleteI have tried giving the labelId in the PromptString property for the parameter in visual studio. There i can see the previously entered labels in the drop down but i am not able to select any of them.
Eventhough i just simply tried to select it and deploy it. After this i can see the labels updated. Not sure because of what change it got updated
Thanks again for your information
Hi Krishna,
ReplyDeleteI need an help in an Existing Report ProdJobCard Report i need to display the transactions for each Job Card respectively.Kindly tell me how can i do that .How can i link the ProdBom with OprNUm and sispaly transations
Hi Krishna,
ReplyDeleteThanks for the whole uttorial!
I made an SSRS report, works well in Visual Studio. Only problem is, when I want to set it to a Output Menu Item, I got the following: "xxx attribute class has not been declared". I got the DP and the Controller classes. Could you give me tips where to find the root of the issue?
Thanks in advance!
Hi Krishna Reddy,
ReplyDeleteI create an SSRS report Ax 2012. I create function:
[
DataMemberAttribute('LedgerConsolidateAccountGroupId'),
SysOperationHelpTextAttribute(literalstr("@GLS222083")),
SysOperationGroupMemberAttribute('ConsolidateGroupId'),
SysOperationDisplayOrderAttribute('4')
]
public LedgerConsolidateAccountGroupId parmConsolidateGroupId(LedgerConsolidateAccountGroupId _consolidateAccountGroupId = consolidateAccountGroupId)
{
consolidateAccountGroupId = _consolidateAccountGroupId;
return consolidateAccountGroupId;
}
on Contract class,
but it seems doesn't pass data to Data Provider class.
Could you please help.
Many thanks.
Hi
ReplyDeleteI have a requirement like we need to print each record information in each page in Ax 2012 ssrs report
How can i acheive this.
can you please help me on this
Hi Gangadhar,
DeleteCreate group by and define page break after for that group.
Thanks Krishna
Deletehi krishna
ReplyDeletei created a lookup but i am not able to fetch data in my lookup from temporary table. please help me krishna.
i want to select multiple fields in my report from the same look up . please help me .
ReplyDeleteHi Deepak,
DeleteIn my above post, I created the lookup for salesId and SalesLineNum in the builder class.
I dint get the point that you mentioned select multiple fields in report from same lookup. could you please brief it.
if you want to talk to me on gmail or skype you can send me the contact request.
gmail:krishna.dynamics@gmail.com
Hi Krishna
ReplyDeleteMy Contract Class code is as follows:-
1.class declration
[DataContractAttribute,
SysOperationContractProcessingAttribute(classstr(tri_uibuilder)) ]
class tri_contract
{
List studentid;
}
2.parmstudentid
[
DataMemberAttribute('StudentId'),
AifCollectionTypeAttribute('StudentId', Types::String),
SysOperationLabelAttribute(literalstr("studentid"))
]
public List parmstudentid(List _studentid = studentid)
{
studentid = _studentid;
return studentid;
}
My Dp Class is as following
[
SRSReportQueryAttribute(queryStr(tri_lookup)),
SRSReportParameterAttribute(classStr(tri_contract))
]
public class tri_rdbclass extends SRSReportDataProviderBase
{
tempstudent tmptable;
}
2.[SRSReportDataSetAttribute('tempstudent')]
public tempstudent gettempstudent()
{
select * from tmptable;
return tmptable;
}
3.Process Report
public void processReport()
{
List studentid=new List(Types::String);
Query query=new query();
QueryRun qr;
QueryBuildDataSource queryBuildDataSource;
QueryBuildRange queryBuildRange;
tri_student querytri_student;
tri_course querytri_course;
ListEnumerator stuindex;
tri_contract dataContract;
str test;
// Get the query from the runtime using a dynamic query.
query = this.parmQuery();
// Get the parameters passed from runtime.
dataContract = this.parmDataContract() as tri_contract;
studentid = dataContract.parmstudentid();
// queryBuildDataSource = query.dataSourceTable(tablenum(tri_student));
if(studentid.empty())
{
queryBuildRange = queryBuildDataSource.addRange(fieldnum(tri_student, studentid));
// if (!queryBuildRange)
//{
// queryBuildRange = queryBuildDataSource.addRange(fieldnum(tri_student, studentid));
//}
// If the student id has not been set, then use the parameter value to set it.
//if(!queryBuildRange.value())
stuindex= studentid.getEnumerator();
//test=stuindex.current();
//while(stuindex.moveNext()){
//test+="||";
//test+=stuindex.current();
}
queryBuildRange.value(test);
qr = new QueryRun(query);
//ttsbegin;
while(qr.next())
{
tmptable.clear();
querytri_student = qr.get(tablenum(tri_student));
//this.insertTmpTable(querytri_student,querytri_course);
querytri_course=qr.get(tableNum(tri_course));
// this.insertTmpTable(tri_course);
tmptable.studentid = querytri_student.studentid;
tmptable.CourseName=querytri_course.coursename;
tmptable.CourseType=querytri_course.coursetype;
tmptable.Courseid=querytri_course.Courseid;
tmptable.StudentName = querytri_student.studentname;
//select * from querytri_student where querytri_student.Courseid==querytri_course.Courseid;
tmptable.insert();
//Tmpco.insert();
//ttscommit;
}
}
my UI bUilder is as follows:-
ReplyDeleteclass tri_uibuilder extends SrsReportDataContractUIBuilder
{
DialogField dialogstudentid;
boolean enable;
tri_contract contract;
}
2.public void build()
{
contract = this.dataContractObject();
dialogstudentid = this.addDialogField(methodStr(tri_contract, parmstudentid),contract);
//super();
}
3.public void getFromDialog()
{
contract = this.dataContractObject();
super();
}
4.public void initializeFields()
{
contract = this.dataContractObject();
}
5.private void studentidLookup(FormStringControl studentidlookup)
{
Query query = new Query();
QueryBuildDataSource qbds_studentid;
SysTableLookup systablelookup;
QueryBuildRange qbr;
if(studentidlookup!=null)
{
// Create an instance of SysTableLookup with the current calling form control.
sysTableLookup = SysTableLookup::newParameters(tableNum(tri_student), studentidlookup);
//sysTableLookup = SysTableLookup::newParameters(tableNum(tri_course), studentidlookup);
// Add fields to be shown in the lookup form.
qbds_studentid = query.addDataSource(tableNum(tri_student));
sysTableLookup.addLookupfield(fieldNum(tri_student,StudentId),true);
// sysTableLookup.addLookupfield(fieldNum(tri_student,StudentName));
//sysTableLookup.addLookupfield(fieldNum(tri_course,CourseName));
// sysTableLookup.addLookupfield(fieldNum(tri_course,CourseType));
// sysTableLookup.addLookupfield(fieldNum(tri_course,CourseId));
//sysTableLookup.addLookupfield(fieldNum(FilterDemo,Name));
qbr = qbds_studentid.addRange(fieldNum(tri_student,studentid));
// qbr.value('20');
sysTableLookup.parmUseLookupValue(false);
sysTableLookup.parmQuery(query);
// Perform the lookup
sysTableLookup.performFormLookup();
}
}
i have to select multiple records from look up but my look up is empty i.e has no record when calling report.
and gettintg error list objects not initialised.
why data is not showing in lookup?
& why error is there.?
help me out
thanks for the good codes
ReplyDeleteI have made a ui builder class which has the dialog field of sales id and sales name in which I used a query build field list for multiselect but when in dialog field I multiselect salesname or salesid it shows only the record of first one selected lookup the others records are not displayed
ReplyDeleteplease help me out regarding this problem.
I have made a ui builder class which has the dialog field of sales id and sales name in which I used a query build field list for multiselect but when in dialog field I multiselect salesname or salesid it shows only the record of first one selected lookup the others records are not displayed
ReplyDeleteplease help me out regarding this problem.
hi krishna
ReplyDeletehow to change the report designs at run time.
when we are using multiple designs.
thanks & regards
rameshkumar
Hi Ramesh,
DeleteYou can do in the controller main method. see in the above code main method, in this method do validation and pass whatever the design that you want to use it.
controller.parmReportName("ProdPackList.Report");
Hi Krishna, Good article.
ReplyDeleteI was searching for the method processPreRunValidate.
However in your article you say to throw an error instead of sending the error Type enum back. Instead you should use
validateResult = [SrsReportPreRunState::Error, "No records available for the Selected criteria"];
The second element in the container being the message instead (If its empty then the default message of exceeding records for timeout will be shown) :)
Hi
DeleteI'm facing problem with ssrs reports, Here is my requirement
I have created a new custom report (with new DP, Contract,Controller) and when ever customer(client)selects copy from Print management-- (where my customer report is attached to drop down list of report format field) my custom report should open from CustinvoiceJourmal--Copy preview --Custom report
AR_printmanagement-- customerinvoice-- copy
Where should i write the code for my report should open
can you please help me with code...
Thanks in advance
Vivek Goud
vivekvalandas@gmail.com
Hi Vivek,
DeleteI already posted one post regarding the configuring the printmanagement for the report, could you please see that post
for your reference I am adding the url below.
http://krishhdax.blogspot.dk/2012/02/ax2012-configure-print-management-for.html