Report Requests Code Example

This example demonstrates how to request and retrieve performance reports.

Tip

Use the language selector in the documentation header to choose C#, Java, Php, or Python.

To get access and refresh tokens for your Microsoft Advertising user and make your first service call using the Bing Ads API, see the Quick Start sample. You'll want to review the Get Started guide and walkthroughs for your preferred language e.g., C#, Java, Php, and Python.

Supporting files for C#, Java, Php, and Python examples are available at GitHub. You can clone each repository or repurpose snippets as needed.

using System;
using System.Linq;
using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.BingAds.V13.Reporting;
using Microsoft.BingAds;

namespace BingAdsExamplesLibrary.V13
{
    /// <summary>
    /// How to request and retrieve performance reports with the Reporting service. 
    /// </summary>
    public class ReportRequests : ExampleBase
    {
        public static ReportingServiceManager ReportingServiceManager;
        
        /// <summary>
        /// The report file extension type.
        /// </summary>
        protected const ReportFormat ReportFileFormat = ReportFormat.Csv;
    
        /// <summary>
        /// The directory for the report file.
        /// </summary>
        protected const string FileDirectory = @"c:\reports\";

        /// <summary>
        /// The name of the report file.
        /// </summary>
        protected string ResultFileName = @"result." + ReportFileFormat.ToString().ToLower();

        /// <summary>
        /// The maximum amount of time (in milliseconds) that you want to wait for the report download.
        /// </summary>
        protected const int TimeoutInMilliseconds = 360000;
        
        public override string Description
        {
            get { return "Report Requests | Reporting V13"; }
        }

        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                ReportingServiceManager = new ReportingServiceManager(
                    authorizationData: authorizationData, 
                    apiEnvironment: environment);
                ReportingServiceManager.StatusPollIntervalInMilliseconds = 5000;

                // You can submit one of the example reports, or build your own.
                var reportRequest = GetReportRequest(authorizationData.AccountId);

                var reportingDownloadParameters = new ReportingDownloadParameters
                {
                    ReportRequest = reportRequest,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = ResultFileName,
                    OverwriteResultFile = true,
                };

                // Option A - Background Completion with ReportingServiceManager
                // You can submit a download request and the ReportingServiceManager will automatically 
                // return results. The ReportingServiceManager abstracts the details of checking for result file 
                // completion, and you don't have to write any code for results polling.

                //OutputStatusMessage("Awaiting Background Completion . . .");
                //await BackgroundCompletionAsync(reportingDownloadParameters);

                // Option B - Submit and Download with ReportingServiceManager
                // Submit the download request and then use the ReportingDownloadOperation result to 
                // track status until the report is complete e.g. either using
                // TrackAsync or GetStatusAsync.

                //OutputStatusMessage("Awaiting Submit and Download . . .");
                //await SubmitAndDownloadAsync(reportRequest);

                // Option C - Download Results with ReportingServiceManager
                // If for any reason you have to resume from a previous application state, 
                // you can use an existing download request identifier and use it 
                // to download the result file. 

                // For example you might have previously retrieved a request ID using SubmitDownloadAsync.
                //var reportingDownloadOperation = await ReportingServiceManager.SubmitDownloadAsync(reportRequest);
                //var requestId = reportingDownloadOperation.RequestId;

                // Given the request ID above, you can resume the workflow and download the report.
                // The report request identifier is valid for two days. 
                // If you do not download the report within two days, you must request the report again.
                //OutputStatusMessage("Awaiting Download Results . . .");
                //await DownloadResultsAsync(requestId, authorizationData);

