Add Billing Setup

Java

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.ads.googleads.examples.billing;

import static com.google.ads.googleads.examples.utils.CodeSampleHelper.getPrintableDateTime;

import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v16.errors.GoogleAdsError;
import com.google.ads.googleads.v16.errors.GoogleAdsException;
import com.google.ads.googleads.v16.resources.BillingSetup;
import com.google.ads.googleads.v16.resources.BillingSetup.PaymentsAccountInfo;
import com.google.ads.googleads.v16.services.BillingSetupOperation;
import com.google.ads.googleads.v16.services.BillingSetupServiceClient;
import com.google.ads.googleads.v16.services.GoogleAdsServiceClient;
import com.google.ads.googleads.v16.services.GoogleAdsServiceClient.SearchPagedResponse;
import com.google.ads.googleads.v16.services.MutateBillingSetupResponse;
import com.google.ads.googleads.v16.utils.ResourceNames;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.joda.time.DateTime;

/**
 * Creates a billing setup for a customer. A billing setup is a link between a payments account and
 * a customer. The new billing setup can either reuse an existing payments account, or create a new
 * payments account with a given payments profile. Billing setups are applicable for clients on
 * monthly invoicing only. See here for details about applying for monthly invoicing:
 * https://support.google.com/google-ads/answer/2375377. In the case of consolidated billing, a
 * payments account is linked to the manager account and is linked to a customer account via a
 * billing setup.
 */
public class AddBillingSetup {
  private static class AddBillingSetupParams extends CodeSampleParams {

    @Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
    private Long customerId;

    @Parameter(names = ArgumentNames.PAYMENTS_ACCOUNT_ID_ID)
    private String paymentsAccountId;

    @Parameter(names = ArgumentNames.PAYMENTS_PROFILE_ID)
    private String paymentsProfileId;
  }

  public static void main(String[] args) {
    AddBillingSetupParams params = new AddBillingSetupParams();

    if (!params.parseArguments(args)) {

      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");

      // Either a payments account ID or a payments profile ID must be provided for the example
      // to run successfully. If both are provided, only the payments account ID will be used.
      // See:
      // https://developers.google.com/google-ads/api/docs/billing/billing-setups#creating_new_billing_setups
      // Provide an existing payments account ID to link to the new billing setup. Must be
      // formatted as "1234-5678-9012-3456".
      params.paymentsAccountId = "INSERT_PAYMENTS_ACCOUNT_ID_HERE";
      // Alternatively, provide a payments profile ID, which will be linked to a new payments
      // account and the new billing setup. Must be formatted as "1234-5678-9012".
      params.paymentsProfileId = "INSERT_PAYMENTS_PROFILE_ID_HERE";
    }

    GoogleAdsClient googleAdsClient;
    try {
      googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
    } catch (FileNotFoundException fnfe) {
      System.err.printf(
          "Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
      return;
    } catch (IOException ioe) {
      System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
      return;
    }

    try {
      new AddBillingSetup()
          .runExample(
              googleAdsClient,
              params.customerId,
              params.paymentsAccountId,
              params.paymentsProfileId);
    } catch (GoogleAdsException gae) {
      // GoogleAdsException is the base class for most exceptions thrown by an API request.
      // Instances of this exception have a message and a GoogleAdsFailure that contains a
      // collection of GoogleAdsErrors that indicate the underlying causes of the
      // GoogleAdsException.
      System.err.printf(
          "Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
          gae.getRequestId());
      int i = 0;
      for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
        System.err.printf("  Error %d: %s%n", i++, googleAdsError);
      }
    } catch (Exception e) {
      System.err.printf("  Error: %s%n", e);
    }
  }

  /**
   * Runs the example.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID containing the BillingSetup to remove.
   * @param paymentsAccountId optional payments account ID to attach to the new billing setup. Must
   *     be formatted as "1234-5678-9012-3456".
   * @param paymentsProfileId optional payments profile ID to attach to a new payments account and
   *     to the new billing setup. Must be formatted as "1234-5678-9012".
   */
  private void runExample(
      GoogleAdsClient googleAdsClient,
      long customerId,
      String paymentsAccountId,
      String paymentsProfileId)
      throws Exception {
    // Constructs a new billing setup.
    BillingSetup billingSetup =
        createBillingSetup(customerId, paymentsAccountId, paymentsProfileId);

    billingSetup = setBillingSetupDateTimes(googleAdsClient, customerId, billingSetup);

    // Creates the billing setup operation.
    BillingSetupOperation operation =
        BillingSetupOperation.newBuilder().setCreate(billingSetup).build();

    // Creates the service client.
    try (BillingSetupServiceClient billingSetupServiceClient =
        googleAdsClient.getLatestVersion().createBillingSetupServiceClient()) {
      // Issues the mutate request to add the billing setup.
      MutateBillingSetupResponse billingResponse =
          billingSetupServiceClient.mutateBillingSetup(Long.toString(customerId), operation);

      System.out.printf(
          "Added new billing setup with resource name '%s'.%n",
          billingResponse.getResult().getResourceName());
    }
  }

  /**
   * Creates and returns a new Billing Setup instance with complete payment details. One of
   * paymentsAccountId or paymentsProfileId must be provided.
   *
   * @param customerId the customer ID containing the BillingSetup to remove.
   * @param paymentsAccountId optional payments account ID to attach to the new billing setup. Must
   *     be formatted as "1234-5678-9012-3456".
   * @param paymentsProfileId optional payments profile ID to attach to a new payments account and
   *     to the new billing setup. Must be formatted as "1234-5678-9012".
   * @return new Billing Setup instance with complete payment details.
   */
  private BillingSetup createBillingSetup(
      long customerId, String paymentsAccountId, String paymentsProfileId) throws Exception {
    BillingSetup.Builder billingSetupBuilder = BillingSetup.newBuilder();

    // Sets the appropriate payments account field.
    if (paymentsAccountId != null) {
      // If a payments account id has been provided, set PaymentsAccount to its resource
      // name. You can list available payments accounts via the PaymentsAccountService's
      // ListPaymentsAccounts method.
      billingSetupBuilder.setPaymentsAccount(
          ResourceNames.paymentsAccount(customerId, paymentsAccountId));
    } else if (paymentsProfileId != null) {
      // Otherwise, create a new payments account by setting the PaymentsAccountInfo
      // field. See https://support.google.com/google-ads/answer/7268503 for information
      // about payments profiles.
      billingSetupBuilder.setPaymentsAccountInfo(
          PaymentsAccountInfo.newBuilder()
              .setPaymentsAccountName("Payments Account #" + getPrintableDateTime())
              .setPaymentsProfileId(paymentsProfileId)
              .build());
    } else {
      throw new Exception("No paymentsAccountId or paymentsProfileId provided.");
    }

    return billingSetupBuilder.build();
  }

