diff --git a/examples/incentives/apply_incentive.rb b/examples/incentives/apply_incentive.rb new file mode 100644 index 000000000..ccf8c80cf --- /dev/null +++ b/examples/incentives/apply_incentive.rb @@ -0,0 +1,133 @@ +# 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 = 'US') + # GoogleAdsClient will read a config file from a default location + # if no path is passed. + client = Google::Ads::GoogleAds::GoogleAdsClient.new + + # Issues the request. + request_args = { + customer_id: customer_id.to_s.tr('-', ''), + selected_incentive_id: incentive_id&.to_i, + country_code: country_code + }.compact + + response = client.service.incentive.apply_incentive(request_args) + + # Processes the response. + if !response.creation_time.to_s.empty? + puts "Incentive was created at '#{response.creation_time}'." + end + if !response.coupon_code.to_s.empty? + puts "Applied incentive with coupon code '#{response.coupon_code}'." + end +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' + options[:incentive_id] = 'INSERT_INCENTIVE_ID_HERE' + + # The country code defaults to US. + options[:country_code] = 'US' + + parser = 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('-I', '--incentive-id INCENTIVE-ID', Integer, '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 + parser.parse! + + # Check if required parameters are present. + if options[:customer_id].nil? || options[:customer_id] == 'INSERT_CUSTOMER_ID_HERE' + puts "Missing required argument: --customer-id (-C) is required.\n\n" + puts parser + exit 1 + end + + if options[:incentive_id].nil? || options[:incentive_id] == 'INSERT_INCENTIVE_ID_HERE' + puts "Missing required argument: --incentive-id (-I) is required.\n\n" + puts parser + exit 1 + end + + if options[:country_code].to_s.empty? + puts "Missing required argument: --country-code (-K) is required.\n\n" + puts parser + exit 1 + end + + begin + apply_incentive(options[:customer_id], options[:incentive_id], options[:country_code]) + rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e + STDERR.printf("Request with ID '%s' failed with status '%s' and includes the following errors:\n", + e.request_id, e.class.name) + e.failure.errors.each do |error| + STDERR.printf("\tError with message: %s\n", error.message) + if error.location + error.location.field_path_elements.each do |field_path_element| + STDERR.printf("\t\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("\t\tType: %s, Code: %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..b75cd4723 --- /dev/null +++ b/examples/incentives/fetch_incentive.rb @@ -0,0 +1,163 @@ +# 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' + +# [START fetch_incentive] +def fetch_incentive(email, language_code = 'en', country_code = 'US') + # GoogleAdsClient will read a config file from a default location + # if no path is passed. + client = Google::Ads::GoogleAds::GoogleAdsClient.new + + # Issues the request. + request_args = { + email: email, + language_code: language_code, + country_code: country_code, + # Passing :ACQUISITION as the symbol representation of the IncentiveType enum. + incentive_type: :ACQUISITION + }.compact + + response = client.service.incentive.fetch_incentive(request_args) + + # 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 = response.incentive_offer.cyo_incentives + [cyo.low_offer, cyo.medium_offer, cyo.high_offer].compact.each do |incentive| + print_incentive_details(incentive) + end + else + puts 'Incentive offer is not a CHOOSE_YOUR_OWN_INCENTIVE type. ' \ + 'Non-CYO offers are not supported by this example.' + end +end + +def print_incentive_details(incentive) + return if incentive.nil? + + puts '=' * 68 + puts "Incentive ID: '#{incentive.incentive_id}'" + puts "Incentive requirement: '#{format_requirement(incentive.requirement)}'" + if !incentive.incentive_terms_and_conditions_url.to_s.empty? + puts "Incentive terms and conditions: '#{incentive.incentive_terms_and_conditions_url}'" + end + puts '=' * 68 +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 + 'Unsupported requirement type' + end +end + +def format_money(money) + return 'N/A' if money.nil? + + units = (money.units || 0).to_f + nanos = (money.nanos || 0).to_f + currency = money.currency_code.to_s.empty? ? '' : " #{money.currency_code}" + + amount = units + (nanos / 1_000_000_000.0) + sprintf('%.2f%s', amount, currency) +end +# [END fetch_incentive] + +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[:email] = 'INSERT_EMAIL_HERE' + options[:language_code] = 'en' + options[:country_code] = 'US' + + parser = 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 + parser.parse! + + # Check if required parameters are present. + if options[:email].nil? || options[:email] == 'INSERT_EMAIL_HERE' + puts "Missing required argument: --email (-E) is required.\n\n" + puts parser + exit 1 + end + + begin + fetch_incentive(options[:email], options[:language_code], options[:country_code]) + rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e + STDERR.printf("Request with ID '%s' failed with status '%s' and includes the following errors:\n", + e.request_id, e.class.name) + e.failure.errors.each do |error| + STDERR.printf("\tError with message: %s\n", error.message) + if error.location + error.location.field_path_elements.each do |field_path_element| + STDERR.printf("\t\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("\t\tType: %s, Code: %s\n", k, v) + end + end + raise + end +end