                // Option D - Download the report in memory with ReportingServiceManager.DownloadReportAsync
                // The DownloadReportAsync helper function downloads the report and summarizes results.
                OutputStatusMessage("Awaiting DownloadReportAsync . . .");
                await DownloadReportAsync(reportingDownloadParameters);

            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Reporting service exceptions
            catch (FaultException<Microsoft.BingAds.V13.Reporting.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V13.Reporting.ApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(String.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (ReportingOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the reporting operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (ReportingOperationCouldNotBeCompletedException ex)
            {
                OutputStatusMessage(string.Format("ReportingOperationCouldNotBeCompletedException Message: {0}", ex.Message));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }

        /// <summary>
        /// You can submit a download request and the ReportingServiceManager will automatically
        /// return results. The ReportingServiceManager abstracts the details of checking for result file
        /// completion, and you don't have to write any code for results polling.
        /// </summary>
        /// <param name="reportingDownloadParameters">Includes the report request type, aggregation, time period, and result file path.</param>
        private async Task BackgroundCompletionAsync(ReportingDownloadParameters reportingDownloadParameters)
        {
            // You may optionally cancel the DownloadFileAsync operation after a specified time interval. 
            var tokenSource = new CancellationTokenSource();
            tokenSource.CancelAfter(TimeoutInMilliseconds);

            var resultFilePath = await ReportingServiceManager.DownloadFileAsync(reportingDownloadParameters, tokenSource.Token);
            OutputStatusMessage(string.Format("Download result file: {0}\n", resultFilePath));
        }

        /// <summary>
        /// Submit the download request and then use the ReportingDownloadOperation result to 
        /// track status until the report is complete e.g. either using
        /// TrackAsync or GetStatusAsync.
        /// </summary>
        /// <param name="reportRequest">Includes the report request type, aggregation, and time period.</param>
        /// <returns></returns>
        private async Task SubmitAndDownloadAsync(ReportRequest reportRequest)
        {
            // You may optionally cancel the TrackAsync operation after a specified time interval.  
            var tokenSource = new CancellationTokenSource();
            tokenSource.CancelAfter(TimeoutInMilliseconds);

            var reportingDownloadOperation = await ReportingServiceManager.SubmitDownloadAsync(reportRequest);

            ReportingOperationStatus reportingOperationStatus = await reportingDownloadOperation.TrackAsync(tokenSource.Token);
            
            // You can use TrackAsync to poll until complete as shown above, 
            // or use custom polling logic with GetStatusAsync as shown below.

            //ReportingOperationStatus reportingOperationStatus;

            //var waitTime = new TimeSpan(0, 0, 5);
            //for (int i = 0; i < 24; i++)
            //{
            //    Thread.Sleep(waitTime);

            //    reportingOperationStatus = await reportingDownloadOperation.GetStatusAsync();

            //    if (reportingOperationStatus.Status == ReportRequestStatusType.Success)
            //    {
            //        break;
            //    }
            //}

            var resultFilePath = await reportingDownloadOperation.DownloadResultFileAsync(
                localResultDirectoryName: FileDirectory,
                localResultFileName: ResultFileName,
                decompress: true,
                overwrite: true);   // Set this value true if you want to overwrite the same file.

            OutputStatusMessage(string.Format("Download result file: {0}\n", resultFilePath));
        }

        /// <summary>
        /// If for any reason you have to resume from a previous application state, 
        /// you can use an existing download request identifier and use it 
        /// to download the result file. Use TrackAsync to indicate that the application 
        /// should wait to ensure that the download status is completed.
        /// </summary>
        /// <param name="requestId">A previous report request ID returned by the Reporting service.</param>
        /// <param name="authorizationData">The user's credentials paired with your developer token.</param>
        /// <returns></returns>
        private async Task DownloadResultsAsync(
            string requestId,
            AuthorizationData authorizationData)
        {
            // You may optionally cancel the TrackAsync operation after a specified time interval. 
            var tokenSource = new CancellationTokenSource();
            tokenSource.CancelAfter(TimeoutInMilliseconds);

            var reportingDownloadOperation = new ReportingDownloadOperation(requestId, authorizationData);

            // Use TrackAsync to indicate that the application should wait to ensure that 
            // the download status is completed.
            var reportingOperationStatus = await reportingDownloadOperation.TrackAsync(tokenSource.Token);

            var resultFilePath = await reportingDownloadOperation.DownloadResultFileAsync(
                localResultDirectoryName: FileDirectory,
                localResultFileName: ResultFileName,
                decompress: true,
                overwrite: true);   // Set this value true if you want to overwrite the same file.

            OutputStatusMessage(string.Format("Download result file: {0}", resultFilePath));
            OutputStatusMessage(string.Format("Status: {0}", reportingOperationStatus.Status));
            OutputStatusMessage(string.Format("TrackingId: {0}\n", reportingOperationStatus.TrackingId));
        }
        
        /// <summary>
        /// Download a report file and store the contents in-memory. 
        /// </summary>
        /// <param name="reportingDownloadParameters">Includes the report request type, aggregation, time period, and result file path.</param>
        /// <returns></returns>
        private async Task DownloadReportAsync(ReportingDownloadParameters reportingDownloadParameters)
        {
            // You can get a Report object by submitting a new download request via ReportingServiceManager. 
            // Although in this case you won�t work directly with the file, under the covers a request is 
            // submitted to the Reporting service and the report file is downloaded to a local directory. 

            Report reportContainer = (await ReportingServiceManager.DownloadReportAsync(
                parameters: reportingDownloadParameters,
                cancellationToken: CancellationToken.None));

            // Otherwise if you already have a report file that was downloaded via the API, 
            // you can get a Report object via the ReportFileReader. 

            //ReportFileReader reader = new ReportFileReader(
            //    reportingDownloadParameters.ResultFileDirectory + reportingDownloadParameters.ResultFileName,
            //    (ReportFormat)reportingDownloadParameters.ReportRequest.Format);
            //Report reportContainer = reader.GetReport();

            if(reportContainer == null)
            {
                OutputStatusMessage("There is no data for the submitted report request parameters.");
                return;
            }

            // Once you have a Report object via either workflow above, you can access the metadata and report records. 

            // Output the report metadata

            long recordCount = reportContainer.ReportRecordCount;
            OutputStatusMessage(string.Format("ReportName: {0}", reportContainer.ReportName));
            OutputStatusMessage(string.Format("ReportTimeStart: {0}", reportContainer.ReportTimeStart));
            OutputStatusMessage(string.Format("ReportTimeEnd: {0}", reportContainer.ReportTimeEnd));
            OutputStatusMessage(string.Format("LastCompletedAvailableDate: {0}", reportContainer.LastCompletedAvailableDate.ToString()));
            OutputStatusMessage(string.Format("ReportAggregation: {0}", reportContainer.ReportAggregation.ToString()));
            OutputStatusMessage(string.Format("ReportColumns: {0}", string.Join("; ", reportContainer.ReportColumns)));
            OutputStatusMessage(string.Format("ReportRecordCount: {0}", recordCount));

            // Analyze and output performance statistics

            IEnumerable<IReportRecord> reportRecordIterable = reportContainer.GetReportRecords();

            int totalImpressions = 0;
            int totalClicks = 0;
            HashSet<string> distinctDevices = new HashSet<string>();
            HashSet<string> distinctNetworks = new HashSet<string>();
            foreach (IReportRecord record in reportContainer.GetReportRecords())
            {
                totalImpressions += record.GetIntegerValue("Impressions");
                totalClicks += record.GetIntegerValue("Clicks");
                distinctDevices.Add(record.GetStringValue("DeviceType"));
                distinctNetworks.Add(record.GetStringValue("Network"));
            }

            OutputStatusMessage(String.Format("Total Impressions: {0}", totalImpressions));
            OutputStatusMessage(string.Format("Total Clicks: {0}", totalClicks));
            OutputStatusMessage(string.Format("Average Impressions: {0}", totalImpressions * 1.0 / recordCount));
            OutputStatusMessage(string.Format("Average Clicks: {0}", totalClicks * 1.0 / recordCount));
            OutputStatusMessage(string.Format("Distinct Devices: {0}", string.Join("; ", distinctDevices)));
            OutputStatusMessage(string.Format("Distinct Networks: {0}", string.Join("; ", distinctNetworks)));
            
            // Be sure to close the report before you attempt to clean up files within the working directory.

            reportContainer.Dispose();

            // The CleanupTempFiles method removes all files (not sub-directories) within the working
            //  directory, whether or not the files were created by this ReportingServiceManager instance. 
            // If you are using a cloud service such as Microsoft Azure you'll want to ensure you do not
            // exceed the file or directory limits. 

            //ReportingServiceManager.CleanupTempFiles();
        }
                
        private ReportRequest GetReportRequest(
            long accountId)
        {
            var aggregation = ReportAggregation.Daily;
            var excludeColumnHeaders = false;
            var excludeReportFooter = false;
            var excludeReportHeader = false;
            var time = new ReportTime
            {
                // You can either use a custom date range or predefined time.
                CustomDateRangeEnd = null,
                CustomDateRangeStart = null,
                PredefinedTime = ReportTimePeriod.Yesterday,
                ReportTimeZone = ReportTimeZone.PacificTimeUSCanadaTijuana
            };
            var returnOnlyCompleteData = false;

            var accountPerformanceReportRequest = GetAccountPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var adGroupPerformanceReportRequest = GetAdGroupPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var adPerformanceReportRequest = GetAdPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var ageGenderAudienceReportRequest = GetAgeGenderAudienceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var audiencePerformanceReportRequest = GetAudiencePerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var budgetSummaryReportRequest = GetBudgetSummaryReportRequest(
                    accountId: accountId,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var campaignPerformanceReportRequest = GetCampaignPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var keywordPerformanceReportRequest = GetKeywordPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            // NegativeKeywordConflictReportRequest does not contain a definition for Aggregation.
            // NegativeKeywordConflictReportRequest does not contain a definition for Time.
            var negativeKeywordConflictReportRequest = GetNegativeKeywordConflictReportRequest(
                    accountId: accountId,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var productDimensionPerformanceReportRequest = GetProductDimensionPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            // ProductMatchCountReportRequest does not contain a definition for Filter.
            var productMatchCountReportRequest = GetProductMatchCountReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var productPartitionPerformanceReportRequest = GetProductPartitionPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            // ProductSearchQueryPerformanceReportRequest does not contain a definition for Filter.
            var productSearchQueryPerformanceReportRequest = GetProductSearchQueryPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var productPartitionUnitPerformanceReportRequest = GetProductPartitionUnitPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            // SearchCampaignChangeHistoryReportRequest does not contain a definition for Aggregation.
            var searchCampaignChangeHistoryReportRequest = GetSearchCampaignChangeHistoryReportRequest(
                    accountId: accountId,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);
            var searchQueryPerformanceReportRequest = GetSearchQueryPerformanceReportRequest(
                    accountId: accountId,
                    aggregation: aggregation,
                    excludeColumnHeaders: excludeColumnHeaders,
                    excludeReportFooter: excludeReportFooter,
                    excludeReportHeader: excludeReportHeader,
                    format: ReportFileFormat,
                    returnOnlyCompleteData: returnOnlyCompleteData,
                    time: time);

            // Return one of the above report types
            return campaignPerformanceReportRequest;
        }

        private ReportRequest GetAccountPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new AccountPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,                
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Account Performance Report",
                Scope = new AccountReportScope
                {
                    AccountIds = new[] { accountId }
                },
                Filter = new AccountPerformanceReportFilter { }, 
                Columns = new[]
                {
                    AccountPerformanceReportColumn.TimePeriod,
                    AccountPerformanceReportColumn.AccountId,
                    AccountPerformanceReportColumn.DeviceType,
                    AccountPerformanceReportColumn.BidMatchType,
                    AccountPerformanceReportColumn.Revenue,
                    AccountPerformanceReportColumn.Assists,
                    AccountPerformanceReportColumn.DeliveredMatchType,
                    AccountPerformanceReportColumn.AveragePosition,
                    AccountPerformanceReportColumn.Conversions,
                    AccountPerformanceReportColumn.AdDistribution,
                    AccountPerformanceReportColumn.Network,
                    AccountPerformanceReportColumn.Clicks,
                    AccountPerformanceReportColumn.Impressions,
                    AccountPerformanceReportColumn.Ctr,
                    AccountPerformanceReportColumn.AverageCpc,
                    AccountPerformanceReportColumn.ImpressionSharePercent,
                    AccountPerformanceReportColumn.Spend,
                },
            };

            return report;
        }

        private ReportRequest GetAdGroupPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new AdGroupPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Ad Group Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new AdGroupPerformanceReportFilter { },
                Columns = new[]
                {
                    AdGroupPerformanceReportColumn.TimePeriod,
                    AdGroupPerformanceReportColumn.AccountId,
                    AdGroupPerformanceReportColumn.CampaignId,
                    AdGroupPerformanceReportColumn.DeviceType,
                    AdGroupPerformanceReportColumn.BidMatchType,
                    AdGroupPerformanceReportColumn.QualityScore,
                    AdGroupPerformanceReportColumn.AdRelevance,
                    AdGroupPerformanceReportColumn.LandingPageExperience,
                    AdGroupPerformanceReportColumn.Revenue,
                    AdGroupPerformanceReportColumn.Assists,
                    AdGroupPerformanceReportColumn.ExpectedCtr,
                    AdGroupPerformanceReportColumn.DeliveredMatchType,
                    AdGroupPerformanceReportColumn.AveragePosition,
                    AdGroupPerformanceReportColumn.Conversions,
                    AdGroupPerformanceReportColumn.AdDistribution,
                    AdGroupPerformanceReportColumn.Network,
                    AdGroupPerformanceReportColumn.Clicks,
                    AdGroupPerformanceReportColumn.Impressions,
                    AdGroupPerformanceReportColumn.Ctr,
                    AdGroupPerformanceReportColumn.AverageCpc,
                    AdGroupPerformanceReportColumn.Spend,
                },
            };

            return report;
        }

        private ReportRequest GetAdPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new AdPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Ad Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new AdPerformanceReportFilter { },
                Columns = new[]
                {
                    AdPerformanceReportColumn.TimePeriod,
                    AdPerformanceReportColumn.AccountName,
                    AdPerformanceReportColumn.AccountNumber,
                    AdPerformanceReportColumn.AdGroupId,
                    AdPerformanceReportColumn.AdGroupName,
                    AdPerformanceReportColumn.AdGroupStatus,
                    AdPerformanceReportColumn.AdId,
                    AdPerformanceReportColumn.Assists,
                    AdPerformanceReportColumn.CampaignName,
                    AdPerformanceReportColumn.Language,
                    AdPerformanceReportColumn.Spend,
                    AdPerformanceReportColumn.Impressions,
                    AdPerformanceReportColumn.Clicks,
                    AdPerformanceReportColumn.Spend
                },
            };
        }

