Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create reports ? #147

Closed
KeypeG opened this issue Oct 14, 2016 · 4 comments
Closed

How to create reports ? #147

KeypeG opened this issue Oct 14, 2016 · 4 comments

Comments

@KeypeG
Copy link

KeypeG commented Oct 14, 2016

Hi,
I am trying to create reports programmatically with the apex metadata api, but am facing the following issue:
image

Here's the code used (in the execute anonymous window) :

public class MetadataServiceException extends Exception { }
public static void handleSaveResults(MetadataService.SaveResult saveResult) {
    if(saveResult==null || saveResult.success)
        return;
    if(saveResult.errors!=null) {
        List<String> messages = new List<String>();
        messages.add(
            (saveResult.errors.size()==1 ? 'Error ' : 'Errors ') +
            'occured processing component ' + saveResult.fullName + '.');
        for(MetadataService.Error error : saveResult.errors)
            messages.add(
                error.message + ' (' + error.statusCode + ').' +
                ( error.fields!=null && error.fields.size()>0 ?
                 ' Fields ' + String.join(error.fields, ',') + '.' : '' ) );
        if(messages.size()>0)
            throw new MetadataServiceException (String.join(messages, ' '));
    }
    if(!saveResult.success)
        throw new MetadataServiceException ('Request failed with no specified error.');
}

// Here's the part that I am concerned with
MetadataService.MetadataPort service = new MetadataService.MetadataPort();
service.SessionHeader = new MetadataService.SessionHeader_element();
service.SessionHeader.sessionId = UserInfo.getSessionId();

// I get the report to clone
MetadataService.Report reportToClone = (MetadataService.Report) service.readMetadata('Report', new String[] { 'report_folder_api_name/report_api_name' }).getRecords()[0];

// Instanciate a new one to attribute the same metadata from the report to clone
MetadataService.Report apexReport = new MetadataService.Report();
apexReport.name = 'Apex_Clone_Report';
apexReport.fullName = 'Apex Clone Report';
apexReport.reportType = reportToClone.reportType;
apexReport.format = reportToClone.format;
apexReport.filter = reportToClone.filter;
apexReport.folderName = 'report_folder_api_name';
apexReport.columns = reportToClone.columns;

// Create the report
List<MetadataService.SaveResult> results = service.createMetadata(new MetadataService.Metadata[] { apexReport });

// Handle the results
handleSaveResults(results[0]);

Could you provide me with what I'm missing there ?

Thanks.

PS: This is almost a duplicate of this issue.

@KeypeG
Copy link
Author

KeypeG commented Nov 22, 2016

Without any answer about this issue, I tried over again and managed to entirely clone a report from one folder to another.

The initial issue was that the "fullName" field of the new report wasn't well constructed as it actually needs to be populated with both the report folder api name and the report api name.

As this might be of use for anyone, here's the code sample I'm using:

public class MetadataServiceException extends Exception { }
public static void handleSaveResults(MetadataService.SaveResult saveResult) {
    if(saveResult==null || saveResult.success)
        return;
    if(saveResult.errors!=null) {
        List<String> messages = new List<String>();
        messages.add(
            (saveResult.errors.size()==1 ? 'Error ' : 'Errors ') +
            'occured processing component ' + saveResult.fullName + '.');
        for(MetadataService.Error error : saveResult.errors)
            messages.add(
                error.message + ' (' + error.statusCode + ').' +
                ( error.fields!=null && error.fields.size()>0 ?
                 ' Fields ' + String.join(error.fields, ',') + '.' : '' ) );
        if(messages.size()>0)
            throw new MetadataServiceException (String.join(messages, ' '));
    }
    if(!saveResult.success)
        throw new MetadataServiceException ('Request failed with no specified error.');
}

/**
 * Method cloneReport(String sFolderApiName, String sReportApiName, String tFolderApiName, String tReportApiName)
 * @param sFolderApiName: api name of the (source) folder of the report to clone
 * @param sReportApiName: api name of the (source) report to clone
 * @param tFolderApiName: api name of the (target) folder to create the cloned report in
 * @param tReportApiName: api name of the (target) cloned report 
 */
