From 2a6d59f114334267e22f4469ade27512299ee67c Mon Sep 17 00:00:00 2001 From: dorasun Date: Tue, 7 Jul 2026 11:34:52 +0000 Subject: [PATCH 1/3] Add incentives examples Change-Id: I57fa8a776fb8a1cbd43f6c1d3a1a71c3c63bdd19 --- examples/incentives/apply_incentive.rb | 111 ++++++++++++++++++ examples/incentives/fetch_incentive.rb | 155 +++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 examples/incentives/apply_incentive.rb create mode 100644 examples/incentives/fetch_incentive.rb diff --git a/examples/incentives/apply_incentive.rb b/examples/incentives/apply_incentive.rb new file mode 100644 index 000000000..e0b29df46 --- /dev/null +++ b/examples/incentives/apply_incentive.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +# Copyright 2026 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 applies an incentive to a user's account. +# +# This example is a no-op if the user already has an accepted incentive. If the user attempts to +# apply a new incentive, the response will simply return the existing incentive that has already +# been applied to the account. + +require 'google/ads/google_ads' +require 'optparse' + +# [START apply_incentive] +def apply_incentive(customer_id, incentive_id, country_code) + # GoogleAdsClient will read a config file from a default location + # if no path is passed. + client = Google::Ads::GoogleAds::GoogleAdsClient.new + + # Issues the request. + response = client.service.incentive.apply_incentive( + customer_id: customer_id, + selected_incentive_id: incentive_id.to_i, + country_code: country_code + ) + + # Processes the response. + puts "Incentive was created at '#{response.creation_time}'." + puts "Applied incentive with coupon code '#{response.coupon_code}'." +end +# [END apply_incentive] + +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' + + # The country code defaults to US. + options[:country_code] = 'US' + + 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.tr('-', '') + end + + opts.on('-I', '--incentive-id INCENTIVE-ID', String, 'Incentive ID') do |v| + options[:incentive_id] = v + end + + opts.on('-K', '--country-code COUNTRY-CODE', String, 'Country Code') do |v| + options[:country_code] = v + end + + opts.separator '' + opts.separator 'Help:' + + opts.on_tail('-h', '--help', 'Show this message') do + puts opts + exit + end + end.parse! + + # Check if required parameters are present. + if options[:customer_id].nil? || options[:incentive_id].nil? + puts "Missing required arguments. See usage:" + puts "Customer ID and Incentive ID are required." + exit 1 + end + + begin + apply_incentive(options[:customer_id], options[:incentive_id], options[:country_code]) + 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 diff --git a/examples/incentives/fetch_incentive.rb b/examples/incentives/fetch_incentive.rb new file mode 100644 index 000000000..2b2403905 --- /dev/null +++ b/examples/incentives/fetch_incentive.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +# Copyright 2026 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 fetches the available incentives for a user. + +require 'google/ads/google_ads' +require 'optparse' + +def fetch_incentive(email, language_code, country_code) + # GoogleAdsClient will read a config file from a default location + # if no path is passed. + client = Google::Ads::GoogleAds::GoogleAdsClient.new + + # Issues the request. + response = client.service.incentive.fetch_incentive( + email: email, + language_code: language_code, + country_code: country_code, + # IncentiveType is usually an enum, we can refer to it via its symbol representation + # or the exact class if needed. Let's pass the symbol :ACQUISITION. + type: :ACQUISITION + ) + + # Processes the response. + if response.incentive_offer.nil? + puts "No incentive offer was found" + return + end + + # If the offer type is CHOOSE_YOUR_OWN_INCENTIVE, there will be 3 incentives in the + # response. At the time this example was written, all incentive offers are CYO incentive offers. + if response.incentive_offer.cyo_incentives + cyo_incentives = response.incentive_offer.cyo_incentives + print_incentive_details(cyo_incentives.low_offer) + print_incentive_details(cyo_incentives.medium_offer) + print_incentive_details(cyo_incentives.high_offer) + end +rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e + puts "Request ID #{e.request_id} failed due to GoogleAdsError." + e.failure.errors.each_with_index do |error, i| + puts " Error #{i}: #{error.message}" + end + exit 1 +end + +def print_incentive_details(incentive) + return if incentive.nil? + + puts "====================================================================" + puts "Incentive ID: '#{incentive.incentive_id}'" + puts "Incentive requirement: '#{format_requirement(incentive.requirement)}'" + puts "Incentive terms and conditions: '#{incentive.incentive_terms_and_conditions_url}'" + puts "====================================================================" +end + +def format_requirement(requirement) + return 'No requirements' if requirement.nil? + + if requirement.spend + spend = requirement.spend + required = format_money(spend.required_amount) + award = format_money(spend.award_amount) + "Spend #{required} to receive #{award}" + else + requirement.to_s + end +end + +def format_money(money) + return 'N/A' if money.nil? + + amount = money.units + amount += money.nanos / 1_000_000_000.0 if money.nanos > 0 + + formatted_amount = money.nanos > 0 ? sprintf("%.2f", amount) : amount.to_s + "#{formatted_amount} #{money.currency_code}" +end + +if __FILE__ == $0 + options = {} + # The following parameter(s) should be provided to run the example. You can + # either specify these by changing the default 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[:language_code] = 'en' + options[:country_code] = 'US' + + OptionParser.new do |opts| + opts.banner = sprintf('Usage: %s [options]', File.basename(__FILE__)) + + opts.separator '' + opts.separator 'Options:' + + opts.on('-E', '--email EMAIL', String, 'Email') do |v| + options[:email] = v + end + + opts.on('-L', '--language-code LANGUAGE-CODE', String, 'Language Code') do |v| + options[:language_code] = v + end + + opts.on('-K', '--country-code COUNTRY-CODE', String, 'Country Code') do |v| + options[:country_code] = v + end + + opts.separator '' + opts.separator 'Help:' + + opts.on_tail('-h', '--help', 'Show this message') do + puts opts + exit + end + end.parse! + + # Check if required parameters are present. + if options[:email].nil? + puts "Missing required argument: Email is required." + exit 1 + end + + begin + fetch_incentive(options[:email], options[:language_code], options[:country_code]) + 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 From 0568d0b7a0ff783842af7f3a5ca82edd1c8e9bf3 Mon Sep 17 00:00:00 2001 From: dorasun Date: Thu, 16 Jul 2026 19:52:31 +0000 Subject: [PATCH 2/3] Respond to offline feedback Change-Id: I2f4db5b40ddc0494f631b62d60b6992f786cbf57 --- examples/incentives/apply_incentive.rb | 16 ++++++++++------ examples/incentives/fetch_incentive.rb | 18 ++++++------------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/examples/incentives/apply_incentive.rb b/examples/incentives/apply_incentive.rb index e0b29df46..633c9bae3 100644 --- a/examples/incentives/apply_incentive.rb +++ b/examples/incentives/apply_incentive.rb @@ -30,11 +30,13 @@ def apply_incentive(customer_id, incentive_id, country_code) client = Google::Ads::GoogleAds::GoogleAdsClient.new # Issues the request. - response = client.service.incentive.apply_incentive( + request_args = { customer_id: customer_id, - selected_incentive_id: incentive_id.to_i, - country_code: country_code - ) + selected_incentive_id: incentive_id + } + request_args[:country_code] = country_code if country_code + + response = client.service.incentive.apply_incentive(request_args) # Processes the response. puts "Incentive was created at '#{response.creation_time}'." @@ -67,7 +69,7 @@ def apply_incentive(customer_id, incentive_id, country_code) options[:customer_id] = v.tr('-', '') end - opts.on('-I', '--incentive-id INCENTIVE-ID', String, 'Incentive ID') do |v| + opts.on('-I', '--incentive-id INCENTIVE-ID', Integer, 'Incentive ID') do |v| options[:incentive_id] = v end @@ -85,7 +87,9 @@ def apply_incentive(customer_id, incentive_id, country_code) end.parse! # Check if required parameters are present. - if options[:customer_id].nil? || options[:incentive_id].nil? + if options[:customer_id].nil? + || options[:customer_id] == 'INSERT_CUSTOMER_ID_HERE' + || options[:incentive_id].nil? puts "Missing required arguments. See usage:" puts "Customer ID and Incentive ID are required." exit 1 diff --git a/examples/incentives/fetch_incentive.rb b/examples/incentives/fetch_incentive.rb index 2b2403905..45282ff1d 100644 --- a/examples/incentives/fetch_incentive.rb +++ b/examples/incentives/fetch_incentive.rb @@ -29,8 +29,7 @@ def fetch_incentive(email, language_code, country_code) email: email, language_code: language_code, country_code: country_code, - # IncentiveType is usually an enum, we can refer to it via its symbol representation - # or the exact class if needed. Let's pass the symbol :ACQUISITION. + # Passing :ACQUISITION as the symbol representation of the IncentiveType enum. type: :ACQUISITION ) @@ -48,12 +47,6 @@ def fetch_incentive(email, language_code, country_code) print_incentive_details(cyo_incentives.medium_offer) print_incentive_details(cyo_incentives.high_offer) end -rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e - puts "Request ID #{e.request_id} failed due to GoogleAdsError." - e.failure.errors.each_with_index do |error, i| - puts " Error #{i}: #{error.message}" - end - exit 1 end def print_incentive_details(incentive) @@ -82,10 +75,11 @@ def format_requirement(requirement) def format_money(money) return 'N/A' if money.nil? - amount = money.units - amount += money.nanos / 1_000_000_000.0 if money.nanos > 0 - - formatted_amount = money.nanos > 0 ? sprintf("%.2f", amount) : amount.to_s + formatted_amount = if money.nanos != 0 + sprintf("%.2f", money.units + (money.nanos / 1_000_000_000.0)) + else + money.units.to_s + end "#{formatted_amount} #{money.currency_code}" end From 0b40d6d29ec6aa351a881f59587a28902f3f4ea6 Mon Sep 17 00:00:00 2001 From: Dora Sun Date: Thu, 16 Jul 2026 17:03:06 -0400 Subject: [PATCH 3/3] Minor spacing fix --- examples/incentives/apply_incentive.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/incentives/apply_incentive.rb b/examples/incentives/apply_incentive.rb index 633c9bae3..9dd49d40e 100644 --- a/examples/incentives/apply_incentive.rb +++ b/examples/incentives/apply_incentive.rb @@ -87,9 +87,9 @@ def apply_incentive(customer_id, incentive_id, country_code) end.parse! # Check if required parameters are present. - if options[:customer_id].nil? - || options[:customer_id] == 'INSERT_CUSTOMER_ID_HERE' - || options[:incentive_id].nil? + if options[:customer_id].nil? || + options[:customer_id] == 'INSERT_CUSTOMER_ID_HERE' || + options[:incentive_id].nil? puts "Missing required arguments. See usage:" puts "Customer ID and Incentive ID are required." exit 1