        private ReportRequest GetAgeGenderAudienceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new AgeGenderAudienceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Age Gender Audience Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new AgeGenderAudienceReportFilter { },
                Columns = new[]
                {
                    AgeGenderAudienceReportColumn.TimePeriod,
                    AgeGenderAudienceReportColumn.AccountName,
                    AgeGenderAudienceReportColumn.AccountNumber,
                    AgeGenderAudienceReportColumn.AdGroupId,
                    AgeGenderAudienceReportColumn.AdGroupName,
                    AgeGenderAudienceReportColumn.AdGroupStatus,
                    AgeGenderAudienceReportColumn.AgeGroup,
                    AgeGenderAudienceReportColumn.Assists,
                    AgeGenderAudienceReportColumn.CampaignName,
                    AgeGenderAudienceReportColumn.Language,
                    AgeGenderAudienceReportColumn.Spend,
                    AgeGenderAudienceReportColumn.Impressions,
                    AgeGenderAudienceReportColumn.Clicks,
                    AgeGenderAudienceReportColumn.Spend
                },
            };
        }

        private ReportRequest GetAudiencePerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new AudiencePerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Audience Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new AudiencePerformanceReportFilter { },
                Columns = new[]
                {
                    AudiencePerformanceReportColumn.TimePeriod,
                    AudiencePerformanceReportColumn.AccountId,
                    AudiencePerformanceReportColumn.CampaignId,
                    AudiencePerformanceReportColumn.AudienceId,
                    AudiencePerformanceReportColumn.AudienceName,
                    AudiencePerformanceReportColumn.BidAdjustment,
                    AudiencePerformanceReportColumn.TargetingSetting,
                    AudiencePerformanceReportColumn.Clicks,
                    AudiencePerformanceReportColumn.Impressions,
                    AudiencePerformanceReportColumn.Ctr,
                    AudiencePerformanceReportColumn.AverageCpc,
                    AudiencePerformanceReportColumn.Spend,
                },
            };
        }

        private ReportRequest GetBudgetSummaryReportRequest(
            long accountId,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new BudgetSummaryReportRequest
            {
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Budget Summary Report",                
                Scope = new AccountThroughCampaignReportScope
                {
                    AccountIds = new[] { accountId }
                }, 
                Columns = new[]
                {
                    BudgetSummaryReportColumn.Date,
                    BudgetSummaryReportColumn.MonthlyBudget,
                    BudgetSummaryReportColumn.DailySpend,
                    BudgetSummaryReportColumn.MonthToDateSpend,
                    BudgetSummaryReportColumn.AccountId,
                    BudgetSummaryReportColumn.AccountName,
                    BudgetSummaryReportColumn.AccountNumber,
                    BudgetSummaryReportColumn.CampaignId,
                    BudgetSummaryReportColumn.CampaignName,
                    BudgetSummaryReportColumn.CurrencyCode,
                },
            };

            return report;
        }

        private ReportRequest GetCampaignPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new CampaignPerformanceReportRequest
            {
                Aggregation = ReportAggregation.Hourly, //aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Campaign Performance Report",
                Scope = new AccountThroughCampaignReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null
                },
                Filter = new CampaignPerformanceReportFilter { },
                Columns = new[]
                {
                    CampaignPerformanceReportColumn.TimePeriod,
                    CampaignPerformanceReportColumn.AccountId,
                    CampaignPerformanceReportColumn.CampaignId,
                    CampaignPerformanceReportColumn.CampaignName,
                    CampaignPerformanceReportColumn.CampaignStatus,
                    CampaignPerformanceReportColumn.DeviceType,
                    CampaignPerformanceReportColumn.BidMatchType,
                    CampaignPerformanceReportColumn.QualityScore,
                    CampaignPerformanceReportColumn.AdRelevance,
                    CampaignPerformanceReportColumn.LandingPageExperience,
                    CampaignPerformanceReportColumn.Revenue,
                    CampaignPerformanceReportColumn.Assists,
                    CampaignPerformanceReportColumn.ExpectedCtr,
                    CampaignPerformanceReportColumn.DeliveredMatchType,
                    CampaignPerformanceReportColumn.AveragePosition,
                    CampaignPerformanceReportColumn.Conversions,
                    CampaignPerformanceReportColumn.AdDistribution,
                    CampaignPerformanceReportColumn.Network,
                    CampaignPerformanceReportColumn.Clicks,
                    CampaignPerformanceReportColumn.Impressions,
                    CampaignPerformanceReportColumn.Ctr,
                    CampaignPerformanceReportColumn.AverageCpc,
                    CampaignPerformanceReportColumn.Spend,
                    CampaignPerformanceReportColumn.LowQualityClicks,
                    CampaignPerformanceReportColumn.LowQualityConversionRate
                },
            };

            return report;
        }

        private KeywordPerformanceReportRequest GetKeywordPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new KeywordPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Keyword Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new KeywordPerformanceReportFilter { },
                Columns = new[]
                {
                    KeywordPerformanceReportColumn.TimePeriod,
                    KeywordPerformanceReportColumn.AccountId,
                    KeywordPerformanceReportColumn.CampaignId,
                    KeywordPerformanceReportColumn.Keyword,
                    KeywordPerformanceReportColumn.KeywordId,
                    KeywordPerformanceReportColumn.DeviceType,
                    KeywordPerformanceReportColumn.BidMatchType,
                    KeywordPerformanceReportColumn.Clicks,
                    KeywordPerformanceReportColumn.Impressions,
                    KeywordPerformanceReportColumn.Ctr,
                    KeywordPerformanceReportColumn.AverageCpc,
                    KeywordPerformanceReportColumn.Spend,
                    KeywordPerformanceReportColumn.QualityScore,
                    KeywordPerformanceReportColumn.AdRelevance,
                    KeywordPerformanceReportColumn.LandingPageExperience,
                    KeywordPerformanceReportColumn.Revenue,
                    KeywordPerformanceReportColumn.Assists,
                    KeywordPerformanceReportColumn.ExpectedCtr,
                    KeywordPerformanceReportColumn.DeliveredMatchType,
                    KeywordPerformanceReportColumn.AveragePosition,
                    KeywordPerformanceReportColumn.Conversions,
                    KeywordPerformanceReportColumn.AdDistribution,
                    KeywordPerformanceReportColumn.Network,
                    KeywordPerformanceReportColumn.AdId,
                    KeywordPerformanceReportColumn.AdType,
                    KeywordPerformanceReportColumn.AdGroupId,
                },
            };

            return report;
        }

        private ReportRequest GetNegativeKeywordConflictReportRequest(
            long accountId,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new NegativeKeywordConflictReportRequest
            {
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                ReportName = "My Negative Keyword Conflict Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new NegativeKeywordConflictReportFilter { }, 
                Columns = new[]
                {
                    NegativeKeywordConflictReportColumn.AccountName,
                    NegativeKeywordConflictReportColumn.CampaignName,
                    NegativeKeywordConflictReportColumn.ConflictLevel,
                    NegativeKeywordConflictReportColumn.ConflictType,
                    NegativeKeywordConflictReportColumn.AccountId,
                    NegativeKeywordConflictReportColumn.AccountNumber,
                    NegativeKeywordConflictReportColumn.AdGroupId,
                    NegativeKeywordConflictReportColumn.AdGroupName,
                    NegativeKeywordConflictReportColumn.CampaignId,
                    NegativeKeywordConflictReportColumn.Keyword,
                    NegativeKeywordConflictReportColumn.NegativeKeyword,
                },
            };
        }
        
        private ReportRequest GetProductDimensionPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new ProductDimensionPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Product Dimension Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    AdGroups = null,
                    Campaigns = null
                },
                Filter = new ProductDimensionPerformanceReportFilter { },                
                Columns = new[]
                {
                    ProductDimensionPerformanceReportColumn.TimePeriod,
                    ProductDimensionPerformanceReportColumn.MerchantProductId,
                    ProductDimensionPerformanceReportColumn.AccountName,
                    ProductDimensionPerformanceReportColumn.AccountNumber,
                    ProductDimensionPerformanceReportColumn.AdGroupId,
                    ProductDimensionPerformanceReportColumn.AdGroupName,
                    ProductDimensionPerformanceReportColumn.AdId,
                    ProductDimensionPerformanceReportColumn.AverageCpc,
                    ProductDimensionPerformanceReportColumn.Brand,
                    ProductDimensionPerformanceReportColumn.CampaignName,
                    ProductDimensionPerformanceReportColumn.Condition,
                    ProductDimensionPerformanceReportColumn.Ctr,
                    ProductDimensionPerformanceReportColumn.CurrencyCode,
                    ProductDimensionPerformanceReportColumn.CustomLabel0,
                    ProductDimensionPerformanceReportColumn.CustomLabel1,
                    ProductDimensionPerformanceReportColumn.CustomLabel2,
                    ProductDimensionPerformanceReportColumn.CustomLabel3,
                    ProductDimensionPerformanceReportColumn.CustomLabel4,
                    ProductDimensionPerformanceReportColumn.DeviceType,
                    ProductDimensionPerformanceReportColumn.Language,
                    ProductDimensionPerformanceReportColumn.ProductCategory1,
                    ProductDimensionPerformanceReportColumn.ProductCategory2,
                    ProductDimensionPerformanceReportColumn.ProductCategory3,
                    ProductDimensionPerformanceReportColumn.ProductCategory4,
                    ProductDimensionPerformanceReportColumn.ProductCategory5,
                    ProductDimensionPerformanceReportColumn.ProductType1,
                    ProductDimensionPerformanceReportColumn.ProductType2,
                    ProductDimensionPerformanceReportColumn.ProductType3,
                    ProductDimensionPerformanceReportColumn.ProductType4,
                    ProductDimensionPerformanceReportColumn.ProductType5,
                    ProductDimensionPerformanceReportColumn.Spend,
                    ProductDimensionPerformanceReportColumn.Title,
                    ProductDimensionPerformanceReportColumn.Impressions,
                    ProductDimensionPerformanceReportColumn.Clicks,
                    ProductDimensionPerformanceReportColumn.Spend
                },
            };
        }

        private ReportRequest GetProductMatchCountReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new ProductMatchCountReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Product Match Count Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    AdGroups = null,
                    Campaigns = null
                },
                Columns = new[]
                {
                    ProductMatchCountReportColumn.AccountName,
                    ProductMatchCountReportColumn.CampaignName,
                    ProductMatchCountReportColumn.AdGroupCriterionId,
                    ProductMatchCountReportColumn.AccountId,
                    ProductMatchCountReportColumn.AccountNumber,
                    ProductMatchCountReportColumn.AdGroupId,
                    ProductMatchCountReportColumn.AdGroupName,
                    ProductMatchCountReportColumn.CampaignId,
                    ProductMatchCountReportColumn.CustomerId,
                    ProductMatchCountReportColumn.CustomerName,
                    ProductMatchCountReportColumn.MatchedProductsAtAdGroup,
                    ProductMatchCountReportColumn.MatchedProductsAtCampaign,
                    ProductMatchCountReportColumn.MatchedProductsAtProductGroup,
                    ProductMatchCountReportColumn.PartitionType,
                    ProductMatchCountReportColumn.ProductGroup
                },
            };
        }

        private ReportRequest GetProductPartitionPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new ProductPartitionPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Product Partition Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    AdGroups = null,
                    Campaigns = null
                },
                Filter = new ProductPartitionPerformanceReportFilter { },
                Columns = new[]
                {
                    ProductPartitionPerformanceReportColumn.TimePeriod,
                    ProductPartitionPerformanceReportColumn.AccountId,
                    ProductPartitionPerformanceReportColumn.CampaignId,
                    ProductPartitionPerformanceReportColumn.AdGroupCriterionId,
                    ProductPartitionPerformanceReportColumn.ProductGroup,
                    ProductPartitionPerformanceReportColumn.PartitionType,
                    ProductPartitionPerformanceReportColumn.BidMatchType,
                    ProductPartitionPerformanceReportColumn.Clicks,
                    ProductPartitionPerformanceReportColumn.Impressions,
                    ProductPartitionPerformanceReportColumn.Ctr,
                    ProductPartitionPerformanceReportColumn.AverageCpc,
                    ProductPartitionPerformanceReportColumn.Spend,
                },
            };
        }

        private ReportRequest GetProductPartitionUnitPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            return new ProductPartitionUnitPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Product Partition Unit Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    AdGroups = null,
                    Campaigns = null
                },
                Filter = new ProductPartitionUnitPerformanceReportFilter { },
                Columns = new[]
                {
                    ProductPartitionUnitPerformanceReportColumn.TimePeriod,
                    ProductPartitionUnitPerformanceReportColumn.AccountId,
                    ProductPartitionUnitPerformanceReportColumn.CampaignId,
                    ProductPartitionUnitPerformanceReportColumn.AdGroupCriterionId,
                    ProductPartitionUnitPerformanceReportColumn.ProductGroup,
                    ProductPartitionUnitPerformanceReportColumn.BidMatchType,
                    ProductPartitionUnitPerformanceReportColumn.Clicks,
                    ProductPartitionUnitPerformanceReportColumn.Impressions,
                    ProductPartitionUnitPerformanceReportColumn.Ctr,
                    ProductPartitionUnitPerformanceReportColumn.AverageCpc,
                    ProductPartitionUnitPerformanceReportColumn.Spend,
                },
            };
        }

        private ReportRequest GetProductSearchQueryPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new ProductSearchQueryPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Product Search Query Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Columns = new[]
                {
                    ProductSearchQueryPerformanceReportColumn.TimePeriod,
                    ProductSearchQueryPerformanceReportColumn.AccountId,
                    ProductSearchQueryPerformanceReportColumn.CampaignName,
                    ProductSearchQueryPerformanceReportColumn.AccountName,
                    ProductSearchQueryPerformanceReportColumn.AccountNumber,
                    ProductSearchQueryPerformanceReportColumn.AdGroupCriterionId,
                    ProductSearchQueryPerformanceReportColumn.CampaignId,
                    ProductSearchQueryPerformanceReportColumn.DeviceType,
                    ProductSearchQueryPerformanceReportColumn.PartitionType,
                    ProductSearchQueryPerformanceReportColumn.ProductGroup,
                    ProductSearchQueryPerformanceReportColumn.SearchQuery,
                    ProductSearchQueryPerformanceReportColumn.Revenue,
                    ProductSearchQueryPerformanceReportColumn.Assists,
                    ProductSearchQueryPerformanceReportColumn.Conversions,
                    ProductSearchQueryPerformanceReportColumn.Network,
                    ProductSearchQueryPerformanceReportColumn.Clicks,
                    ProductSearchQueryPerformanceReportColumn.Impressions,
                    ProductSearchQueryPerformanceReportColumn.Ctr,
                    ProductSearchQueryPerformanceReportColumn.AverageCpc,
                    ProductSearchQueryPerformanceReportColumn.Spend,
                    ProductSearchQueryPerformanceReportColumn.MerchantProductId
                },

            };

            return report;
        }
        
        private ReportRequest GetSearchCampaignChangeHistoryReportRequest(
            long accountId,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        { 
            var report = new SearchCampaignChangeHistoryReportRequest
            {
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Search Campaign Change History Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    Campaigns = null,
                    AdGroups = null
                },
                Filter = new SearchCampaignChangeHistoryReportFilter { },
                Columns = new[]
                {
                    SearchCampaignChangeHistoryReportColumn.DateTime,
                    SearchCampaignChangeHistoryReportColumn.AccountId,
                    SearchCampaignChangeHistoryReportColumn.AdGroupId,
                    SearchCampaignChangeHistoryReportColumn.AdGroupName,
                    SearchCampaignChangeHistoryReportColumn.AdTitle,
                    SearchCampaignChangeHistoryReportColumn.AttributeChanged,
                    SearchCampaignChangeHistoryReportColumn.CampaignId,
                    SearchCampaignChangeHistoryReportColumn.CampaignName,
                    SearchCampaignChangeHistoryReportColumn.ChangedBy,
                    SearchCampaignChangeHistoryReportColumn.DisplayUrl,
                    SearchCampaignChangeHistoryReportColumn.HowChanged,
                    SearchCampaignChangeHistoryReportColumn.ItemChanged,
                    SearchCampaignChangeHistoryReportColumn.Keyword,
                    SearchCampaignChangeHistoryReportColumn.NewValue,
                    SearchCampaignChangeHistoryReportColumn.OldValue,
                },                
            };

            return report;
        }

        private ReportRequest GetSearchQueryPerformanceReportRequest(
            long accountId,
            ReportAggregation aggregation,
            bool excludeColumnHeaders,
            bool excludeReportFooter,
            bool excludeReportHeader,
            ReportFormat format,
            bool returnOnlyCompleteData,
            ReportTime time)
        {
            var report = new SearchQueryPerformanceReportRequest
            {
                Aggregation = aggregation,
                ExcludeColumnHeaders = excludeColumnHeaders,
                ExcludeReportFooter = excludeReportFooter,
                ExcludeReportHeader = excludeReportHeader,
                Format = format,
                ReturnOnlyCompleteData = returnOnlyCompleteData,
                Time = time,
                ReportName = "My Search Query Performance Report",
                Scope = new AccountThroughAdGroupReportScope
                {
                    AccountIds = new[] { accountId },
                    AdGroups = null,
                    Campaigns = null
                },
                Filter = new SearchQueryPerformanceReportFilter { },
                Columns = new[]
                {
                    SearchQueryPerformanceReportColumn.TimePeriod,
                    SearchQueryPerformanceReportColumn.AccountId,
                    SearchQueryPerformanceReportColumn.CampaignId,
                    SearchQueryPerformanceReportColumn.DeviceType,
                    SearchQueryPerformanceReportColumn.BidMatchType,
                    SearchQueryPerformanceReportColumn.CampaignType,
                    SearchQueryPerformanceReportColumn.SearchQuery,
                    SearchQueryPerformanceReportColumn.Revenue,
                    SearchQueryPerformanceReportColumn.Assists,
                    SearchQueryPerformanceReportColumn.DeliveredMatchType,
                    SearchQueryPerformanceReportColumn.AveragePosition,
                    SearchQueryPerformanceReportColumn.Conversions,
                    SearchQueryPerformanceReportColumn.Network,
                    SearchQueryPerformanceReportColumn.Clicks,
                    SearchQueryPerformanceReportColumn.Impressions,
                    SearchQueryPerformanceReportColumn.Ctr,
                    SearchQueryPerformanceReportColumn.AverageCpc,
                    SearchQueryPerformanceReportColumn.Spend,
                },
            };

            return report;
        }
    }
}
package com.microsoft.bingads.examples.v13;