  /**
   * Sets the starting and ending date times for the new billing setup. Queries the customer's
   * account to see if there are any approved billing setups. If there are any, the new billing
   * setup starting date time is set to one day after the last. If not, the billing setup is set to
   * start immediately. The ending date is set to one day after the starting date time.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID containing the BillingSetup to remove.
   * @param billingSetup The instance of BillingSetup whose starting date time will be set.
   * @return Billing Setup with updated start and end date time.
   */
  private BillingSetup setBillingSetupDateTimes(
      GoogleAdsClient googleAdsClient, long customerId, BillingSetup billingSetup)
      throws Exception {
    // Defines a query to search existing approved billing setups in the end date time descending
    // order.
    // See GetBillingSetup.java for a more detailed example of requesting billing setup
    // information.
    String query =
        "SELECT billing_setup.end_date_time "
            + "FROM billing_setup "
            + "WHERE billing_setup.status = 'APPROVED' "
            + "ORDER BY billing_setup.end_date_time DESC";

    // Creates the service client.
    try (GoogleAdsServiceClient googleAdsServiceClient =
        googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
      // Issues a search request.
      SearchPagedResponse searchPagedResponse =
          googleAdsServiceClient.search(Long.toString(customerId), query);

      BillingSetup.Builder billingSetupBuilder = billingSetup.toBuilder();
      if (searchPagedResponse.getPage().getResponse().getResultsCount() > 0) {
        // Retrieves the ending date time of the last billing setup.
        String lastEndingDateTimeString =
            searchPagedResponse
                .getPage()
                .getResponse()
                .getResults(0)
                .getBillingSetup()
                .getEndDateTime();

        // A null ending date time indicates that the current billing setup is set to run
        // indefinitely. Billing setups cannot overlap, so throw an exception in this case.
        if (lastEndingDateTimeString == null) {
          throw new Exception(
              "Cannot set starting and ending date times for the new billing setup; the latest"
                  + " existing billing setup is set to run indefinitely.");
        }

        DateTime lastEndingDateTime = DateTime.parse(lastEndingDateTimeString.toString());

        // Sets the new billing setup to start one day after the ending date time.
        billingSetupBuilder.setStartDateTime(lastEndingDateTime.plusDays(1).toString("yyyy-MM-dd"));

        // Sets the new billing setup to end one day after the starting date time.
        billingSetupBuilder.setEndDateTime(lastEndingDateTime.plusDays(2).toString("yyyy-MM-dd"));
      } else {
        // Otherwise, the only acceptable start time is DateTime.now().
        billingSetupBuilder.setStartDateTime(DateTime.now().toString());

        // Sets the new billing setup to end tomorrow.
        billingSetupBuilder.setEndDateTime(new DateTime().plusDays(1).toString("yyyy-MM-dd"));
      }
      return billingSetupBuilder.build();
    }
  }
}

      

C#

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using CommandLine;
using Google.Ads.Gax.Examples;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V16.Errors;
using Google.Ads.GoogleAds.V16.Resources;
using Google.Ads.GoogleAds.V16.Services;
using Google.Api.Gax;
using System;
using System.Collections.Generic;
using System.Linq;
using static Google.Ads.GoogleAds.V16.Enums.TimeTypeEnum.Types;

namespace Google.Ads.GoogleAds.Examples.V16
{
    /// <summary>
    /// This example creates a billing setup for a customer. A billing setup is a link between a
    /// payments account and a customer. The new billing setup can either reuse an existing payments
    /// account, or create a new payments account with a given payments profile. Billing setups are
    /// applicable for clients on monthly invoicing only. See here for details about applying for
    /// monthly invoicing: https://support.google.com/google-ads/answer/2375377 In the case of
    /// consolidated billing, a payments account is linked to the manager account and is linked to a
    /// customer account via a billing setup.
    /// </summary>
    public class AddBillingSetup : ExampleBase
    {
        /// <summary>
        /// Command line options for running the <see cref="AddBillingSetup"/> example.
        /// </summary>
        public class Options : OptionsBase
        {
            /// <summary>
            /// The Google Ads customer ID for which the call is made.
            /// </summary>
            [Option("customerId", Required = true, HelpText =
                "The Google Ads customer ID for which the call is made.")]
            public long CustomerId { get; set; }

            /// <summary>
            /// Optional payments account ID to attach to the new billing setup. Must be formatted
            /// as "1234-5678-9012-3456".
            /// </summary>
            [Option("paymentsAccountId", Required = false, HelpText =
                "Optional payments account ID to attach to the new billing setup. Must be " +
                "formatted as '1234-5678-9012-3456'.")]
            public string PaymentsAccountId { get; set; }

            /// <summary>
            /// Optional payments profile ID to attach to a new payments account and to the new
            /// billing setup. Must be formatted as "1234-5678-9012".
            /// </summary>
            [Option("paymentsProfileId", Required = false, HelpText =
                "Optional payments profile ID to attach to a new payments account and to the new" +
                " billing setup. Must be formatted as '1234-5678-9012'.")]
            public string PaymentsProfileId { get; set; }
        }

