If you need to provide an SSRS report with a multiple company selection, you can opt for a cross-company query. In this case, such an option will be maintained by the system automatically. (You can try this [SrsReportQuery(queryStr(LogisticsEntityLocationUnion))])
But what if you need to do that without the former? In this case you'll need to use LedgerLegalEntityLookup class as follows. Say we deal with some mySalesBySegment report, which is meant to return some data for a given selection of legal entities.
I hid some not relevant code; so that you can get the gist.
Data contract mySalesBySegmentContract: we keep the user selection of companies as a string.
[DataContract] [SysOperationContractProcessing(classstr(mySalesBySegmentUIBuilder), SysOperationDataContractProcessingMode::CreateUIBuilderForRootContractOnly)] class mySalesBySegmentContract implements SysOperationValidatable { ... str legalEntityOptionsStr; ... [ DataMember('legalEntityOptions') , SysOperationGroupMember('Grouping'), SysOperationDisplayOrder('5') ] public str parmLegalEntityOptions(str _legalEntityOptions = legalEntityOptionsStr) { legalEntityOptionsStr = _legalEntityOptions; return legalEntityOptionsStr; } }
Report controller mySalesBySegmentController: if no companies selected, let's set it to the user's context.
public class mySalesBySegmentController extends SrsReportRunController { protected void prePromptModifyContract() { mySalesBySegmentContract dc = this.parmReportContract().parmRdpContract() as mySalesBySegmentContract; ... if (!dc.parmLegalEntityOptions()) { // Set the default value for the legal entity selection dc.parmLegalEntityOptions(con2str([curExt()])); } } protected void preRunModifyContract() { mySalesBySegmentContract dc; container legalEntityOptions; dc = this.parmReportContract().parmRdpContract() as mySalesBySegmentContract; legalEntityOptions = str2con(dc.parmLegalEntityOptions()); // Default current company if there were no company specifications provided to the API. if (legalEntityOptions == conNull()) { legalEntityOptions = [curExt()]; dc.parmLegalEntityOptions(con2str(legalEntityOptions)); } } public static void main(Args _args) { mySalesBySegmentController controller = new mySalesBySegmentController(); controller.parmReportName(ssrsReportStr(mySalesBySegment, Report)); controller.parmArgs(_args); controller.startOperation(); } }
User interface builder mySalesBySegmentUIBuilder: when an SSRS report runs, it shows its dialog twice: the second time in the report viewer, when the report is rendered. Thus we have to override dialog methods in the UIBuilder class to avoid the lovely 'Object reference not set to an instance of an object' error.
public class mySalesBySegmentUIBuilder extends SrsReportDataContractUIBuilder { mySalesBySegmentContract dc; // Legal entity lookup controls FormStringControl dialogLegalEntitySelection; LedgerLegalEntityLookup legalEntityLookup; int dialogLegalEntityLookupId; str userLegalEntityRange; container legalEntityOptions; /// <summary> /// Override this method in order to initialize the dialog fields after the fields are built. /// </summary> public void postBuild() { DialogField dialogField; super(); // parmCompanySelection dialogField = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(mySalesBySegmentContract, parmLegalEntityOptions)); this.setInVisible(dialogField); this.constructLegalEntityControl(dialog); } /// <summary> /// post runs /// </summary> public void postRun() { super(); this.constructLegalEntityLookup(dialog); Set userLegalEntitySet = LedgerSecurityHelper::ledgersWithMinimumSecurityAccess(menuItemActionStr(LedgerExchAdj), AccessRight::Edit, MenuItemType::Action); userLegalEntityRange = LedgerLegalEntityLookup::getLegalEntityRangeFromLegalEntitySet(userLegalEntitySet); } /// <summary> /// Contstruct /// </summary> /// <param name = "_dialog">Dialog</param> private void constructLegalEntityControl(Dialog _dialog) { FormBuildGroupControl currentGroup = _dialog.form().design().control(_dialog.curFormGroup().name()); FormBuildStringControl dialogLegalEntityLookup = currentGroup.addControl(FormControlType::String, 'LegalEntityLookup'); dialogLegalEntityLookup.extendedDataType(extendedTypeNum(LedgerLegalEntitySelection)); dialogLegalEntityLookup.lookupOnly(true); dialogLegalEntityLookupId = dialogLegalEntityLookup.id(); } /// <summary> /// Constructs the lookup for the legal entity selection. /// </summary> /// <param name = "_control">The <c>FormStringControl</c> object.</param> private void legalEntityLookup(FormStringControl _control) { legalEntityLookup.lookup(_control.text(), userLegalEntityRange); } /// <summary> /// Lookup override /// </summary> /// <param name = "_dialog">dialog</param> private void constructLegalEntityLookup(Dialog _dialog) { dialoglegalEntitySelection = _dialog.formRun().design().control(dialogLegalEntityLookupId); legalEntityLookup = LedgerLegalEntityLookup::construct(_dialog.formRun(), dialoglegalEntitySelection); // populates it from the packed paramater legalEntityLookup.setSelection(str2con(dc.parmLegalEntityOptions())); // let's have our own lookup dialoglegalEntitySelection.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(mySalesBySegmentUIBuilder, legalEntityLookup), this); } /// <summary> /// prebuilds /// </summary> public void preBuild() { dc = this.dataContractObject() as mySalesBySegmentContract; super(); } /// <summary> /// Gets it back from the dialog /// </summary> public void getFromDialog() { super(); dc.parmLegalEntityOptions(con2Str(legalEntityLookup.getLegalEntitySelection())); } }
Report data provider mySalesBySegmentDP: we need just to convert the saved string back to a container, then we can loop through it as required by the report logic.
[SRSReportParameterAttribute(classStr(mySalesBySegmentContract))] public class mySalesBySegmentDP extends SRSReportDataProviderPreProcessTempDB { container legalEntityOptions; public void processReport() { mySalesBySegmentContract dc; List legalEntityList; ListEnumerator legalEntityListEnumerator; SelectableDataArea companyId; str companyName; dc = this.parmDataContract() as mySalesBySegmentContract; this.setUserConnection(tmp); // getting all selected companies from the report query legalEntityList = con2List(str2con(dc.parmLegalEntityOptions())); legalEntityListEnumerator = legalEntityList.getEnumerator(); while (legalEntityListEnumerator.moveNext()) { companyId = legalEntityListEnumerator.current(); companyName = CompanyInfo::findDataArea(companyId).name(); changecompany(companyId) { // Populate the base processing table with data from the appropriate source table ... } } } }