import com.microsoft.bingads.v13.reporting.*;
import com.microsoft.bingads.v13.reporting.Report;
import com.microsoft.bingads.v13.reporting.ReportingDownloadOperation; 
import com.microsoft.bingads.v13.reporting.ReportingOperationStatus;
import com.microsoft.bingads.v13.reporting.ReportingDownloadParameters; 
import com.microsoft.bingads.v13.reporting.ReportRecord;

import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.HashSet;
import java.util.Objects;
import java.net.*;
import java.io.*;

import javax.xml.stream.XMLStreamException;

import org.apache.commons.text.WordUtils;
import org.apache.commons.lang3.StringUtils;

public class ReportRequests extends ExampleBase {

    static ReportingServiceManager ReportingServiceManager; 
        
    // The reportRequest file extension type.
    final static ReportFormat ReportFileFormat = ReportFormat.CSV; 
    
    // The directory for the reportRequest file.
    static java.lang.String FileDirectory = "c:\\reports\\";

    // The name of the reportRequest file.
    static java.lang.String ResultFileName = "result." + ReportFileFormat.toString().toLowerCase();    
    
    // The maximum amount of time (in milliseconds) that you want to wait for the reportRequest download.
    static int TimeoutInMilliseconds = 3600000;
  
    public static void main(String[] args) {

        // Confirm that the download folder exists; otherwise, exit.
        
        String folder = FileDirectory.substring(0, FileDirectory.lastIndexOf('\\'));
        File dir = new File(folder);

        if (!dir.exists())
        {
            System.out.println("The output folder does not exist. Ensure that the folder exists and try again.");
            return;
        }

        try
        {            
            authorizationData = getAuthorizationData();
            
            ReportingServiceManager = new ReportingServiceManager(authorizationData, API_ENVIRONMENT);
            ReportingServiceManager.setStatusPollIntervalInMilliseconds(5000);

            // You can submit one of the example reports, or build your own.
            ReportRequest reportRequest = getReportRequest(authorizationData.getAccountId());

            ReportingDownloadParameters reportingDownloadParameters = new ReportingDownloadParameters();
            reportingDownloadParameters.setReportRequest(reportRequest);
            reportingDownloadParameters.setResultFileDirectory(new File(FileDirectory));
            reportingDownloadParameters.setResultFileName(ResultFileName);
            reportingDownloadParameters.setOverwriteResultFile(true);
            
            // Option A - Background Completion with ReportingServiceManager
            // You can submit a download request and the ReportingServiceManager will automatically 
            // return results. The ReportingServiceManager abstracts the details of checking for result file 
            // completion, and you don't have to write any code for results polling.

//            outputStatusMessage("Awaiting Background Completion . . .");
//            backgroundCompletionAsync(reportingDownloadParameters);

            // Option B - Submit and Download with ReportingServiceManager
            // Submit the download request and then use the ReportingDownloadOperation result to 
            // track status until the download is complete e.g. either using
            // trackAsync or getStatusAsync.

//            outputStatusMessage("Awaiting Submit and Download . . .");
//            submitAndDownloadAsync(reportRequest);

            // Option C - Download Results with ReportingServiceManager
            // If for any reason you have to resume from a previous application state, 
            // you can use an existing download request identifier and use it 
            // to download the result file. Use trackAsync to indicate that the application 
            // should wait to ensure that the download status is completed.

            // For example you might have previously retrieved a request ID using submitDownloadAsync.
//            ReportingDownloadOperation reportingDownloadOperation = ReportingServiceManager.submitDownloadAsync(reportRequest, null).get();
//            java.lang.String requestId = reportingDownloadOperation.getRequestId();

            // Given the request ID above, you can resume the workflow and download the reportRequest.
            // The reportRequest request identifier is valid for two days. 
            // If you do not download the reportRequest within two days, you must request it again.
//            outputStatusMessage("Awaiting Download Results . . .");
//            downloadResultsAsync(requestId);

            // Option D - Download the reportRequest in memory with ReportingServiceManager.downloadReportAsync
            // The downloadReportAsync helper function downloads the reportRequest and summarizes results.
            outputStatusMessage("Awaiting downloadReportAsync . . .");
            downloadReportAsync(reportingDownloadParameters);   
        } 
        catch (Exception ex) {
            String faultXml = ExampleExceptionHelper.getBingAdsExceptionFaultXml(ex, System.out);
            outputStatusMessage(faultXml);
            String message = ExampleExceptionHelper.handleBingAdsSDKException(ex, System.out);
            outputStatusMessage(message);
        }
    }
                    
    // You can submit a download request and the ReportingServiceManager will automatically 
    // return results. The ReportingServiceManager abstracts the details of checking for result file 
    // completion, and you don't have to write any code for results polling.
    private static void backgroundCompletionAsync(ReportingDownloadParameters reportingDownloadParameters) 
            throws ExecutionException, InterruptedException, TimeoutException {
        // You may optionally cancel the downloadFileAsync operation after a specified time interval.
        File resultFile = ReportingServiceManager.downloadFileAsync(
                        reportingDownloadParameters, 
                        null).get(TimeoutInMilliseconds, TimeUnit.MILLISECONDS);
        
        if(resultFile != null && !Objects.equals(resultFile.getName(), ""))
        {
            outputStatusMessage(String.format("Download result file: %s\n", resultFile.getName()));
        }
        else
        {
            outputStatusMessage("No report data for the submitted request\n");
        }
    }
    
