Skip to content

Commit 0b92847

Browse files
authored
Add analyzer demo code (intern project) (#584)
1 parent 680a48a commit 0b92847

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#!/usr/bin/env python
2+
# Copyright 2021 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
"""Gets the account infomation of the given MCC and login customer."""
16+
17+
18+
import argparse
19+
import sys
20+
21+
from google.ads.googleads.client import GoogleAdsClient
22+
from google.ads.googleads.errors import GoogleAdsException
23+
24+
_DEFAULT_LOG_SPACE_LENGTH = 4
25+
26+
27+
def account_hierarchy_module(google_ads_client, customer_id):
28+
"""Print the account hierarchy for the given login customer ID.
29+
30+
Args:
31+
client: an initialized GoogleAdsClient instance.
32+
customer_id: the given customer ID for getting the hierarchy info.
33+
"""
34+
googleads_service = google_ads_client.get_service("GoogleAdsService")
35+
customer_service = google_ads_client.get_service("CustomerService")
36+
# A collection of customer IDs to handle.
37+
seed_customer_ids = []
38+
39+
# If a manager ID was provided in the customer ID parameter, it will be
40+
# the only ID in the list. Otherwise, we will issue a request for all
41+
# customers accessible by this authenticated Google account.
42+
if customer_id:
43+
seed_customer_ids = [customer_id]
44+
else:
45+
print(
46+
"No manager ID is specified. The example will print the "
47+
"hierarchies of all accessible customer IDs."
48+
)
49+
# Starting in v10 this will list all customers, not just customers with
50+
# ENABLED status. If you wish to only show ENABLED customers, you can
51+
# further filter by the Customer.status field.
52+
accessible_customers = customer_service.list_accessible_customers()
53+
customer_resource_names = accessible_customers.resource_names
54+
print(f"Total results: {len(customer_resource_names)}")
55+
for resource_name in customer_resource_names:
56+
print(f'Customer resource name: "{resource_name}"')
57+
seed_customer_ids.append(resource_name.split("/")[1])
58+
59+
# Creates a query that retrieves all child accounts of the manager
60+
# specified in search calls below.
61+
query = """
62+
SELECT
63+
customer_client.client_customer,
64+
customer_client.level,
65+
customer_client.manager,
66+
customer_client.descriptive_name,
67+
customer_client.currency_code,
68+
customer_client.time_zone,
69+
customer_client.id
70+
FROM customer_client
71+
WHERE customer_client.level <= 1"""
72+
73+
for seed_customer_id in seed_customer_ids:
74+
# Performs a breadth-first search to build a Dictionary that maps
75+
# managers to their child accounts (customer_ids_to_child_accounts).
76+
unprocessed_customer_ids = [seed_customer_id]
77+
customer_ids_to_child_accounts = dict()
78+
root_customer_client = None
79+
80+
while unprocessed_customer_ids:
81+
customer_id = unprocessed_customer_ids.pop(0)
82+
response = googleads_service.search(
83+
customer_id=customer_id, query=query
84+
)
85+
86+
# Iterates over all rows in all pages to get all customer
87+
# clients under the specified customer's hierarchy.
88+
for row in response:
89+
customer_client = row.customer_client
90+
91+
# The customer client with level 0 is the specified customer.
92+
if customer_client.level == 0:
93+
if root_customer_client is None:
94+
root_customer_client = customer_client
95+
# If it's level 0, we need to skip this round of loop.
96+
continue
97+
98+
# For all level 1 (direct child) accounts that are a
99+
# manager account, the above query will be run against them
100+
# to create a dictionary of managers mapped to their child
101+
# accounts for printing the hierarchy afterwards.
102+
if customer_id not in customer_ids_to_child_accounts:
103+
customer_ids_to_child_accounts[customer_id] = []
104+
105+
customer_ids_to_child_accounts[customer_id].append(
106+
customer_client
107+
)
108+
109+
if customer_client.manager:
110+
# A customer can be managed by multiple managers, so to
111+
# prevent visiting the same customer many times, we
112+
# need to check if it's already in the dictionary.
113+
if (
114+
customer_client.id not in customer_ids_to_child_accounts
115+
and customer_client.level == 1
116+
):
117+
unprocessed_customer_ids.append(customer_client.id)
118+
119+
if root_customer_client is not None:
120+
print(
121+
"\nThe hierarchy of customer ID "
122+
f"{root_customer_client.id} is printed below:"
123+
)
124+
_print_account_hierarchy(
125+
root_customer_client, customer_ids_to_child_accounts, 0
126+
)
127+
else:
128+
print(f"No hierarchy info was found for Customer ID {customer_id}.")
129+
130+
131+
def _print_account_hierarchy(
132+
customer_client, customer_ids_to_child_accounts, depth
133+
):
134+
"""Prints the specified account's hierarchy using recursion.
135+
136+
Args:
137+
customer_client: a customer_client resource that contains current
138+
account information.
139+
customer_ids_to_child_accounts: a mapping between customer_ids and
140+
their child accounts.
141+
depth: the current depth from the root node.
142+
"""
143+
if depth == 0:
144+
print("Customer ID (Descriptive Name, Currency Code, Time Zone)")
145+
customer_id = str(customer_client.id)
146+
print("-" * (depth * _DEFAULT_LOG_SPACE_LENGTH + 1), end="")
147+
print(
148+
f"{customer_id} ({customer_client.descriptive_name}, "
149+
f"{customer_client.currency_code}, "
150+
f"{customer_client.time_zone})"
151+
)
152+
# Recursively call this function for all child accounts of customer_client.
153+
if customer_id in customer_ids_to_child_accounts:
154+
for child_account in customer_ids_to_child_accounts[customer_id]:
155+
_print_account_hierarchy(
156+
child_account, customer_ids_to_child_accounts, depth + 1
157+
)
158+
159+
160+
def get_users_module(google_ads_client, customer_id):
161+
"""Prints the user access informaion for the given customer_id.
162+
163+
Args:
164+
client: an initialized GoogleAdsClient instance.
165+
customer_id: the given customer ID for retrieving customer user access
166+
info.
167+
"""
168+
googleads_service = google_ads_client.get_service("GoogleAdsService")
169+
customer_service = google_ads_client.get_service("CustomerService")
170+
query = f"""
171+
SELECT
172+
customer_user_access.user_id,
173+
customer_user_access.email_address,
174+
customer_user_access.access_role,
175+
customer_user_access.access_creation_date_time,
176+
customer_user_access.inviter_user_email_address
177+
FROM customer_user_access
178+
"""
179+
response = googleads_service.search(customer_id=customer_id, query=query)
180+
181+
for customer_user_access in response:
182+
user_access = customer_user_access.customer_user_access
183+
print(
184+
"The given customer ID has access to the client account with ID "
185+
f"{user_access.user_id}, with an access role of "
186+
f"'{user_access.access_role.name}', and creation time of "
187+
f"'{user_access.access_creation_date_time}'."
188+
)
189+
190+
191+
if __name__ == "__main__":
192+
# GoogleAdsClient will read the google-ads.yaml configuration file in the
193+
# home directory if none is specified.
194+
parser = argparse.ArgumentParser(
195+
description="This analyzer will display the account info "
196+
"according to the input."
197+
)
198+
# process argument(s)
199+
parser.add_argument(
200+
"-c",
201+
"--customer_id",
202+
type=str,
203+
required=False,
204+
help="The Google Ads customer ID.",
205+
)
206+
args = parser.parse_args()
207+
208+
try:
209+
googleads_client = GoogleAdsClient.load_from_storage()
210+
account_hierarchy_module(googleads_client, args.customer_id)
211+
get_users_module(googleads_client, args.customer_id)
212+
except GoogleAdsException as ex:
213+
print(
214+
f'Request with ID "{ex.request_id}" failed with status '
215+
f'"{ex.error.code().name}" '
216+
)
217+
print(f"And includes the following errors:")
218+
for error in ex.failure.errors:
219+
print(f'\tError with message "{error.message}".')
220+
if error.location:
221+
for field_path_element in error.location.field_path_elements:
222+
print(f"\t\tOn field: {field_path_element.field_name}")
223+
sys.exit(1)

0 commit comments

Comments
 (0)