        /// <summary>
        /// Main method, to run this code example as a standalone application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            Options options = ExampleUtilities.ParseCommandLine<Options>(args);

            AddBillingSetup codeExample = new AddBillingSetup();
            Console.WriteLine(codeExample.Description);
            codeExample.Run(new GoogleAdsClient(), options.CustomerId, options.PaymentsAccountId,
                options.PaymentsProfileId);
        }

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "This example creates a billing setup for a customer. A billing setup is a link " +
            "between a payments account and a customer. The new billing setup can either reuse " +
            "an existing payments account, or create a new payments account with a given " +
            "payments profile.\n" +
            "Billing setups are applicable for clients on monthly invoicing only. See here for " +
            "details about applying for monthly invoicing: " +
            "https://support.google.com/google-ads/answer/2375377\n" +
            "In the case of consolidated billing, a payments account is linked to the " +
            "manager account and is linked to a customer account via a billing setup.";

        /// <summary>
        /// Runs the code example. Either a payments account ID or a payments profile ID must be
        /// provided for the example to run successfully. If both are provided, only the payments
        /// account ID will be used.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="paymentsAccountId">
        /// Optional payments account ID to attach to the new billing setup. Must be formatted as
        /// "1234-5678-9012-3456".
        /// </param>
        /// <param name="paymentsProfileId">
        /// Optional payments profile ID to attach to a new payments account and to the new billing
        /// setup. Must be formatted as "1234-5678-9012".
        /// </param>
        public void Run(GoogleAdsClient client, long customerId, string paymentsAccountId,
            string paymentsProfileId)
        {
            // Gets the GoogleAdsServiceClient.
            GoogleAdsServiceClient googleAdsService = client.GetService(
                Services.V16.GoogleAdsService);

            // Gets the BillingSetupServiceClient.
            BillingSetupServiceClient billingSetupServiceClient =
                client.GetService(Services.V16.BillingSetupService);

            try
            {
                // Constructs a new billing setup.
                BillingSetup billingSetup =
                    CreateBillingSetup(customerId, paymentsAccountId, paymentsProfileId);

                SetBillingSetupStartDateTime(googleAdsService, customerId, billingSetup);

                // Creates the billing setup operation.
                BillingSetupOperation operation = new BillingSetupOperation()
                {
                    Create = billingSetup
                };

                // Issues a mutate request to add the billing setup.
                MutateBillingSetupResponse billingResponse =
                    billingSetupServiceClient.MutateBillingSetup(customerId.ToString(), operation);

                Console.WriteLine("Added new billing setup with resource name: " +
                                  $"{billingResponse.Result.ResourceName}");
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }

        /// <summary>
        /// Creates and returns a new Billing Setup instance with complete payment details. One of
        /// paymentsAccountId or paymentsProfileId must be provided.
        /// </summary>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="paymentsAccountId">
        /// Optional payments account ID to attach to the new billing setup. Must be formatted as
        /// "1234-5678-9012-3456".
        /// </param>
        /// <param name="paymentsProfileId">
        /// Optional payments profile ID to attach to a new payments account and to the new billing
        /// setup. Must be formatted as "1234-5678-9012".
        /// </param>
        /// <returns>A new BillingSetup instance with complete payment details.</returns>
        /// <exception cref="Exception">
        /// Generic exception if no payment details have been provided.
        /// </exception>
        private BillingSetup CreateBillingSetup(long customerId, string paymentsAccountId,
            string paymentsProfileId)
        {
            BillingSetup billingSetup = new BillingSetup();

            // Sets the appropriate payments account field.
            if (paymentsAccountId != null)
            {
                // If a payments account id has been provided, set PaymentsAccount to its resource
                // name. You can list available payments accounts via the PaymentsAccountService's
                // ListPaymentsAccounts method.
                billingSetup.PaymentsAccount =
                    ResourceNames.PaymentsAccount(customerId, paymentsAccountId);
            }
            else if (paymentsProfileId != null)
            {
                // Otherwise, create a new payments account by setting the PaymentsAccountInfo
                // field. See https://support.google.com/google-ads/answer/7268503 for information
                // about payments profiles.
                billingSetup.PaymentsAccountInfo = new BillingSetup.Types.PaymentsAccountInfo()
                {
                    PaymentsAccountName = "Payments Account #" + ExampleUtilities.GetRandomString(),
                    PaymentsProfileId = paymentsProfileId
                };
            }
            else
            {
                throw new Exception("No paymentsAccountId or paymentsProfileId provided.");
            }

            return billingSetup;
        }

        /// <summary>
        /// Sets the starting and ending date times for the new billing setup. Queries the
        /// customer's account to see if there are any approved billing setups. If there are any,
        /// the new billing setup starting date time is set to one day after the last. If not, the
        /// billing setup is set to start immediately. The ending date is set to one day after the
        /// starting date time.
        /// </summary>
        /// <param name="googleAdsService">The Google Ads service client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="billingSetup">
        /// The instance of BillingSetup whose starting date time will be set.
        /// </param>
        private void SetBillingSetupStartDateTime(GoogleAdsServiceClient googleAdsService,
            long customerId, BillingSetup billingSetup)
        {
            // The query to search existing approved billing setups in the end date time descending
            // order. See GetBillingSetup.cs for a more detailed example of requesting billing setup
            // information.
            string query = @"
                SELECT billing_setup.end_date_time
                FROM billing_setup
                WHERE billing_setup.status = 'APPROVED'
                ORDER BY billing_setup.end_date_time DESC
                LIMIT 1";

            // Issues a search request.
            PagedEnumerable<SearchGoogleAdsResponse, GoogleAdsRow> searchResponse =
                googleAdsService.Search(customerId.ToString(), query);

            if (searchResponse.Any())
            {
                // Retrieves the ending date time of the last billing setup.
                string lastEndingDateTimeString = searchResponse.First().BillingSetup.EndDateTime;

                // A null ending date time indicates that the current billing setup is set to run
                // indefinitely. Billing setups cannot overlap, so throw an exception in this case.
                if (lastEndingDateTimeString == null)
                {
                    throw new Exception("Cannot set starting and ending date times for " +
                                        "the new billing setup; the latest existing billing " +
                                        "setup is set to run indefinitely.");
                }

                DateTime lastEndingDateTime = DateTime.Parse(lastEndingDateTimeString);

                // Sets the new billing setup to start one day after the ending date time.
                billingSetup.StartDateTime = lastEndingDateTime.AddDays(1).ToString("yyyy-MM-dd");

                // Sets the new billing setup to end one day after the starting date time.
                billingSetup.EndDateTime = lastEndingDateTime.AddDays(2).ToString("yyyy-MM-dd");
            }
            else
            {
                // Otherwise, the only acceptable start time is TimeType.Now.
                billingSetup.StartTimeType = TimeType.Now;

                // Sets the new billing setup to end tomorrow.
                billingSetup.EndDateTime = DateTime.Today.AddDays(1).ToString("yyyy-MM-dd");
            }
        }
    }
}

      

PHP

<?php

/**
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Google\Ads\GoogleAds\Examples\Billing;

require __DIR__ . '/../../vendor/autoload.php';

use Exception;
use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Examples\Utils\Helper;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsServerStreamDecorator;
use Google\Ads\GoogleAds\Util\V16\ResourceNames;
use Google\Ads\GoogleAds\V16\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V16\Resources\BillingSetup;
use Google\Ads\GoogleAds\V16\Resources\BillingSetup\PaymentsAccountInfo;
use Google\Ads\GoogleAds\V16\Services\BillingSetupOperation;
use Google\Ads\GoogleAds\V16\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V16\Services\MutateBillingSetupRequest;
use Google\Ads\GoogleAds\V16\Services\SearchGoogleAdsStreamRequest;
use Google\ApiCore\ApiException;

/**
 * This example creates a billing setup for a customer. A billing setup is a link between
 * a payments account and a customer. The new billing setup can either reuse an existing payments
 * account, or create a new payments account with a given payments profile.
 * Billing setups are applicable for clients on monthly invoicing only. See here for details
 * about applying for monthly invoicing: https://support.google.com/google-ads/answer/2375377.
 * In the case of consolidated billing, a payments account is linked to the manager account and
 * is linked to a customer account via a billing setup.
 */
class AddBillingSetup
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';

    // Either a payments account ID or a payments profile ID must be provided for the example
    // to run successfully. If both are provided, only the payments account ID will be used.
    // See: https://developers.google.com/google-ads/api/docs/billing/billing-setups#creating_new_billing_setups
    /**
     * Provide an existing payments account ID to link to the new billing setup. Must be
     * formatted as "1234-5678-9012-3456".
     */
    private const PAYMENTS_ACCOUNT_ID = null;
    /**
     * Alternatively, provide a payments profile ID which will be linked to a new payments
     * account and the new billing setup. Must be formatted as "1234-5678-9012".
     */
    private const PAYMENTS_PROFILE_ID = null;

    public static function main()
    {
        // Either pass the required parameters for this example on the command line, or insert them
        // into the constants above.
        $options = (new ArgumentParser())->parseCommandArguments([
            ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
            ArgumentNames::PAYMENTS_ACCOUNT_ID => GetOpt::OPTIONAL_ARGUMENT,
            ArgumentNames::PAYMENTS_PROFILE_ID => GetOpt::OPTIONAL_ARGUMENT
        ]);

        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct a Google Ads client configured from a properties file and the
        // OAuth2 credentials above.
        $googleAdsClient = (new GoogleAdsClientBuilder())->fromFile()
            ->withOAuth2Credential($oAuth2Credential)
            // We set this value to true to show how to use GAPIC v2 source code. You can remove the
            // below line if you wish to use the old-style source code. Note that in that case, you
            // probably need to modify some parts of the code below to make it work.
            // For more information, see
            // https://developers.devsite.corp.google.com/google-ads/api/docs/client-libs/php/gapic.
            ->usingGapicV2Source(true)
            ->build();

        try {
            self::runExample(
                $googleAdsClient,
                $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
                $options[ArgumentNames::PAYMENTS_ACCOUNT_ID] ?: self::PAYMENTS_ACCOUNT_ID,
                $options[ArgumentNames::PAYMENTS_PROFILE_ID] ?: self::PAYMENTS_PROFILE_ID
            );
        } catch (GoogleAdsException $googleAdsException) {
            printf(
                "Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
                $googleAdsException->getRequestId(),
                PHP_EOL,
                PHP_EOL
            );
            foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
                /** @var GoogleAdsError $error */
                printf(
                    "\t%s: %s%s",
                    $error->getErrorCode()->getErrorCode(),
                    $error->getMessage(),
                    PHP_EOL
                );
            }
            exit(1);
        } catch (ApiException $apiException) {
            printf(
                "ApiException was thrown with message '%s'.%s",
                $apiException->getMessage(),
                PHP_EOL
            );
            exit(1);
        }
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string|null $paymentsAccountId optional, payments account ID to attach to the new
     *     billing setup. Must be formatted as "1234-5678-9012-3456"
     * @param string|null $paymentsProfileId optional, payments profile ID to attach to a new
     *     payments account and to the new billing setup. Must be formatted as "1234-5678-9012"
     */
    public static function runExample(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        ?string $paymentsAccountId,
        ?string $paymentsProfileId
    ) {
        // Constructs a new billing setup.
        $billingSetup = self::createBillingSetup(
            $customerId,
            $paymentsAccountId,
            $paymentsProfileId
        );
        self::setBillingSetupDateTimes($googleAdsClient, $customerId, $billingSetup);

        $billingSetupOperation = new BillingSetupOperation();
        $billingSetupOperation->setCreate($billingSetup);

        // Issues a mutate request to add the billing setup.
        $billingSetupServiceClient = $googleAdsClient->getBillingSetupServiceClient();
        $response = $billingSetupServiceClient->mutateBillingSetup(
            MutateBillingSetupRequest::build($customerId, $billingSetupOperation)
        );

        printf(
            "Added new billing setup with resource name '%s'.%s",
            $response->getResult()->getResourceName(),
            PHP_EOL
        );
    }

    /**
     * Creates and returns a new billing setup instance with complete payment details. One of
     * the payments account ID or payments profile ID must be provided.
     *
     * @param int $customerId the customer ID
     * @param string|null $paymentsAccountId optional, payments account ID to attach to the new
     *     billing setup. Must be formatted as "1234-5678-9012-3456"
     * @param string|null $paymentsProfileId optional, payments profile ID to attach to a new
     *     payments account and to the new billing setup. Must be formatted as "1234-5678-9012"
     * @return BillingSetup the created billing setup
     */
    public static function createBillingSetup(
        int $customerId,
        ?string $paymentsAccountId,
        ?string $paymentsProfileId
    ): BillingSetup {
        $billingSetup = new BillingSetup();

        // Sets the appropriate payments account field.
        if (!is_null($paymentsAccountId)) {
            // If a payments account ID has been provided, set the resource name.
            // You can list available payments accounts via the PaymentsAccountService's
            // ListPaymentsAccounts method.
            $billingSetup->setPaymentsAccount(
                ResourceNames::forPaymentsAccount($customerId, $paymentsAccountId)
            );
        } elseif (!is_null($paymentsProfileId)) {
            // Otherwise, create a new payments account by setting the payments account info.
            // See https://support.google.com/google-ads/answer/7268503 for more information about
            // payments profiles.
            $billingSetup->setPaymentsAccountInfo(new PaymentsAccountInfo([
                'payments_account_name' => 'Payments Account #' . Helper::getPrintableDatetime(),
                'payments_profile_id' => $paymentsProfileId
            ]));
        } else {
            throw new \UnexpectedValueException(
                'No payments account ID or payments profile ID is provided.' . PHP_EOL
            );
        }

        return $billingSetup;
    }

    /**
     * Sets the starting and ending date times for the new billing setup. Queries the customer's
     * account to see if there are any approved billing setups. If there are any, the new billing
     * setup starting date time is set to one day after the last. If not, the billing setup is
     * set to start immediately. The ending date is set to one day after the starting date time.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param BillingSetup $billingSetup the billing setup whose starting and ending date times
     *     will be set
     */
    public static function setBillingSetupDateTimes(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        BillingSetup $billingSetup
    ) {
        // The query to search existing approved billing setups in the end date time descending
        // order.
        // See GetBillingSetup.php for a more detailed example of how to retrieve billing setups.
        $query = 'SELECT billing_setup.end_date_time ' .
            'FROM billing_setup ' .
            'WHERE billing_setup.status = APPROVED ' .
            'ORDER BY billing_setup.end_date_time DESC';

        // Issues a search stream request.
        /** @var GoogleAdsServerStreamDecorator $stream */
        $stream = $googleAdsClient->getGoogleAdsServiceClient()->searchStream(
            SearchGoogleAdsStreamRequest::build($customerId, $query)
        );
        /** @var GoogleAdsRow $googleAdsRow */
        $googleAdsRow = $stream->iterateAllElements()->current();

        if (!is_null($googleAdsRow)) {
            // Retrieves the ending date time of the last billing setup
            $lastEndingDateTimeString = $googleAdsRow->getBillingSetup()->getEndDateTime();

            if (is_null($lastEndingDateTimeString)) {
                // A null ending date time indicates that the current billing setup is set to run
                // indefinitely. Billing setups cannot overlap, so throw an exception in this case.
                throw new Exception(
                    'Cannot set starting and ending date times for the new billing setup; the ' .
                    'latest existing billing setup is set to run indefinitely.'
                );
            }

            // Sets the new billing setup to start one day after the ending date time.
            $startDate = strtotime('+1 day', strtotime($lastEndingDateTimeString));
        } else {
            // Otherwise, the only acceptable start date time is today.
            $startDate = time();
        }
        $billingSetup->setStartDateTime(date('Y-m-d', $startDate));
        // Sets the new billing setup to end one day after the starting date time.
        $billingSetup->setEndDateTime(date('Y-m-d', strtotime('+1 day', $startDate)));
    }
}