    // Submit the download request and then use the ReportingDownloadOperation result to 
    // track status until the reportRequest is complete e.g. either using
    // trackAsync or getStatusAsync.
    private static void submitAndDownloadAsync(ReportRequest reportRequest) 
        throws ExecutionException, InterruptedException, URISyntaxException, IOException, TimeoutException {
        ReportingDownloadOperation reportingDownloadOperation = ReportingServiceManager.submitDownloadAsync(
                        reportRequest,
                        null).get();

        // You may optionally cancel the trackAsync operation after a specified time interval.
        ReportingOperationStatus reportingOperationStatus = 
                        reportingDownloadOperation.trackAsync(null).get(TimeoutInMilliseconds, TimeUnit.MILLISECONDS);

        // You can use trackAsync to poll until complete as shown above, 
        // or use custom polling logic with getStatusAsync as shown below.

//        ReportingOperationStatus reportingOperationStatus;
//
//        for (int i = 0; i < 24; i++)
//        {
//            Thread.sleep(5000);
//            reportingOperationStatus = reportingDownloadOperation.getStatusAsync(null).get(TimeoutInMilliseconds, TimeUnit.MILLISECONDS);
//            if (reportingOperationStatus.getStatus() == ReportRequestStatusType.SUCCESS)
//            {
//                break;
//            }
//        }

        File resultFile = reportingDownloadOperation.downloadResultFileAsync(
            new File(FileDirectory),
            ResultFileName,
            true, // Set this value to true if you want to decompress the ZIP file.
            true,  // Set this value true if you want to overwrite the named file.
            null).get();
    
        if(resultFile != null && !Objects.equals(resultFile.getName(), ""))
        {
            outputStatusMessage(String.format("Download result file: %s\n", resultFile.getName()));
        }
        else
        {
            outputStatusMessage("No report data for the submitted request\n");
        }
    }
    
    // If for any reason you have to resume from a previous application state, 
    // you can use an existing download request identifier and use it 
    // to download the result file. Use trackAsync to indicate that the application 
    // should wait to ensure that the download status is completed.
    private static void downloadResultsAsync(java.lang.String requestId) 
        throws ExecutionException, InterruptedException, URISyntaxException, IOException, TimeoutException {

        ReportingDownloadOperation reportingDownloadOperation = new ReportingDownloadOperation(requestId, authorizationData, API_ENVIRONMENT);

        reportingDownloadOperation.setStatusPollIntervalInMilliseconds(5000);

        // You can use trackAsync to poll until complete as shown here, 
        // or use custom polling logic with getStatusAsync.

        // You may optionally cancel the trackAsync operation after a specified time interval.
        ReportingOperationStatus reportingOperationStatus = reportingDownloadOperation.trackAsync(null)
                .get(TimeoutInMilliseconds, TimeUnit.MILLISECONDS);

        File resultFile = reportingDownloadOperation.downloadResultFileAsync(
            new File(FileDirectory),
            ResultFileName,
            true, // Set this value to true if you want to decompress the ZIP file
            true,  // Set this value true if you want to overwrite the named file.
            null).get();

        if(resultFile != null && !Objects.equals(resultFile.getName(), ""))
        {
            outputStatusMessage(String.format("Download result file: %s", resultFile.getName()));
            outputStatusMessage(String.format("Status: %s", reportingOperationStatus.getStatus()));
            outputStatusMessage(String.format("TrackingId: %s\n", reportingOperationStatus.getTrackingId()));
        }
        else
        {
            outputStatusMessage("No report data for the submitted request\n");
        }
    }
    
    // Download the reportRequest in memory with ReportingServiceManager.downloadReportAsync
    // The downloadReportAsync helper function downloads the reportRequest and summarizes results.
    static void downloadReportAsync(ReportingDownloadParameters reportingDownloadParameters) throws IOException, InterruptedException, ExecutionException, XMLStreamException, CouldNotGetReportingMetadataException, InvalidColumnException
    {
        // You can get a Report object by submitting a new download request via ReportingServiceManager. 
        // Although in this case you will not work directly with the file, under the covers a request is 
        // submitted to the Reporting service and the reportRequest file is downloaded to a local directory. 

        Report reportContainer = ReportingServiceManager.downloadReportAsync(
                reportingDownloadParameters, 
                null).get(); 

        // Otherwise if you already have a reportRequest file that was downloaded via the API, 
        // you can get a Report object via the ReportFileReader. 

//        ReportFileReader reader = new ReportFileReader(
//                reportingDownloadParameters.getResultFileDirectory() + "\\" + reportingDownloadParameters.getResultFileName(), 
//                reportingDownloadParameters.getReportRequest().getFormat());
//        Report reportContainer = reader.getReport();

        if(reportContainer == null)
        {
            outputStatusMessage("There is no report data for the submitted report request parameters.");
            return;
        }

        // Once you have a Report object via either workflow above, you can access the metadata and reportRequest records. 

        // Output the reportRequest metadata

        java.lang.Long recordCount = reportContainer.getReportRecordCount();
        outputStatusMessage(String.format("ReportName: %s", reportContainer.getReportName()));
        outputStatusMessage(String.format("ReportTimeStart: %s", reportContainer.getReportTimeStart()));
        outputStatusMessage(String.format("ReportTimeEnd: %s", reportContainer.getReportTimeEnd()));
        outputStatusMessage(String.format("LastCompletedAvailableDate: %s", reportContainer.getLastCompletedAvailableDate().toString()));
        outputStatusMessage(String.format("ReportAggregation: %s", enumCaseToPascalCase(reportContainer.getReportAggregation().toString())));
        outputStatusMessage(String.format("ReportColumns: %s", String.join("; ", reportContainer.getReportColumns())));
        outputStatusMessage(String.format("ReportRecordCount: %s", recordCount));

        // Analyze and output performance statistics
        
        if(Arrays.asList(reportContainer.getReportColumns()).contains("Impressions")){
            Iterable<ReportRecord> reportRecordIterable = reportContainer.getReportRecords();

            int totalImpressions = 0;
            int totalClicks = 0;
            HashSet<String> distinctDevices = new HashSet<>();
            HashSet<String> distinctNetworks = new HashSet<>();
            for (ReportRecord record : reportRecordIterable)
            {
                totalImpressions += record.getIntegerValue("Impressions");
                totalClicks += record.getIntegerValue("Clicks");
                distinctDevices.add(record.getStringValue("DeviceType"));
                distinctNetworks.add(record.getStringValue("Network"));
            }

            outputStatusMessage(String.format("Total Impressions: %s", totalImpressions));
            outputStatusMessage(String.format("Total Clicks: %s", totalClicks));
            outputStatusMessage(String.format("Average Impressions: %s", totalImpressions * 1.0 / recordCount));
            outputStatusMessage(String.format("Average Clicks: %s", totalClicks * 1.0 / recordCount));
            outputStatusMessage(String.format("Distinct Devices: %s", String.join("; ", distinctDevices)));
            outputStatusMessage(String.format("Distinct Networks: %s", String.join("; ", distinctNetworks)));
        }       

        // Be sure to close the reportRequest before you attempt to clean up files within the working directory.

        reportContainer.close();

        // The cleanupTempFiles method removes all files (not sub-directories) within the working
        // directory, whether or not the files were created by this ReportingServiceManager instance. 
        // If you are using a cloud service such as Microsoft Azure you'll want to ensure you do not
        // exceed the file or directory limits. 

        //ReportingServiceManager.cleanupTempFiles();
    }
        
    private static java.lang.String enumCaseToPascalCase(java.lang.String text) {
        return StringUtils.remove(WordUtils.capitalizeFully(text, '_'), "_");
    }
    
    private static ReportRequest getReportRequest(java.lang.Long accountId)
    {
        ReportAggregation aggregation = ReportAggregation.DAILY;
        java.lang.Boolean excludeColumnHeaders = false;
        java.lang.Boolean excludeReportFooter = false;
        java.lang.Boolean excludeReportHeader = false;
        ReportTime time = new ReportTime();
        // You can either use a custom date range or predefined time.
        time.setPredefinedTime(ReportTimePeriod.YESTERDAY);
        time.setReportTimeZone(ReportTimeZone.PACIFIC_TIME_US_CANADA_TIJUANA);
        java.lang.Boolean returnOnlyCompleteData = false;
        
        AdPerformanceReportRequest adPerformanceReportRequest = getAdPerformanceReportRequest(
            accountId,
            aggregation,
            excludeColumnHeaders,
            excludeReportFooter,
            excludeReportHeader,
            ReportFileFormat,
            returnOnlyCompleteData,
            time);
        
        KeywordPerformanceReportRequest keywordPerformanceReportRequest = getKeywordPerformanceReportRequest(
            accountId,
            aggregation,
            excludeColumnHeaders,
            excludeReportFooter,
            excludeReportHeader,
            ReportFileFormat,
            returnOnlyCompleteData,
            time);
                            
        return keywordPerformanceReportRequest;        
    }
    