Public static void cloneReport(String sFolderApiName, String sReportApiName, String tFolderApiName, String tReportApiName) {
	MetadataService.MetadataPort service = new MetadataService.MetadataPort();
	service.SessionHeader = new MetadataService.SessionHeader_element();
	service.SessionHeader.sessionId = UserInfo.getSessionId();

	// Get the report to clone
	MetadataService.Report reportToClone = (MetadataService.Report) service.readMetadata('Report', new String[] { sFolderApiName+'/'+sReportApiName }).getRecords()[0];

	// Instanciate a new one to attribute the same metadata from the report to clone
	MetadataService.Report apexReport = new MetadataService.Report();
	// Set the cloned report properties from parameters and the source report
	apexReport.name = reportToClone.name + ' Clone';
	apexReport.fullName = tFolderApiName + '/' + tReportApiName;
	apexReport.reportType = reportToClone.reportType;
	apexReport.description = reportToClone.description;
	apexReport.format = reportToClone.format;
	apexReport.filter = reportToClone.filter;
        apexReport.showDetails = reportToClone.showDetails;
        apexReport.sortColumn = reportToClone.sortColumn;
        apexReport.sortOrder = reportToClone.sortOrder;
        apexReport.groupingsAcross = reportToClone.groupingsAcross;
        apexReport.groupingsDown = reportToClone.groupingsDown;
        apexReport.chart = reportToClone.chart;
	apexReport.timeFrameFilter = reportToClone.timeFrameFilter;
	apexReport.columns = reportToClone.columns;

	// Create the report clone
	List<MetadataService.SaveResult> results = service.createMetadata(new MetadataService.Metadata[] { apexReport });

	// Handle results
	handleSaveResults(results[0]);
}

cloneReport('Source_Folder_Api_Name','Source_Report_Api_Name','Target_Folder_Api_Name','Target_Report_Api_Name');

This actually needs to be customized depending on one's need over reports metadata, but it's a great sample to begin with mdapi report cloning.

@KeypeG KeypeG closed this as completed Nov 22, 2016
@afawcett
Copy link
Contributor

afawcett commented Dec 4, 2016

Thank you @KGFTW for this excellent submission. My recent family relocation to the US has kept my personal time quite busy, i'm only just getting back into the community. I really really appreciate you sharing this.

@afawcett
Copy link
Contributor

afawcett commented Dec 9, 2016

@KGFTW i update the README file to highlight this excellent submission, also tweeted it, thanks again! 👍

@KeypeG
Copy link
Author

KeypeG commented Dec 9, 2016

@afawcett You're Welcome ! Here's also a dashboard cloning code sample I managed to do as I needed it too. Combining both this one and the previous one can become really handy :)

/**
 * Methode initDashboardComponent(MetadataService.DashboardComponent comp)
 * @param comp: source dashboard component to clone
 * @return newComp: new dashboard component initialised using the source dashboard component
 */
public static MetadataService.DashboardComponent initDashboardComponent(MetadataService.DashboardComponent comp) {
    // Init the new component and set its properties from the source dashboard component
    MetadataService.DashboardComponent newComp = new MetadataService.DashboardComponent();
    newComp.report = comp.report;
    newComp.autoselectColumnsFromReport = comp.autoselectColumnsFromReport;
    newComp.chartAxisRange = comp.chartAxisRange;
    newComp.chartAxisRangeMax = comp.chartAxisRangeMax;
    newComp.chartAxisRangeMin = comp.chartAxisRangeMin;
    newComp.chartSummary = comp.chartSummary;
    newComp.componentType = comp.componentType;
    newComp.dashboardFilterColumns = comp.dashboardFilterColumns;
    newComp.dashboardTableColumn = comp.dashboardTableColumn;
    newComp.displayUnits = comp.displayUnits;
    newComp.drillDownUrl = comp.drillDownUrl;
    newComp.drillEnabled = comp.drillEnabled;
    newComp.drillToDetailEnabled = comp.drillToDetailEnabled;
    newComp.enableHover = comp.enableHover;
    newComp.expandOthers = comp.expandOthers;
    newComp.footer = comp.footer;
    newComp.gaugeMax = comp.gaugeMax;
    newComp.gaugeMin = comp.gaugeMin;
    newComp.groupingColumn = comp.groupingColumn;
    newComp.header = comp.header;
    newComp.indicatorBreakpoint1 = comp.indicatorBreakpoint1;
    newComp.indicatorBreakpoint2 = comp.indicatorBreakpoint2;
    newComp.indicatorHighColor = comp.indicatorHighColor;
    newComp.indicatorLowColor = comp.indicatorLowColor;
    newComp.indicatorMiddleColor = comp.indicatorMiddleColor;
    newComp.legendPosition = comp.legendPosition;
    newComp.maxValuesDisplayed = comp.maxValuesDisplayed;
    newComp.metricLabel = comp.metricLabel;
    newComp.page_x = comp.page_x;
    newComp.pageHeightInPixels = comp.pageHeightInPixels;
    newComp.scontrol = comp.scontrol;
    newComp.scontrolHeightInPixels = comp.scontrolHeightInPixels;
    newComp.showPercentage = comp.showPercentage;
    newComp.showPicturesOnCharts = comp.showPicturesOnCharts;
    newComp.showPicturesOnTables = comp.showPicturesOnTables;
    newComp.showTotal = comp.showTotal;
    newComp.showValues = comp.showValues;
    newComp.sortBy = comp.sortBy;
    newComp.title = comp.title;
    newComp.useReportChart = comp.useReportChart;
    return newComp;
}