AddBillingSetup::main();

      

Python

#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This example creates a billing setup for a customer.

A billing setup is a link between a payments account and a customer. The new
billing setup can either reuse an existing payments account, or create a new
payments account with a given payments profile. Billing setups are applicable
for clients on monthly invoicing only. See here for details about applying for
monthly invoicing: https://support.google.com/google-ads/answer/2375377.
In the case of consolidated billing, a payments account is linked to the
manager account and is linked to a customer account via a billing setup.
"""


import argparse
from datetime import datetime, timedelta
import sys
from uuid import uuid4

from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException


def main(
    client, customer_id, payments_account_id=None, payments_profile_id=None
):
    """The main method that creates all necessary entities for the example.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        payments_account_id: payments account ID to attach to the new billing
            setup. If provided it must be formatted as "1234-5678-9012-3456".
        payments_profile_id: payments profile ID to attach to a new payments
            account and to the new billing setup. If provided it must be
            formatted as "1234-5678-9012".
    """
    billing_setup = create_billing_setup(
        client, customer_id, payments_account_id, payments_profile_id
    )
    set_billing_setup_date_times(client, customer_id, billing_setup)
    billing_setup_operation = client.get_type("BillingSetupOperation")
    client.copy_from(billing_setup_operation.create, billing_setup)
    billing_setup_service = client.get_service("BillingSetupService")
    response = billing_setup_service.mutate_billing_setup(
        customer_id=customer_id, operation=billing_setup_operation
    )
    print(
        "Added new billing setup with resource name "
        f"{response.result.resource_name}"
    )


def create_billing_setup(
    client, customer_id, payments_account_id=None, payments_profile_id=None
):
    """Creates and returns a new billing setup instance.

    The new billing setup will have its payment details populated. One of the
    payments_account_id or payments_profile_id must be provided.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        payments_account_id: payments account ID to attach to the new billing
            setup. If provided it must be formatted as "1234-5678-9012-3456".
        payments_profile_id: payments profile ID to attach to a new payments
            account and to the new billing setup. If provided it must be
            formatted as "1234-5678-9012".

    Returns:
        A newly created BillingSetup instance.
    """
    billing_setup = client.get_type("BillingSetup")

    # Sets the appropriate payments account field.
    if payments_account_id != None:
        # If a payments account ID has been provided, set the payments_account
        # field to the full resource name of the given payments account ID.
        # You can list available payments accounts via the
        # PaymentsAccountService's ListPaymentsAccounts method.
        billing_setup.payments_account = client.get_service(
            "BillingSetupService"
        ).payments_account_path(customer_id, payments_account_id)
    elif payments_profile_id != None:
        # Otherwise, create a new payments account by setting the
        # payments_account_info field
        # See https://support.google.com/google-ads/answer/7268503
        # for more information about payments profiles.
        billing_setup.payments_account_info.payments_account_name = (
            f"Payments Account #{uuid4()}"
        )
        billing_setup.payments_account_info.payments_profile_id = (
            payments_profile_id
        )

    return billing_setup


def set_billing_setup_date_times(client, customer_id, billing_setup):
    """Sets the starting and ending date times for the new billing setup.

    Queries the customer's account to see if there are any approved billing
    setups. If there are any, the new billing setup starting date time is set to
    one day after the last. If not, the billing setup is set to start
    immediately. The ending date is set to one day after the starting date time.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        billing_setup: the billing setup whose starting and ending date times
            will be set.
    """
    # The query to search existing approved billing setups in the end date time
    # descending order. See get_billing_setup.py for a more detailed example of
    # how to retrieve billing setups.
    query = """
      SELECT
        billing_setup.end_date_time
      FROM billing_setup
      WHERE billing_setup.status = APPROVED
      ORDER BY billing_setup.end_date_time DESC
      LIMIT 1"""

    ga_service = client.get_service("GoogleAdsService")
    stream = ga_service.search_stream(customer_id=customer_id, query=query)
    # Coercing the response iterator to a list causes the stream to be fully
    # consumed so that we can easily access the last row in the request.
    batches = list(stream)
    # Checks if any results were included in the response.
    if batches:
        # Retrieves the ending_date_time of the last BillingSetup.
        last_batch = batches[0]
        last_row = last_batch.results[0]
        last_ending_date_time = last_row.billing_setup.end_date_time

        if not last_ending_date_time:
            # A null ending date time indicates that the current billing setup
            # is set to run indefinitely. Billing setups cannot overlap, so
            # throw an exception in this case.
            raise Exception(
                "Cannot set starting and ending date times for the new billing "
                "setup; the latest existing billing setup is set to run "
                "indefinitely."
            )

        try:
            # BillingSetup.end_date_time is a string that can be in the format
            # %Y-%m-%d or %Y-%m-%d %H:%M:%S. This checks for the first format.
            end_date_time_obj = datetime.strptime(
                last_ending_date_time, "%Y-%m-%d"
            )
        except ValueError:
            # If a ValueError is raised then the end_date_time string is in the
            # second format that includes hours, minutes and seconds.
            end_date_time_obj = datetime.strptime(
                last_ending_date_time, "%Y-%m-%d %H:%M:%S"
            )

        # Sets the new billing setup start date to one day after the end date.
        start_date = end_date_time_obj + timedelta(days=1)
    else:
        # If there are no BillingSetup objects to retrieve, the only acceptable
        # start date time is today.
        start_date = datetime.now()

    billing_setup.start_date_time = start_date.strftime("%Y-%m-%d %H:%M:%S")
    billing_setup.end_date_time = (start_date + timedelta(days=1)).strftime(
        "%Y-%m-%d %H:%M:%S"
    )


if __name__ == "__main__":
    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client = GoogleAdsClient.load_from_storage(version="v16")

    parser = argparse.ArgumentParser(
        description=("Creates a billing setup for a given customer.")
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    # Creates a mutually exclusive argument group to ensure that only one of the
    # following two arguments are given, otherwise it will raise an error.
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument(
        "-a",
        "--payments_account_id",
        type=str,
        help="Either a payments account ID or a payments profile ID must be "
        "provided for the example to run successfully. "
        "See: https://developers.google.com/google-ads/api/docs/billing/billing-setups#creating_new_billing_setups. "
        "Provide an existing payments account ID to link to the new "
        "billing setup. Must be formatted as '1234-5678-9012-3456'.",
    )
    group.add_argument(
        "-p",
        "--payments_profile_id",
        type=str,
        help="Either a payments account ID or a payments profile ID must be "
        "provided for the example to run successfully. "
        "See: https://developers.google.com/google-ads/api/docs/billing/billing-setups#creating_new_billing_setups. "
        "Provide an existing payments profile ID to link to a new payments "
        "account and the new billing setup. Must be formatted as: "
        "'1234-5678-9012-3456'.",
    )
    args = parser.parse_args()

    try:
        main(
            googleads_client,
            args.customer_id,
            args.payments_account_id,
            args.payments_profile_id,
        )
    except GoogleAdsException as ex:
        print(
            f'Request with ID "{ex.request_id}" failed with status '
            f'"{ex.error.code().name}" and includes the following errors:'
        )
        for error in ex.failure.errors:
            print(f'\tError with message "{error.message}".')
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(f"\t\tOn field: {field_path_element.field_name}")
        sys.exit(1)

      

Ruby

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example creates a billing setup for a customer. A billing setup is a link
# between a payments account and a customer. The new billing setup can either
# reuse an existing payments account, or create a new payments account with a
# given payments profile.
# Billing setups are applicable for clients on monthly invoicing only. See here
# for details about applying for monthly invoicing:
# https://support.google.com/google-ads/answer/2375377.
# In the case of consolidated billing, a payments account is linked to the
# manager account and is linked to a customer account via a billing setup.

require 'optparse'
require 'google/ads/google_ads'

def add_billing_setup(customer_id, payments_account_id, payments_profile_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  billing_setup = create_billing_setup(
    client, customer_id, payments_account_id, payments_profile_id)

  set_billing_setup_date_times(client, customer_id, billing_setup)

  # Issues a mutate request to add the billing setup.
  response = client.service.billing_setup.mutate_billing_setup(
    customer_id: customer_id,
    operation: billing_setup
  )

  puts "Added new billing setup with resource name #{response.result.resource_name}"
end

def create_billing_setup(
  client,
  customer_id,
  payments_account_id,
  payments_profile_id)
  client.operation.create_resource.billing_setup do |b|
    # Sets the appropriate payments account field.
    if payments_account_id
      # If a payments account ID has been provided, set the resource name.
      # You can list available payments accounts via the PaymentsAccountService's
      # ListPaymentsAccounts method.
      b.payments_account = client.path.payments_account(customer_id, payments_account_id)
    elsif payments_profile_id
      # Otherwise, create a new payments account by setting the payments account info.
      # See https://support.google.com/google-ads/answer/7268503 for more information about
      # payments profiles.
      b.payments_account_info = client.resource.payments_account_info do |pai|
        pai.payments_account_name = "Payment Account #{(Time.new.to_f * 1000).to_i}"
        pai.payments_profile_id = payments_profile_id
      end
    else
      raise "No payments account ID or payments profile ID is provided."
    end
  end
end

def set_billing_setup_date_times(client, customer_id, billing_setup)
  # The query to search existing approved billing setups in the end date time
  # descending order.
  # See get_billing_setup.rb for a more detailed example of how to retrieve
  # billing setups.
  query = <<~QUERY
    SELECT billing_setup.end_date_time
    FROM billing_setup
    WHERE billing_setup.status = APPROVED
    ORDER BY billing_setup.end_date_time DESC
  QUERY

  # Issues a search stream request.
  stream = client.service.google_ads.search_stream(
    customer_id: customer_id,
    query: query,
  )

  start_date = DateTime.parse(Date.today.strftime("%Y%m%d"))

  # Retrieves the ending date time of the last billing setup.
  row = stream.first.results.first
  if row
    last_ending_date_time_string = row.billing_setup.end_date_time
    if last_ending_date_time_string.nil?
      raise "Cannot set starting and ending date times for the new billing setup." \
        "The latest existing billing setup is set to run indefinitely."
    end
    # Sets the new billing setup to start one day after the ending date time.
    start_date = DateTime.parse(last_ending_date_time_string) + 1
  end

  # Sets the new billing setup start date and end date.
  billing_setup.start_date_time = start_date.strftime("%Y-%m-%d")
  billing_setup.end_date_time = (start_date + 1).strftime("%Y-%m-%d")
end

if __FILE__ == $0
  options = {}
  # The following parameter(s) should be provided to run the example. You can
  # either specify these by changing the INSERT_XXX_ID_HERE values below, or on
  # the command line.
  #
  # Parameters passed on the command line will override any parameters set in
  # code.
  #
  # Running the example with -h will print the command line usage.
  options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'
  # Provide an existing payments account ID to link to the new billing setup.
  # Must be formatted as "1234-5678-9012-3456".
  options[:payments_account_id] = nil
  # Alternatively, provide a payments profile ID which will be linked to a new
  # payments account and the new billing setup. Must be formatted
  # as "1234-5678-9012".
  options[:payments_profile_id] = nil

  OptionParser.new do |opts|
    opts.banner = sprintf('Usage: %s [options]', File.basename(__FILE__))

    opts.separator ''
    opts.separator 'Options:'

    opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
      options[:customer_id] = v
    end

    opts.on('-p', '--payments-account-id PAYMENTS-ACCOUNT-ID', String, 'Payments Account ID') do |v|
      options[:payments_account_id] = v
    end

    opts.on('-P', '--payments-profile-id PAYMENTS-PROFILE-ID', String, 'Payments Profile ID') do |v|
      options[:payments_profile_id] = v
    end

    opts.separator ''
    opts.separator 'Help:'

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  begin
    add_billing_setup(
      options.fetch(:customer_id).tr("-", ""),
      options[:payments_account_id],
      options[:payments_profile_id],
    )
  rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
    e.failure.errors.each do |error|
      STDERR.printf("Error with message: %s\n", error.message)
      if error.location
        error.location.field_path_elements.each do |field_path_element|
          STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
        end
      end
      error.error_code.to_h.each do |k, v|
        next if v == :UNSPECIFIED
        STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
      end
    end
    raise
  end
end

      

Perl

#!/usr/bin/perl -w
#
# Copyright 2020, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example creates a billing setup for a customer. A billing setup is a link
# between a payments account and a customer. The new billing setup can either reuse
# an existing payments account, or create a new payments account with a given
# payments profile.
#
# Billing setups are applicable for clients on monthly invoicing only. See here
# for details about applying for monthly invoicing:
# https://support.google.com/google-ads/answer/2375377.
#
# In the case of consolidated billing, a payments account is linked to the manager
# account and is linked to a customer account via a billing setup.

use strict;
use warnings;
use utf8;

use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::V16::Resources::BillingSetup;
use Google::Ads::GoogleAds::V16::Resources::PaymentsAccountInfo;
use
  Google::Ads::GoogleAds::V16::Services::BillingSetupService::BillingSetupOperation;
use Google::Ads::GoogleAds::V16::Utils::ResourceNames;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd          qw(abs_path);
use Data::Uniqid qw(uniqid);
use Date::Parse;
use POSIX qw(strftime);

# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my $customer_id = "INSERT_CUSTOMER_ID_HERE";
# Either a payments account ID or a payments profile ID must be provided for the
# example to run successfully. If both are provided, only the payments account ID
# will be used. See:
# https://developers.google.com/google-ads/api/docs/billing/billing-setups#creating_new_billing_setups
#
# Provide an existing payments account ID to link to the new billing setup. Must
# be formatted as "1234-5678-9012-3456".
my $payments_account_id = undef;
# Alternatively, provide a payments profile ID which will be linked to a new payments
# account and the new billing setup. Must be formatted as "1234-5678-9012".
my $payments_profile_id = undef;

sub add_billing_setup {
  my ($api_client, $customer_id, $payments_account_id, $payments_profile_id) =
    @_;

  # Construct a new billing setup.
  my $billing_setup = create_billing_setup($customer_id, $payments_account_id,
    $payments_profile_id);
  set_billing_setup_date_times($api_client, $customer_id, $billing_setup);

  my $billing_setup_operation =
    Google::Ads::GoogleAds::V16::Services::BillingSetupService::BillingSetupOperation
    ->new({
      create => $billing_setup
    });

  # Issue a mutate request to add the billing setup.
  my $billing_setup_response = $api_client->BillingSetupService()->mutate({
    customerId => $customer_id,
    operation  => $billing_setup_operation
  });

  printf
    "Added new billing setup with resource name '%s'.\n",
    $billing_setup_response->{result}{resourceName};

  return 1;
}

# Creates and returns a new billing setup instance with complete payment details.
# One of the payments account ID or payments profile ID must be provided.
sub create_billing_setup {
  my ($customer_id, $payments_account_id, $payments_profile_id) = @_;

  my $billing_setup =
    Google::Ads::GoogleAds::V16::Resources::BillingSetup->new();

  # Set the appropriate payments account field.
  if (defined $payments_account_id) {
    # If a payments account ID has been provided, set the resource name.
    # You can list available payments accounts via the PaymentsAccountService's
    # list method.
    $billing_setup->{paymentsAccount} =
      Google::Ads::GoogleAds::V16::Utils::ResourceNames::payments_account(
      $customer_id, $payments_account_id);
  } elsif (defined $payments_profile_id) {
    # Otherwise, create a new payments account by setting the payments account
    # info. See https://support.google.com/google-ads/answer/7268503 for more
    # information about payments profiles.
    $billing_setup->{paymentsAccountInfo} =
      Google::Ads::GoogleAds::V16::Resources::PaymentsAccountInfo->new({
        paymentsAccountName => "Payments Account #" . uniqid(),
        paymentsProfileId   => $payments_profile_id
      });
  } else {
    die "No payments account ID or payments profile ID is provided.\n";
  }

  return $billing_setup;
}

# Sets the starting and ending date times for the new billing setup. Queries the
# customer's account to see if there are any approved billing setups. If there are
# any, the new billing setup starting date time is set to one day after the last.
# If not, the billing setup is set to start immediately. The ending date is set
# to one day after the starting date time.
sub set_billing_setup_date_times {
  my ($api_client, $customer_id, $billing_setup) = @_;

  # The query to search existing approved billing setups in the end date time
  # descending order.
  # See get_billing_setup.pl for a more detailed example of how to retrieve
  # billing setups.
  my $search_query =
    "SELECT billing_setup.end_date_time " .
    "FROM billing_setup " . "WHERE billing_setup.status = 'APPROVED' " .
    "ORDER BY billing_setup.end_date_time DESC";

  # Issue a search request.
  my $search_response = $api_client->GoogleAdsService()->search({
    customerId => $customer_id,
    query      => $search_query
  });
  my $google_ads_row = $search_response->{results}[0];

  my $start_date = undef;
  if (defined $google_ads_row) {
    # Retrieve the ending date time of the last billing setup.
    my $last_ending_date_time_string =
      $google_ads_row->{billingSetup}{endDateTime};

    if (not $last_ending_date_time_string) {
      # A null ending date time indicates that the current billing setup is set
      # to run indefinitely. Billing setups cannot overlap, so die with error
      # in this case.
      die
        "Cannot set starting and ending date times for the new billing setup; "
        . "the latest existing billing setup is set to run indefinitely.\n";
    }

    # Set the new billing setup to start one day after the ending date time.
    $start_date = str2time($last_ending_date_time_string) + 60 * 60 * 24;
  } else {
    # Otherwise, the only acceptable start date time is today.
    $start_date = time;
  }

  $billing_setup->{startDateTime} =
    strftime("%Y-%m-%d", localtime($start_date));
  # Set the new billing setup to end one day after the starting date time.
  $billing_setup->{endDateTime} =
    strftime("%Y-%m-%d", localtime($start_date + 60 * 60 * 24));
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my $api_client = Google::Ads::GoogleAds::Client->new();

# By default examples are set to die on any server returned fault.
$api_client->set_die_on_faults(1);

# Parameters passed on the command line will override any parameters set in code.
GetOptions(
  "customer_id=s"         => \$customer_id,
  "payments_account_id=s" => \$payments_account_id,
  "payments_profile_id=s" => \$payments_profile_id,
);

# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id);

# Call the example.
add_billing_setup(
  $api_client,          $customer_id =~ s/-//gr,
  $payments_account_id, $payments_profile_id
);

=pod

=head1 NAME

add_billing_setup

=head1 DESCRIPTION

This example creates a billing setup for a customer. A billing setup is a link
between a payments account and a customer. The new billing setup can either reuse
an existing payments account, or create a new payments account with a given
payments profile.

Billing setups are applicable for clients on monthly invoicing only. See here
for details about applying for monthly invoicing:
https://support.google.com/google-ads/answer/2375377.

In the case of consolidated billing, a payments account is linked to the manager
account and is linked to a customer account via a billing setup.

=head1 SYNOPSIS

add_billing_setup.pl [options]

    -help                       Show the help message.
    -customer_id                The Google Ads customer ID.
    -payments_account_id        [optional] The payments account ID to attach to the new billing setup.
                                Must be formatted as "1234-5678-9012-3456"
    -payments_profile_id        [optional] The payments profile ID to attach to a new payments account
                                and to the new billing setup. Must be formatted as "1234-5678-9012"

=cut