    private static AdPerformanceReportRequest getAdPerformanceReportRequest(
            java.lang.Long accountId,
            ReportAggregation aggregation,
            java.lang.Boolean excludeColumnHeaders,
            java.lang.Boolean excludeReportFooter,
            java.lang.Boolean excludeReportHeader,
            ReportFormat format,
            java.lang.Boolean returnOnlyCompleteData,
            ReportTime time)
    {
        AdPerformanceReportRequest reportRequest = new AdPerformanceReportRequest();
        
        reportRequest.setAggregation(aggregation);
        reportRequest.setExcludeColumnHeaders(excludeColumnHeaders);
        reportRequest.setExcludeReportFooter(excludeReportFooter);
        reportRequest.setExcludeReportHeader(excludeReportHeader);
        reportRequest.setFormat(format);
        reportRequest.setReturnOnlyCompleteData(returnOnlyCompleteData);
        reportRequest.setTime(time);
        reportRequest.setReportName("My Ad Performance Report");
        ArrayOflong accountIds = new ArrayOflong();
        accountIds.getLongs().add(accountId);
        reportRequest.setScope(new AccountThroughAdGroupReportScope());
        reportRequest.getScope().setAccountIds(accountIds);
        reportRequest.getScope().setCampaigns(null);
        reportRequest.getScope().setAdGroups(null);        
        AdPerformanceReportFilter filter = new AdPerformanceReportFilter();
        reportRequest.setFilter(filter);
        ArrayOfAdPerformanceReportColumn adPerformanceReportColumns = new ArrayOfAdPerformanceReportColumn(); 
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.ACCOUNT_NAME);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.ACCOUNT_NUMBER);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.ACCOUNT_ID);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.TIME_PERIOD);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CAMPAIGN_NAME);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CAMPAIGN_ID);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_GROUP_NAME);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_GROUP_ID);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_ID);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_TYPE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.DESTINATION_URL);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CURRENCY_CODE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.DELIVERED_MATCH_TYPE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_DISTRIBUTION);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.IMPRESSIONS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CLICKS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CTR);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AVERAGE_CPC);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.SPEND);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AVERAGE_POSITION);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CONVERSIONS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CONVERSION_RATE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.COST_PER_CONVERSION);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.BID_MATCH_TYPE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.DEVICE_TYPE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.LANGUAGE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CAMPAIGN_STATUS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.ACCOUNT_STATUS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_GROUP_STATUS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.AD_STATUS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.NETWORK);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.TOP_VS_OTHER);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.DEVICE_OS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.ASSISTS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.REVENUE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.RETURN_ON_AD_SPEND);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.COST_PER_ASSIST);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.REVENUE_PER_CONVERSION);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.REVENUE_PER_ASSIST);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.TRACKING_TEMPLATE);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.CUSTOM_PARAMETERS);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.FINAL_URL);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.FINAL_MOBILE_URL);
        adPerformanceReportColumns.getAdPerformanceReportColumns().add(AdPerformanceReportColumn.FINAL_APP_URL);
        reportRequest.setColumns(adPerformanceReportColumns);
        
        return reportRequest;
    }
            
    private static KeywordPerformanceReportRequest getKeywordPerformanceReportRequest(
            java.lang.Long accountId,
            ReportAggregation aggregation,
            java.lang.Boolean excludeColumnHeaders,
            java.lang.Boolean excludeReportFooter,
            java.lang.Boolean excludeReportHeader,
            ReportFormat format,
            java.lang.Boolean returnOnlyCompleteData,
            ReportTime time)
    {
        KeywordPerformanceReportRequest reportRequest = new KeywordPerformanceReportRequest();
        
        reportRequest.setAggregation(aggregation);
        reportRequest.setExcludeColumnHeaders(excludeColumnHeaders);
        reportRequest.setExcludeReportFooter(excludeReportFooter);
        reportRequest.setExcludeReportHeader(excludeReportHeader);
        reportRequest.setFormat(format);
        reportRequest.setReturnOnlyCompleteData(returnOnlyCompleteData);
        reportRequest.setTime(time);
        reportRequest.setReportName("My Keyword Performance Report");
        ArrayOflong accountIds = new ArrayOflong();
        accountIds.getLongs().add(accountId);
        reportRequest.setScope(new AccountThroughAdGroupReportScope());
        reportRequest.getScope().setAccountIds(accountIds);
        reportRequest.getScope().setCampaigns(null);
        reportRequest.getScope().setAdGroups(null);        
        KeywordPerformanceReportFilter filter = new KeywordPerformanceReportFilter();
        reportRequest.setFilter(filter);
        ArrayOfKeywordPerformanceReportColumn keywordPerformanceReportColumns = new ArrayOfKeywordPerformanceReportColumn(); 
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.ACCOUNT_NAME);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.ACCOUNT_NUMBER);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.ACCOUNT_ID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.TIME_PERIOD);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CAMPAIGN_NAME);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CAMPAIGN_ID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_GROUP_NAME);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_GROUP_ID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.KEYWORD);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.KEYWORD_ID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_ID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_TYPE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.DESTINATION_URL);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CURRENT_MAX_CPC);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CURRENCY_CODE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.DELIVERED_MATCH_TYPE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_DISTRIBUTION);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.IMPRESSIONS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CLICKS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CTR);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AVERAGE_CPC);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.SPEND);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AVERAGE_POSITION);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CONVERSIONS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CONVERSION_RATE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.COST_PER_CONVERSION);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.BID_MATCH_TYPE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.DEVICE_TYPE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.QUALITY_SCORE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.EXPECTED_CTR);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_RELEVANCE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.LANDING_PAGE_EXPERIENCE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.LANGUAGE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.HISTORICAL_QUALITY_SCORE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.HISTORICAL_EXPECTED_CTR);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.HISTORICAL_AD_RELEVANCE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.HISTORICAL_LANDING_PAGE_EXPERIENCE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.QUALITY_IMPACT);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CAMPAIGN_STATUS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.ACCOUNT_STATUS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.AD_GROUP_STATUS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.KEYWORD_STATUS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.NETWORK);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.TOP_VS_OTHER);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.DEVICE_OS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.ASSISTS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.REVENUE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.RETURN_ON_AD_SPEND);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.COST_PER_ASSIST);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.REVENUE_PER_CONVERSION);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.REVENUE_PER_ASSIST);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.TRACKING_TEMPLATE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.CUSTOM_PARAMETERS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.FINAL_URL);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.FINAL_MOBILE_URL);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.FINAL_APP_URL);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.BID_STRATEGY_TYPE);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.KEYWORD_LABELS);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.MAINLINE_1_BID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.MAINLINE_BID);
        keywordPerformanceReportColumns.getKeywordPerformanceReportColumns().add(KeywordPerformanceReportColumn.FIRST_PAGE_BID);
        reportRequest.setColumns(keywordPerformanceReportColumns);
        
        return reportRequest;
    }
}
<?php

namespace Microsoft\BingAds\Samples\V13;

// For more information about installing and using the Bing Ads PHP SDK, 
// see https://go.microsoft.com/fwlink/?linkid=838593.

require_once __DIR__ . "/../vendor/autoload.php";

include __DIR__ . "/AuthHelper.php";
include __DIR__ . "/ReportingExampleHelper.php";

use SoapVar;
use SoapFault;
use Exception;

// Specify the Microsoft\BingAds\V13\Reporting classes that will be used.
use Microsoft\BingAds\V13\Reporting\SubmitGenerateReportRequest;
use Microsoft\BingAds\V13\Reporting\PollGenerateReportRequest;
use Microsoft\BingAds\V13\Reporting\AccountPerformanceReportRequest;
use Microsoft\BingAds\V13\Reporting\AudiencePerformanceReportRequest;
use Microsoft\BingAds\V13\Reporting\KeywordPerformanceReportRequest;
use Microsoft\BingAds\V13\Reporting\ReportFormat;
use Microsoft\BingAds\V13\Reporting\ReportAggregation;
use Microsoft\BingAds\V13\Reporting\AccountThroughAdGroupReportScope;
use Microsoft\BingAds\V13\Reporting\CampaignReportScope;
use Microsoft\BingAds\V13\Reporting\AccountReportScope;
use Microsoft\BingAds\V13\Reporting\ReportTime;
use Microsoft\BingAds\V13\Reporting\ReportTimePeriod;
use Microsoft\BingAds\V13\Reporting\Date;
use Microsoft\BingAds\V13\Reporting\AccountPerformanceReportFilter;
use Microsoft\BingAds\V13\Reporting\KeywordPerformanceReportFilter;
use Microsoft\BingAds\V13\Reporting\DeviceTypeReportFilter;
use Microsoft\BingAds\V13\Reporting\AccountPerformanceReportColumn;
use Microsoft\BingAds\V13\Reporting\AudiencePerformanceReportColumn;
use Microsoft\BingAds\V13\Reporting\KeywordPerformanceReportColumn;
use Microsoft\BingAds\V13\Reporting\ReportRequestStatusType;

// Specify the Microsoft\BingAds\Auth classes that will be used.
use Microsoft\BingAds\Auth\ServiceClient;
use Microsoft\BingAds\Auth\ServiceClientType;

// Specify the Microsoft\BingAds\Samples classes that will be used.
use Microsoft\BingAds\Samples\V13\AuthHelper;
use Microsoft\BingAds\Samples\V13\ReportingExampleHelper;

// Specify the file to download the report to. Because the file is
// compressed use the .zip file extension.

$DownloadPath = "c:\\reports\\MyReport.zip";

// Confirm that the download folder exist; otherwise, exit.

$length = strrpos($DownloadPath, '\\');
$folder = substr($DownloadPath, 0, $length);

if (!is_dir($folder))
{
    printf("The output folder, %s, does not exist.\nEnsure that the " .
        "folder exists and try again.", $folder);
    return;
}

try
{
    // Authenticate user credentials and set the account ID for the sample.  
    AuthHelper::Authenticate();

    // You can submit one of the example reports, or build your own.
    $report = GetAccountPerformanceReportRequest(
        $GLOBALS['AuthorizationData']->AccountId
    );
        
    // SubmitGenerateReport helper method calls the corresponding Bing Ads service operation
    // to request the report identifier. The identifier is used to check report generation status
    // before downloading the report.
    
    print("-----\r\nSubmitGenerateReport:\r\n");
    $reportRequestId = ReportingExampleHelper::SubmitGenerateReport(
        $report
    )->ReportRequestId;

    printf("Report Request ID: %s\r\n", $reportRequestId);
    
    $waitTime = 10 * 1; 
    $requestStatus = null;
    $resultFileUrl = null;
    
    // This sample polls every 10 seconds up to 5 minutes.
    // In production you may poll the status every 1 to 2 minutes for up to one hour.
    // If the call succeeds, stop polling. If the call or 
    // download fails, the call throws a fault.
    
    for ($i = 0; $i < 30; $i++)
    {
        printf("-----\r\nsleep(%s seconds)\r\n", $waitTime);
        sleep($waitTime);
        
        // Get the download request status.
        print("-----\r\nPollGenerateReport:\r\n");
        $pollGenerateReportResponse = ReportingExampleHelper::PollGenerateReport(
            $reportRequestId
        );

        $requestStatus = $pollGenerateReportResponse->ReportRequestStatus->Status;
        $resultFileUrl = $pollGenerateReportResponse->ReportRequestStatus->ReportDownloadUrl;
        printf("RequestStatus: %s\r\n", $requestStatus);
        printf("ReportDownloadUrl: %s\r\n", $resultFileUrl);
    
        if ($requestStatus == ReportRequestStatusType::Success ||
            $requestStatus == ReportRequestStatusType::Error)
        {
            break;
        }
    }

    if ($requestStatus != null)
    {
        if ($requestStatus == ReportRequestStatusType::Success)
        {            
            if($resultFileUrl == null)
            {
                print "No report data for the submitted request.\r\n";
            }
            else
            {
                printf("-----\r\nDownloading from %s.\r\n", $resultFileUrl);
                DownloadFile($resultFileUrl, $DownloadPath);
                printf("The report was written to %s.\r\n", $DownloadPath);
            }
            
        }
        else if ($requestStatus == ReportRequestStatusType::Error)
        {
            printf("The request failed. Try requesting the report later.\r\n" .
                "If the request continues to fail, contact support.\r\n"
            );
        }
        else  // Pending
        {
            printf("The request is taking longer than expected.\r\n " .
                "Save the report ID (%s) and try again later.\r\n",
                $reportRequestId
            );
        }
    }
}
catch (SoapFault $e)
{
    printf("-----\r\nFault Code: %s\r\nFault String: %s\r\nFault Detail: \r\n", $e->faultcode, $e->faultstring);
    var_dump($e->detail);
    print "-----\r\nLast SOAP request/response:\r\n";
    print $GLOBALS['Proxy']->GetWsdl() . "\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastRequest()."\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastResponse()."\r\n";
}
catch (Exception $e)
{
    // Ignore fault exceptions that we already caught.
    if ($e->getPrevious())
    { ; }
    else
    {
        print $e->getCode()." ".$e->getMessage()."\r\n";
        print $e->getTraceAsString()."\r\n";
    }
}

// Using the URL that the PollGenerateReport operation returned,
// send an HTTP request to get the report and write it to the specified
// ZIP file.

function DownloadFile($resultFileUrl, $downloadPath)
{
    if (!$reader = fopen($resultFileUrl, 'rb'))
    {
        throw new Exception("Failed to open URL " . $resultFileUrl . ".");
    }

    if (!$writer = fopen($downloadPath, 'wb'))
    {
        fclose($reader);
        throw new Exception("Failed to create ZIP file " . $downloadPath . ".");
    }

    $bufferSize = 100 * 1024;

    while (!feof($reader))
    {
        if (false === ($buffer = fread($reader, $bufferSize)))
        {
             fclose($reader);
             fclose($writer);
             throw new Exception("Read operation from URL failed.");
        }

        if (fwrite($writer, $buffer) === false)
        {
             fclose($reader);
             fclose($writer);
             $exception = new Exception("Write operation to ZIP file failed.");
        }
    }

    fclose($reader);
    fflush($writer);
    fclose($writer);
}

function GetKeywordPerformanceReportRequest($accountId) 
{
    $report = new KeywordPerformanceReportRequest();
    
    $report->Format = ReportFormat::Tsv;
    $report->ReportName = 'My Keyword Performance Report';
    $report->ReturnOnlyCompleteData = false;
    $report->Aggregation = ReportAggregation::Weekly;
    
    $report->Scope = new AccountThroughAdGroupReportScope();
    $report->Scope->AccountIds = array();
    $report->Scope->AccountIds[] = $accountId;
    $report->Scope->AdGroups = null;
    $report->Scope->Campaigns = null;
    
    $report->Time = new ReportTime();
    $report->Time->PredefinedTime = ReportTimePeriod::Yesterday;
            
    $report->Columns = array (
            KeywordPerformanceReportColumn::TimePeriod,
            KeywordPerformanceReportColumn::AccountId,
            KeywordPerformanceReportColumn::CampaignId,
            KeywordPerformanceReportColumn::Keyword,
            KeywordPerformanceReportColumn::KeywordId,
            KeywordPerformanceReportColumn::DeviceType,
            KeywordPerformanceReportColumn::BidMatchType,
            KeywordPerformanceReportColumn::Clicks,
            KeywordPerformanceReportColumn::Impressions,
            KeywordPerformanceReportColumn::Ctr,
            KeywordPerformanceReportColumn::AverageCpc,
            KeywordPerformanceReportColumn::Spend,
            KeywordPerformanceReportColumn::QualityScore
    );

    $encodedReport = new SoapVar(
        $report, 
        SOAP_ENC_OBJECT, 
        'KeywordPerformanceReportRequest', 
        $GLOBALS['ReportingProxy']->GetNamespace()
    );
    
    return $encodedReport;
}

function GetAccountPerformanceReportRequest($accountId) 
{
    $report = new AccountPerformanceReportRequest();
    
    $report->Format = ReportFormat::Tsv;
    $report->ReportName = 'My Account Performance Report';
    $report->ReturnOnlyCompleteData = false;
    $report->Aggregation = ReportAggregation::Weekly;
    
    $report->Scope = new AccountReportScope();
    $report->Scope->AccountIds = array();
    $report->Scope->AccountIds[] = $accountId;
        
    $report->Time = new ReportTime();
    $report->Time->PredefinedTime = ReportTimePeriod::Yesterday;

    $report->Columns = array (
            AccountPerformanceReportColumn::TimePeriod,
            AccountPerformanceReportColumn::AccountId,
            AccountPerformanceReportColumn::AccountName,
            AccountPerformanceReportColumn::Clicks,
            AccountPerformanceReportColumn::Impressions,
            AccountPerformanceReportColumn::Ctr,
            AccountPerformanceReportColumn::AverageCpc,
            AccountPerformanceReportColumn::Spend,
            AccountPerformanceReportColumn::DeviceOS
    );

    $encodedReport = new SoapVar(
        $report, 
        SOAP_ENC_OBJECT, 
        'AccountPerformanceReportRequest', 
        $GLOBALS['ReportingProxy']->GetNamespace()
    );
    
    return $encodedReport;
}

function GetAudiencePerformanceReportRequest($accountId) 
{
    $report = new AudiencePerformanceReportRequest();
    
    $report->Format = ReportFormat::Tsv;
    $report->ReportName = 'My Audience Performance Report';
    $report->ReturnOnlyCompleteData = false;
    $report->Aggregation = ReportAggregation::Daily;
    
    $report->Scope = new AccountThroughAdGroupReportScope();
    $report->Scope->AccountIds = array();
    $report->Scope->AccountIds[] = $accountId;
    $report->Scope->AdGroups = null;
    $report->Scope->Campaigns = null;
    
    $report->Time = new ReportTime();
    $report->Time->PredefinedTime = ReportTimePeriod::Yesterday;
    
    $report->Columns = array (
            AudiencePerformanceReportColumn::TimePeriod,
            AudiencePerformanceReportColumn::AccountId,
            AudiencePerformanceReportColumn::CampaignId,
            AudiencePerformanceReportColumn::AudienceId,
            AudiencePerformanceReportColumn::Clicks,
            AudiencePerformanceReportColumn::Impressions,
            AudiencePerformanceReportColumn::Ctr,
            AudiencePerformanceReportColumn::AverageCpc,
            AudiencePerformanceReportColumn::Spend,
    );
    
    $encodedReport = new SoapVar(
        $report, 
        SOAP_ENC_OBJECT, 
        'AudiencePerformanceReportRequest', 
        $GLOBALS['ReportingProxy']->GetNamespace()
    );
    
    return $encodedReport;
}
from auth_helper import *
from bingads.v13.reporting import *

# You must provide credentials in auth_helper.py.

# The report file extension type.
REPORT_FILE_FORMAT='Csv'

# The directory for the report files.
FILE_DIRECTORY='c:/reports/'

# The name of the report download file.
RESULT_FILE_NAME='result.' + REPORT_FILE_FORMAT.lower()

# The maximum amount of time (in milliseconds) that you want to wait for the report download.
TIMEOUT_IN_MILLISECONDS=3600000

def main(authorization_data):
    try:
        # You can submit one of the example reports, or build your own.

        report_request=get_report_request(authorization_data.account_id)
        
        reporting_download_parameters = ReportingDownloadParameters(
            report_request=report_request,
            result_file_directory = FILE_DIRECTORY, 
            result_file_name = RESULT_FILE_NAME, 
            overwrite_result_file = True, # Set this value true if you want to overwrite the same file.
            timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS # You may optionally cancel the download after a specified time interval.
        )

        #Option A - Background Completion with ReportingServiceManager
        #You can submit a download request and the ReportingServiceManager will automatically 
        #return results. The ReportingServiceManager abstracts the details of checking for result file 
        #completion, and you don't have to write any code for results polling.

        #output_status_message("-----\nAwaiting Background Completion...")
        #background_completion(reporting_download_parameters)

        #Option B - Submit and Download with ReportingServiceManager
        #Submit the download request and then use the ReportingDownloadOperation result to 
        #track status yourself using ReportingServiceManager.get_status().

        #output_status_message("-----\nAwaiting Submit and Download...")
        #submit_and_download(report_request)

        #Option C - Download Results with ReportingServiceManager
        #If for any reason you have to resume from a previous application state, 
        #you can use an existing download request identifier and use it 
        #to download the result file. 

        #For example you might have previously retrieved a request ID using submit_download.
        #reporting_operation=reporting_service_manager.submit_download(report_request)
        #request_id=reporting_operation.request_id

        #Given the request ID above, you can resume the workflow and download the report.
        #The report request identifier is valid for two days. 
        #If you do not download the report within two days, you must request the report again.
        #output_status_message("-----\nAwaiting Download Results...")
        #download_results(request_id, authorization_data)

        #Option D - Download the report in memory with ReportingServiceManager.download_report
        #The download_report helper function downloads the report and summarizes results.
        output_status_message("-----\nAwaiting download_report...")
        download_report(reporting_download_parameters)

    except WebFault as ex:
        output_webfault_errors(ex)
    except Exception as ex:
        output_status_message(ex)


def background_completion(reporting_download_parameters):
    """ You can submit a download request and the ReportingServiceManager will automatically 
    return results. The ReportingServiceManager abstracts the details of checking for result file 
    completion, and you don't have to write any code for results polling. """

    global reporting_service_manager
    result_file_path = reporting_service_manager.download_file(reporting_download_parameters)
    output_status_message("Download result file: {0}".format(result_file_path))

def submit_and_download(report_request):
    """ Submit the download request and then use the ReportingDownloadOperation result to 
    track status until the report is complete e.g. either using
    ReportingDownloadOperation.track() or ReportingDownloadOperation.get_status(). """

    global reporting_service_manager
    reporting_download_operation = reporting_service_manager.submit_download(report_request)

    # You may optionally cancel the track() operation after a specified time interval.
    reporting_operation_status = reporting_download_operation.track(timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS)

    # You can use ReportingDownloadOperation.track() to poll until complete as shown above, 
    # or use custom polling logic with get_status() as shown below.
    #for i in range(10):
    #    time.sleep(reporting_service_manager.poll_interval_in_milliseconds / 1000.0)

    #    download_status = reporting_download_operation.get_status()
        
    #    if download_status.status == 'Success':
    #        break
    
    result_file_path = reporting_download_operation.download_result_file(
        result_file_directory = FILE_DIRECTORY, 
        result_file_name = RESULT_FILE_NAME, 
        decompress = True, 
        overwrite = True,  # Set this value true if you want to overwrite the same file.
        timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS # You may optionally cancel the download after a specified time interval.
    )
    
    output_status_message("Download result file: {0}".format(result_file_path))

def download_results(request_id, authorization_data):
    """ If for any reason you have to resume from a previous application state, 
    you can use an existing download request identifier and use it 
    to download the result file. Use ReportingDownloadOperation.track() to indicate that the application 
    should wait to ensure that the download status is completed. """
    
    reporting_download_operation = ReportingDownloadOperation(
        request_id = request_id, 
        authorization_data=authorization_data, 
        poll_interval_in_milliseconds=1000, 
        environment=ENVIRONMENT,
    )

    # Use track() to indicate that the application should wait to ensure that 
    # the download status is completed.
    # You may optionally cancel the track() operation after a specified time interval.
    reporting_operation_status = reporting_download_operation.track(timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS)
    
    result_file_path = reporting_download_operation.download_result_file(
        result_file_directory = FILE_DIRECTORY, 
        result_file_name = RESULT_FILE_NAME, 
        decompress = True, 
        overwrite = True,  # Set this value true if you want to overwrite the same file.
        timeout_in_milliseconds=TIMEOUT_IN_MILLISECONDS # You may optionally cancel the download after a specified time interval.
    ) 

    output_status_message("Download result file: {0}".format(result_file_path))
    output_status_message("Status: {0}".format(reporting_operation_status.status))