/**
 * Method cloneDashboard(String sFolderApiName, String sDashboardApiName, String tFolderApiName)
 * @param sFolderApiName: api name of the (source) folder of the dashboard to clone
 * @param sDashboardApiName: api name of the (source) dashboard to clone
 * @param tFolderApiName: api name of the (target) folder to create the cloned dashboard in
 */
Public static void cloneDashboards(String sFolderApiName, String sDashboardApiName, String tFolderApiName) {
    MetadataService.MetadataPort service = new MetadataService.MetadataPort();
    service.SessionHeader = new MetadataService.SessionHeader_element();
    service.SessionHeader.sessionId = UserInfo.getSessionId();
    // Get the dashboard to clone
    MetadataService.Dashboard dashboardToClone = (MetadataService.Dashboard) service.readMetadata('Dashboard', new String[] { sFolderApiName + '/' + sDashboardApiName }).getRecords()[0];

    // Create a new dashboard, this will be the clone
    MetadataService.Dashboard apexDashboard = new MetadataService.Dashboard();

    // Create the new dashboard component sections
    apexDashboard.leftSection = new MetadataService.DashboardComponentSection();
    apexDashboard.middleSection = new MetadataService.DashboardComponentSection();
    apexDashboard.rightSection = new MetadataService.DashboardComponentSection();

    // Set their size based on the sections to clone
    apexDashboard.leftSection.columnSize = dashboardToClone.leftSection.columnSize;
    apexDashboard.middleSection.columnSize = dashboardToClone.middleSection.columnSize;
    apexDashboard.rightSection.columnSize = dashboardToClone.rightSection.columnSize;

    // Create new components for each
    apexDashboard.leftSection.components = new List<MetadataService.DashboardComponent>();
    apexDashboard.middleSection.components = new List<MetadataService.DashboardComponent>();
    apexDashboard.rightSection.components = new List<MetadataService.DashboardComponent>();

    // Populate them from the report to clone
    for(MetadataService.DashboardComponent comp: dashboardToClone.leftSection.components) {
        apexDashboard.leftSection.components.add(initDashboardComponent(comp));
    }
    for(MetadataService.DashboardComponent comp: dashboardToClone.middleSection.components) {
        apexDashboard.middleSection.components.add(initDashboardComponent(comp));
    }
    for(MetadataService.DashboardComponent comp: dashboardToClone.rightSection.components) {
        apexDashboard.rightSection.components.add(initDashboardComponent(comp));
    }
    // Set other properties
    apexDashboard.title = dashboardToClone.title + ' Clone';
    apexDashboard.fullName = tFolderApiName + '/' +  dashboardToClone.fullName.substring(dashboardToClone.fullName.indexOf('/')+1) + '_Clone';
    apexDashboard.titleColor = dashboardToClone.titleColor;
    apexDashboard.titleSize = dashboardToClone.titleSize;
    apexDashboard.textColor = dashboardToClone.textColor;
    apexDashboard.dashboardType = dashboardToClone.dashboardType;
    apexDashboard.description = dashboardToClone.description;
    apexDashboard.runningUser = dashboardToClone.runningUser;
    apexDashboard.backgroundEndColor = dashboardToClone.backgroundEndColor;
    apexDashboard.backgroundFadeDirection = dashboardToClone.backgroundFadeDirection;
    apexDashboard.backgroundStartColor = dashboardToClone.backgroundStartColor;
    apexDashboard.isGridLayout = dashboardToClone.isGridLayout;

    // Create the dashboard clone
    List<MetadataService.SaveResult> results = service.createMetadata(new MetadataService.Dashboard[] { apexDashboard });

    // Handle the results (Don't forget to include this method !)
    handleSaveResults(results[0]);
}

// Call the clone method as following
cloneDashboards('Source_Folder', 'Source_Dashboard', 'Target_Folder');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants