/
get_account_hierarchy.pl
315 lines (263 loc) · 11.4 KB
/
get_account_hierarchy.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
#!/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.
#
# Gets the account hierarchy of the specified manager customer ID and login customer
# ID. If you don't specify them, the example will instead print the hierarchies
# of all accessible customer accounts for your authenticated Google account.
#
# Note that if the list of accessible customers for your authenticated Google
# account includes accounts within the same hierarchy, this example will retrieve
# and print the overlapping portions of the hierarchy for each accessible customer.
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::Utils::SearchStreamHandler;
use
Google::Ads::GoogleAds::V4::Services::GoogleAdsService::SearchGoogleAdsStreamRequest;
use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd qw(abs_path);
# 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.
#
# Optional: You may pass the manager customer ID on the command line or specify
# it here. If neither are set, a null value will be passed to run the example,
# and the example will print the hierarchies of all accessible customer IDs.
my $manager_customer_id = undef;
# Optional: You may pass the login customer ID on the command line or specify it
# here if and only if the manager customer ID is set. If the login customer ID
# is set neither on the command line nor below, a null value will be passed to
# run the example, and the example will use each accessible customer ID as the
# login customer ID.
my $login_customer_id = undef;
# Stores the mapping from the root customer IDs (the ones that will be used as a
# start point for printing each hierarchy) to their `CustomerClient` objects.
my $root_customer_clients = {};
sub get_account_hierarchy {
my ($api_client, $manager_customer_id, $login_customer_id) = @_;
my $root_customer_ids = [];
if (not $manager_customer_id) {
# Get the account hierarchies for all accessible customers.
$root_customer_ids = get_accessible_customers($api_client);
} else {
# Only get the hierarchy for the provided manager customer ID if provided.
push @$root_customer_ids, $manager_customer_id;
}
my $all_hierarchies = {};
my $accounts_with_no_info = [];
# Construct a map of account hierarchies.
foreach my $root_customer_id (@$root_customer_ids) {
my $customer_client_to_hierarchy =
create_customer_client_to_hierarchy($login_customer_id,
$root_customer_id);
if (not $customer_client_to_hierarchy) {
push @$accounts_with_no_info, $root_customer_id;
} else {
$all_hierarchies = {%$all_hierarchies, %$customer_client_to_hierarchy};
}
}
# Print the IDs of any accounts that did not produce hierarchy information.
if (scalar @$accounts_with_no_info > 0) {
print "Unable to retrieve information for the following accounts " .
"which are likely either test accounts or accounts with setup issues. " .
"Please check the logs for details:\n";
foreach my $account_id (@$accounts_with_no_info) {
print "$account_id\n";
}
print "\n";
}
# Print the hierarchy information for all accounts for which there is hierarchy
# information available.
foreach my $root_customer_id (keys %$all_hierarchies) {
printf "The hierarchy of customer ID %d is printed below:\n",
$root_customer_id;
print_account_hierarchy($root_customer_clients->{$root_customer_id},
$all_hierarchies->{$root_customer_id}, 0);
print "\n";
}
return 1;
}
# Retrieves a list of accessible customers with the provided set up credentials.
sub get_accessible_customers {
my $api_client = shift;
my $accessible_customer_ids = [];
# Issue a request for listing all customers accessible by this authenticated
# Google account.
my $list_accessible_customers_response =
$api_client->CustomerService()->list_accessible_customers();
print "No manager customer ID is specified. The example will print the " .
"hierarchies of all accessible customer IDs:\n";
foreach my $customer_resource_name (
@{$list_accessible_customers_response->{resourceNames}})
{
my $customer_id = $1 if $customer_resource_name =~ /(\d+)$/;
print "$customer_id\n";
push @$accessible_customer_ids, $customer_id;
}
return $accessible_customer_ids;
}
# Creates a map between a customer client and each of its managers' mappings.
sub create_customer_client_to_hierarchy() {
my ($login_customer_id, $root_customer_id) = @_;
# Create a GoogleAdsClient with the specified login customer ID. Seec
# https://developers.google.com/google-ads/api/docs/concepts/call-structure#cid
# for more information.
my $api_client = Google::Ads::GoogleAds::Client->new({
login_customer_id => $login_customer_id || $root_customer_id
});
# Get the GoogleAdsService.
my $google_ads_service = $api_client->GoogleAdsService();
# Create a query that retrieves all child accounts of the manager specified in
# search calls below.
my $search_query =
"SELECT customer_client.client_customer, customer_client.level, " .
"customer_client.manager, customer_client.descriptive_name, " .
"customer_client.currency_code, customer_client.time_zone, " .
"customer_client.id " .
"FROM customer_client WHERE customer_client.level <= 1";
my $root_customer_client = undef;
# Add the root customer ID to the list of IDs to be processed.
my $manager_customer_ids_to_search = [$root_customer_id];
# Perform a breadth-first search algorithm to build a mapping of managers to
# their child accounts.
my $customer_ids_to_child_accounts = {};
while (scalar @$manager_customer_ids_to_search > 0) {
my $customer_id_to_search = shift @$manager_customer_ids_to_search;
$customer_ids_to_child_accounts->{$customer_id_to_search} ||= [];
my $search_stream_handler =
Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
service => $google_ads_service,
request =>
Google::Ads::GoogleAds::V4::Services::GoogleAdsService::SearchGoogleAdsStreamRequest
->new({
customerId => $customer_id_to_search,
query => $search_query,
})});
# Iterate over all elements to get all customer clients under the specified
# customer's hierarchy.
$search_stream_handler->process_contents(
sub {
my $google_ads_row = shift;
my $customer_client = $google_ads_row->{customerClient};
# Get the CustomerClient object for the root customer in the tree.
if ($customer_client->{id} == $root_customer_id) {
$root_customer_client = $customer_client;
$root_customer_clients->{$root_customer_id} = $root_customer_client;
}
# The steps below map parent and children accounts. Return here so that
# manager accounts exclude themselves from the list of their children
# accounts.
if ($customer_client->{id} == $customer_id_to_search) {
return;
}
# For all level-1 (direct child) accounts that are manager accounts, the
# above query will be run against them to create a map of managers to their
# child accounts for printing the hierarchy afterwards.
push @{$customer_ids_to_child_accounts->{$customer_id_to_search}},
$customer_client;
# Check if the child account is a manager itself so that it can later be
# processed and added to the map if it hasn't been already.
if ($customer_client->{manager}) {
# A customer can be managed by multiple managers, so to prevent visiting
# the same customer multiple times, we need to check if it's already
# in the map.
my $already_visited =
exists $customer_ids_to_child_accounts->{$customer_client->{id}};
if (not $already_visited && $customer_client->{level} == 1) {
push @$manager_customer_ids_to_search, $customer_client->{id};
}
}
});
}
return $root_customer_client
? {$root_customer_client->{id} => $customer_ids_to_child_accounts}
: undef;
}
# Prints the specified account's hierarchy using recursion.
sub print_account_hierarchy {
my ($customer_client, $customer_ids_to_child_accounts, $depth) = @_;
if ($depth == 0) {
print "Customer ID (Descriptive Name, Currency Code, Time Zone)\n";
}
my $customer_id = $customer_client->{id};
print "--" x $depth;
printf
" %d ('%s', '%s', '%s')\n",
$customer_id,
$customer_client->{descriptiveName} || "",
$customer_client->{currencyCode},
$customer_client->{timeZone};
# Recursively call this function for all child accounts of $customer_client.
if (exists $customer_ids_to_child_accounts->{$customer_id}) {
foreach
my $child_account (@{$customer_ids_to_child_accounts->{$customer_id}})
{
print_account_hierarchy($child_account, $customer_ids_to_child_accounts,
$depth + 1);
}
}
}
# 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(
"manager_customer_id=s" => \$manager_customer_id,
"login_customer_id=s" => \$login_customer_id
);
if ($manager_customer_id xor $login_customer_id) {
die "Both the manager customer ID and login customer ID must be " .
"provided together, or they must both be null.\n";
}
# Call the example.
get_account_hierarchy(
$api_client,
$manager_customer_id ? $manager_customer_id =~ s/-//gr
: undef,
$login_customer_id ? $login_customer_id =~ s/-//gr
: undef
);
=pod
=head1 NAME
get_account_hierarchy
=head1 DESCRIPTION
Gets the account hierarchy of the specified manager customer ID and login customer
ID. If you don't specify them, the example will instead print the hierarchies
of all accessible customer accounts for your authenticated Google account.
Note that if the list of accessible customers for your authenticated Google
account includes accounts within the same hierarchy, this example will retrieve
and print the overlapping portions of the hierarchy for each accessible customer.
=head1 SYNOPSIS
get_account_hierarchy.pl [options]
-help Show the help message.
-manager_customer_id [optional] The Google Ads manager customer ID.
-login_customer_id [optional] The login customer ID.
=cut