def download_report(reporting_download_parameters):
    """ You can get a Report object by submitting a new download request via ReportingServiceManager. 
    Although in this case you will not work directly with the file, under the covers a request is 
    submitted to the Reporting service and the report file is downloaded to a local directory.  """
    
    global reporting_service_manager

    report_container = reporting_service_manager.download_report(reporting_download_parameters)

    #Otherwise if you already have a report file that was downloaded via the API, 
    #you can get a Report object via the ReportFileReader. 

    # report_file_reader = ReportFileReader(
    #     file_path = reporting_download_parameters.result_file_directory + reporting_download_parameters.result_file_name, 
    #     format = reporting_download_parameters.report_request.Format)
    # report_container = report_file_reader.get_report()

    if(report_container == None):
        output_status_message("There is no report data for the submitted report request parameters.")
        sys.exit(0)

    #Once you have a Report object via either workflow above, you can access the metadata and report records. 

    #Output the report metadata

    record_count = report_container.record_count
    output_status_message("ReportName: {0}".format(report_container.report_name))
    output_status_message("ReportTimeStart: {0}".format(report_container.report_time_start))
    output_status_message("ReportTimeEnd: {0}".format(report_container.report_time_end))
    output_status_message("LastCompletedAvailableDate: {0}".format(report_container.last_completed_available_date))
    output_status_message("ReportAggregation: {0}".format(report_container.report_aggregation))
    output_status_message("ReportColumns: {0}".format("; ".join(str(column) for column in report_container.report_columns)))
    output_status_message("ReportRecordCount: {0}".format(record_count))

    #Analyze and output performance statistics

    if "Impressions" in report_container.report_columns and \
        "Clicks" in report_container.report_columns and \
        "DeviceType" in report_container.report_columns and \
        "Network" in report_container.report_columns:

        report_record_iterable = report_container.report_records

        total_impressions = 0
        total_clicks = 0
        distinct_devices = set()
        distinct_networks = set()
        for record in report_record_iterable:
            total_impressions += record.int_value("Impressions")
            total_clicks += record.int_value("Clicks")
            distinct_devices.add(record.value("DeviceType"))
            distinct_networks.add(record.value("Network"))

        output_status_message("Total Impressions: {0}".format(total_impressions))
        output_status_message("Total Clicks: {0}".format(total_clicks))
        output_status_message("Average Impressions: {0}".format(total_impressions * 1.0 / record_count))
        output_status_message("Average Clicks: {0}".format(total_clicks * 1.0 / record_count))
        output_status_message("Distinct Devices: {0}".format("; ".join(str(device) for device in distinct_devices)))
        output_status_message("Distinct Networks: {0}".format("; ".join(str(network) for network in distinct_networks)))

    #Be sure to close the report.

    report_container.close()

def get_report_request(account_id):
    """ 
    Use a sample report request or build your own. 
    """

    aggregation = 'Daily'
    exclude_column_headers=False
    exclude_report_footer=False
    exclude_report_header=False
    time=reporting_service.factory.create('ReportTime')
    # You can either use a custom date range or predefined time.
    time.PredefinedTime='Yesterday'
    time.ReportTimeZone='PacificTimeUSCanadaTijuana'
    return_only_complete_data=False

    #BudgetSummaryReportRequest does not contain a definition for Aggregation.
    budget_summary_report_request=get_budget_summary_report_request(
        account_id=account_id,
        exclude_column_headers=exclude_column_headers,
        exclude_report_footer=exclude_report_footer,
        exclude_report_header=exclude_report_header,
        report_file_format=REPORT_FILE_FORMAT,
        return_only_complete_data=return_only_complete_data,
        time=time)

    campaign_performance_report_request=get_campaign_performance_report_request(
        account_id=account_id,
        aggregation=aggregation,
        exclude_column_headers=exclude_column_headers,
        exclude_report_footer=exclude_report_footer,
        exclude_report_header=exclude_report_header,
        report_file_format=REPORT_FILE_FORMAT,
        return_only_complete_data=return_only_complete_data,
        time=time)

    keyword_performance_report_request=get_keyword_performance_report_request(
        account_id=account_id,
        aggregation=aggregation,
        exclude_column_headers=exclude_column_headers,
        exclude_report_footer=exclude_report_footer,
        exclude_report_header=exclude_report_header,
        report_file_format=REPORT_FILE_FORMAT,
        return_only_complete_data=return_only_complete_data,
        time=time)

    user_location_performance_report_request=get_user_location_performance_report_request(
        account_id=account_id,
        aggregation=aggregation,
        exclude_column_headers=exclude_column_headers,
        exclude_report_footer=exclude_report_footer,
        exclude_report_header=exclude_report_header,
        report_file_format=REPORT_FILE_FORMAT,
        return_only_complete_data=return_only_complete_data,
        time=time)

    return campaign_performance_report_request

def get_budget_summary_report_request(
        account_id,
        exclude_column_headers,
        exclude_report_footer,
        exclude_report_header,
        report_file_format,
        return_only_complete_data,
        time):

    report_request=reporting_service.factory.create('BudgetSummaryReportRequest')
    report_request.ExcludeColumnHeaders=exclude_column_headers
    report_request.ExcludeReportFooter=exclude_report_footer
    report_request.ExcludeReportHeader=exclude_report_header
    report_request.Format=report_file_format
    report_request.ReturnOnlyCompleteData=return_only_complete_data
    report_request.Time=time    
    report_request.ReportName="My Budget Summary Report"
    scope=reporting_service.factory.create('AccountThroughCampaignReportScope')
    scope.AccountIds={'long': [account_id] }
    scope.Campaigns=None
    report_request.Scope=scope     

    report_columns=reporting_service.factory.create('ArrayOfBudgetSummaryReportColumn')
    report_columns.BudgetSummaryReportColumn.append([
        'AccountName',
        'AccountNumber',
        'AccountId',
        'CampaignName',
        'CampaignId',
        'Date',
        'CurrencyCode',
        'MonthlyBudget',
        'DailySpend',
        'MonthToDateSpend'
    ])
    report_request.Columns=report_columns

    return report_request

def get_campaign_performance_report_request(
        account_id,
        aggregation,
        exclude_column_headers,
        exclude_report_footer,
        exclude_report_header,
        report_file_format,
        return_only_complete_data,
        time):

    report_request=reporting_service.factory.create('CampaignPerformanceReportRequest')
    report_request.Aggregation=aggregation
    report_request.ExcludeColumnHeaders=exclude_column_headers
    report_request.ExcludeReportFooter=exclude_report_footer
    report_request.ExcludeReportHeader=exclude_report_header
    report_request.Format=report_file_format
    report_request.ReturnOnlyCompleteData=return_only_complete_data
    report_request.Time=time    
    report_request.ReportName="My Campaign Performance Report"
    scope=reporting_service.factory.create('AccountThroughCampaignReportScope')
    scope.AccountIds={'long': [account_id] }
    scope.Campaigns=None
    report_request.Scope=scope     

    report_columns=reporting_service.factory.create('ArrayOfCampaignPerformanceReportColumn')
    report_columns.CampaignPerformanceReportColumn.append([
        'TimePeriod',
        'CampaignId',
        'CampaignName',
        'DeviceType',
        'Network',
        'Impressions',
        'Clicks',  
        'Spend'
    ])
    report_request.Columns=report_columns
    
    return report_request

def get_keyword_performance_report_request(
        account_id,
        aggregation,
        exclude_column_headers,
        exclude_report_footer,
        exclude_report_header,
        report_file_format,
        return_only_complete_data,
        time):

    report_request=reporting_service.factory.create('KeywordPerformanceReportRequest')
    report_request.Aggregation=aggregation
    report_request.ExcludeColumnHeaders=exclude_column_headers
    report_request.ExcludeReportFooter=exclude_report_footer
    report_request.ExcludeReportHeader=exclude_report_header
    report_request.Format=report_file_format
    report_request.ReturnOnlyCompleteData=return_only_complete_data
    report_request.Time=time    
    report_request.ReportName="My Keyword Performance Report"
    scope=reporting_service.factory.create('AccountThroughAdGroupReportScope')
    scope.AccountIds={'long': [account_id] }
    scope.Campaigns=None
    scope.AdGroups=None
    report_request.Scope=scope     

    report_columns=reporting_service.factory.create('ArrayOfKeywordPerformanceReportColumn')
    report_columns.KeywordPerformanceReportColumn.append([
        'TimePeriod',
        'AccountId',
        'CampaignId',
        'Keyword',
        'KeywordId',
        'DeviceType',
        'Network',
        'Impressions',
        'Clicks',  
        'Spend',
        'BidMatchType',              
        'Ctr',
        'AverageCpc',        
        'QualityScore'
    ])
    report_request.Columns=report_columns

    return report_request

def get_user_location_performance_report_request(
        account_id,
        aggregation,
        exclude_column_headers,
        exclude_report_footer,
        exclude_report_header,
        report_file_format,
        return_only_complete_data,
        time):
    
    report_request=reporting_service.factory.create('UserLocationPerformanceReportRequest')
    report_request.Aggregation=aggregation
    report_request.ExcludeColumnHeaders=exclude_column_headers
    report_request.ExcludeReportFooter=exclude_report_footer
    report_request.ExcludeReportHeader=exclude_report_header
    report_request.Format=report_file_format
    report_request.ReturnOnlyCompleteData=return_only_complete_data
    report_request.Time=time    
    report_request.ReportName="My User Location Performance Report"
    scope=reporting_service.factory.create('AccountThroughAdGroupReportScope')
    scope.AccountIds={'long': [account_id] }
    scope.Campaigns=None
    scope.AdGroups=None
    report_request.Scope=scope 

    report_columns=reporting_service.factory.create('ArrayOfUserLocationPerformanceReportColumn')
    report_columns.UserLocationPerformanceReportColumn.append([
        'TimePeriod',
        'AccountId',
        'AccountName',
        'CampaignId',
        'AdGroupId',
        'LocationId',
        'Country',
        'Clicks',
        'Impressions',
        'DeviceType',
        'Network',
        'Ctr',
        'AverageCpc',
        'Spend',
    ])
    report_request.Columns=report_columns

    return report_request

# Main execution
if __name__ == '__main__':

    print("Loading the web service client proxies...")

    authorization_data=AuthorizationData(
        account_id=None,
        customer_id=None,
        developer_token=DEVELOPER_TOKEN,
        authentication=None,
    )

    reporting_service_manager=ReportingServiceManager(
        authorization_data=authorization_data, 
        poll_interval_in_milliseconds=5000, 
        environment=ENVIRONMENT,
    )

    # In addition to ReportingServiceManager, you will need a reporting ServiceClient 
    # to build the ReportRequest.

    reporting_service=ServiceClient(
        service='ReportingService', 
        version=13,
        authorization_data=authorization_data, 
        environment=ENVIRONMENT,
    )

    authenticate(authorization_data)
        
    main(authorization_data)

See Also

Get Started with the Bing Ads API