bing-ads-api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +92 -0
  3. data/Rakefile +38 -0
  4. data/lib/bing-ads-api.rb +38 -0
  5. data/lib/bing-ads-api.yml +345 -0
  6. data/lib/bing-ads-api/api_exception.rb +42 -0
  7. data/lib/bing-ads-api/client_proxy.rb +131 -0
  8. data/lib/bing-ads-api/config.rb +75 -0
  9. data/lib/bing-ads-api/constants.rb +133 -0
  10. data/lib/bing-ads-api/data/ad.rb +119 -0
  11. data/lib/bing-ads-api/data/ad_group.rb +121 -0
  12. data/lib/bing-ads-api/data/campaign.rb +40 -0
  13. data/lib/bing-ads-api/data/report_request.rb +78 -0
  14. data/lib/bing-ads-api/data/report_request_status.rb +48 -0
  15. data/lib/bing-ads-api/data/reporting/account_performance_report_request.rb +176 -0
  16. data/lib/bing-ads-api/data/reporting/campaign_performance_report_request.rb +186 -0
  17. data/lib/bing-ads-api/data/reporting/helpers/column_helper.rb +65 -0
  18. data/lib/bing-ads-api/data/reporting/helpers/filter_helper.rb +124 -0
  19. data/lib/bing-ads-api/data/reporting/helpers/scope_helper.rb +51 -0
  20. data/lib/bing-ads-api/data/reporting/helpers/time_helper.rb +69 -0
  21. data/lib/bing-ads-api/data/reporting/performance_report_request.rb +78 -0
  22. data/lib/bing-ads-api/data_object.rb +35 -0
  23. data/lib/bing-ads-api/fault/ad_api_error.rb +15 -0
  24. data/lib/bing-ads-api/fault/ad_api_fault_detail.rb +67 -0
  25. data/lib/bing-ads-api/fault/api_fault_detail.rb +97 -0
  26. data/lib/bing-ads-api/fault/application_fault.rb +18 -0
  27. data/lib/bing-ads-api/fault/batch_error.rb +47 -0
  28. data/lib/bing-ads-api/fault/operation_error.rb +22 -0
  29. data/lib/bing-ads-api/fault/partial_errors.rb +75 -0
  30. data/lib/bing-ads-api/service.rb +174 -0
  31. data/lib/bing-ads-api/service/campaign_management.rb +483 -0
  32. data/lib/bing-ads-api/service/reporting.rb +101 -0
  33. data/lib/bing-ads-api/soap_hasheable.rb +143 -0
  34. data/lib/bing-ads-api/version.rb +6 -0
  35. data/lib/locales/es.yml +174 -0
  36. data/lib/tasks/bing-ads-api_tasks.rake +4 -0
  37. data/test/bing-ads-api_test.rb +134 -0
  38. data/test/campaign_management_test.rb +463 -0
  39. data/test/data_object_test.rb +46 -0
  40. data/test/dummy/README.rdoc +261 -0
  41. data/test/dummy/Rakefile +7 -0
  42. data/test/dummy/app/assets/javascripts/application.js +15 -0
  43. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  44. data/test/dummy/app/controllers/application_controller.rb +3 -0
  45. data/test/dummy/app/helpers/application_helper.rb +2 -0
  46. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  47. data/test/dummy/config.ru +4 -0
  48. data/test/dummy/config/application.rb +56 -0
  49. data/test/dummy/config/boot.rb +10 -0
  50. data/test/dummy/config/database.yml +25 -0
  51. data/test/dummy/config/environment.rb +5 -0
  52. data/test/dummy/config/environments/development.rb +37 -0
  53. data/test/dummy/config/environments/production.rb +67 -0
  54. data/test/dummy/config/environments/test.rb +37 -0
  55. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  56. data/test/dummy/config/initializers/inflections.rb +15 -0
  57. data/test/dummy/config/initializers/mime_types.rb +5 -0
  58. data/test/dummy/config/initializers/secret_token.rb +7 -0
  59. data/test/dummy/config/initializers/session_store.rb +8 -0
  60. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/test/dummy/config/locales/en.yml +5 -0
  62. data/test/dummy/config/routes.rb +58 -0
  63. data/test/dummy/db/development.sqlite3 +0 -0
  64. data/test/dummy/db/test.sqlite3 +0 -0
  65. data/test/dummy/log/development.log +29 -0
  66. data/test/dummy/log/test.log +3264 -0
  67. data/test/dummy/public/404.html +26 -0
  68. data/test/dummy/public/422.html +26 -0
  69. data/test/dummy/public/500.html +25 -0
  70. data/test/dummy/public/favicon.ico +0 -0
  71. data/test/dummy/script/rails +6 -0
  72. data/test/report_request_test.rb +312 -0
  73. data/test/reporting_test.rb +145 -0
  74. data/test/test_helper.rb +11 -0
  75. metadata +205 -0
@@ -0,0 +1,174 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module BingAdsApi
4
+
5
+ # Public : Base class for service object
6
+ #
7
+ # Author:: jlopezn@neonline.cl
8
+ #
9
+ class Service
10
+
11
+ attr_accessor :client_proxy, :environment
12
+
13
+ # Default logger for services
14
+ LOGGER = Logger.new(STDOUT)
15
+
16
+ # Public : Constructor
17
+ #
18
+ # Author:: jlopezn@neonline.cl
19
+ #
20
+ # === Parameters
21
+ # * +options+ - Hash with autentication and environment settings
22
+ #
23
+ # === Options
24
+ # * environment - +:production+ or +:sandbox+
25
+ # * username - Bing Ads username
26
+ # * passwrod - Bing Ads user's sign-in password
27
+ # * developer_token - client application's developer access token
28
+ # * customer_id - identifier for the customer that owns the account
29
+ # * account_id - identifier of the account that own the entities in the request
30
+ # * proxy - Hash with any Client Proxy additional options (such as header, logger or enconding)
31
+ #
32
+ # === Examples
33
+ # service = BingAdsApi::Service.new(
34
+ # :environment => :sandbox,
35
+ # :username => 'username',
36
+ # :password => 'pass',
37
+ # :developer_token => 'SOME_TOKEN',
38
+ # :account_id => 123456,
39
+ # :customer_id => 654321,
40
+ # :proxy => {:logger => Rails.logger}
41
+ # )
42
+ # # => <Service>
43
+ def initialize(options={})
44
+
45
+ # Service Environment
46
+ self.environment = options[:environment]
47
+
48
+ # ClientProxy settings
49
+ clientProxySettings = {
50
+ :username => options[:username],
51
+ :password => options[:password],
52
+ :developer_token => options[:developer_token],
53
+ :account_id => options[:account_id],
54
+ :customer_id => options[:customer_id],
55
+ :wsdl_url => options[:wdsl] || solve_wsdl_url
56
+ }
57
+
58
+ # Additionsl ClientProxy settings
59
+ clientProxySettings[:proxy] = options[:proxy] if options[:proxy]
60
+
61
+ # ClientProxy creation
62
+ self.client_proxy = BingAdsApi::ClientProxy.new(clientProxySettings)
63
+
64
+ end
65
+
66
+ # Public : This is a utility wrapper for calling services into the
67
+ # +ClientProxy+. This methods handle all the +Savon::Client+ Exceptions
68
+ # and returns a Hash with the call response
69
+ #
70
+ # Author:: jlopezn@neonline.cl
71
+ #
72
+ # === Parameters
73
+ # +operation+ - name of the operation to be called
74
+ # +message+ - hash with the parameters to the operation
75
+ #
76
+ # === Examples
77
+ # service.call(:some_operation, {key: value})
78
+ # # => <Hash>
79
+ #
80
+ # Returns:: Hash with the result of the service call
81
+ # Raises:: ServiceError if the SOAP call, the ClientProxy fails or the response is invalid
82
+ def call(operation, message, &block)
83
+ raise "You must provide an operation" if operation.nil?
84
+ begin
85
+ LOGGER.debug "BingAdsApi Service"
86
+ LOGGER.debug " Calling #{operation.to_s}"
87
+ LOGGER.debug " Message: #{message}"
88
+ response = self.client_proxy.call(operation.to_sym,
89
+ message: message)
90
+
91
+ LOGGER.debug "response header:"
92
+ LOGGER.debug "\t#{response.header}"
93
+
94
+ LOGGER.info "Operation #{operation.to_s} call success"
95
+ return response.hash
96
+ rescue Savon::SOAPFault => error
97
+ LOGGER.error "SOAP Error calling #{operation.to_s}: #{error.http.code}"
98
+ fault_detail = error.to_hash[:fault][:detail]
99
+ if fault_detail.key?(:api_fault_detail)
100
+ api_fault_detail = BingAdsApi::ApiFaultDetail.new(fault_detail[:api_fault_detail])
101
+ raise BingAdsApi::ApiException.new(
102
+ api_fault_detail, "SOAP Error calling #{operation.to_s}")
103
+ elsif fault_detail.key?(:ad_api_fault_detail)
104
+ ad_api_fault_detail = BingAdsApi::AdApiFaultDetail.new(fault_detail[:ad_api_fault_detail])
105
+ raise BingAdsApi::ApiException.new(
106
+ ad_api_fault_detail, "SOAP Error calling #{operation.to_s}")
107
+ else
108
+ raise
109
+ end
110
+ rescue Savon::HTTPError => error
111
+ LOGGER.error "Http Error calling #{operation.to_s}: #{error.http.code}"
112
+ raise
113
+ rescue Savon::InvalidResponseError => error
114
+ LOGGER.error "Invalid server reponse calling #{operation.to_s}"
115
+ raise
116
+ end
117
+ end
118
+
119
+
120
+ # Public : Extracts the actual response from the entire response hash.
121
+ # For example, if you specify 'AddCampaigns', this method will return
122
+ # the content of 'AddCampaignsResponse' tag as a Hash
123
+ #
124
+ # Author:: jlopezn@neonline.cl
125
+ #
126
+ # === Parameters
127
+ # response - The complete response hash received from a Operation call
128
+ # method - Name of the method of with the 'reponse' tag is require
129
+ #
130
+ # === Examples
131
+ # service.get_response_hash(Hash, 'add_campaigns')
132
+ # # => Hash
133
+ #
134
+ # Returns:: Hash with the inner structure of the method response hash
135
+ # Raises:: exception
136
+ def get_response_hash(response, method)
137
+ return response[:envelope][:body]["#{method}_response".to_sym]
138
+ end
139
+
140
+ private
141
+
142
+ # Private : This method must be overriden by specific services.
143
+ # Returns:: the service name
144
+ #
145
+ # Author:: jlopezn@neonline.cl
146
+ #
147
+ # Examples
148
+ # get_service_name
149
+ # # => "service_name"
150
+ #
151
+ # Returns:: String with the service name
152
+ # Raises:: exception if the specific Service class hasn't overriden this method
153
+ def get_service_name
154
+ raise "Should return the a service name from config.wsdl keys"
155
+ end
156
+
157
+
158
+ # Private : Solves the service WSDL URL based on his service name
159
+ # and environment values
160
+ #
161
+ # Author:: jlopezn@neonline.cl
162
+ #
163
+ # Examples
164
+ # solve_wsdl_url
165
+ # # => "https://bing.wsdl.url.com"
166
+ #
167
+ # Returns:: String with the Service url
168
+ def solve_wsdl_url
169
+ config = BingAdsApi::Config.instance
170
+ return config.service_wsdl(environment, get_service_name)
171
+ end
172
+ end
173
+
174
+ end
@@ -0,0 +1,483 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module BingAdsApi
3
+
4
+
5
+ # Public : This class represents the Campaign Management Services
6
+ # defined in the Bing Ads API, to manage advertising campaigns
7
+ #
8
+ # Author:: jlopezn@neonline.cl
9
+ #
10
+ # Examples
11
+ # options = {
12
+ # :environment => :sandbox,
13
+ # :username => "username",
14
+ # :password => "pass",
15
+ # :developer_token => "SOME_TOKEN",
16
+ # :customer_id => "1234567",
17
+ # :account_id => "9876543" }
18
+ # service = BingAdsApi::CampaignManagement.new(options)
19
+ class CampaignManagement < BingAdsApi::Service
20
+
21
+
22
+ # Public : Constructor
23
+ #
24
+ # Author:: jlopezn@neonline.cl
25
+ #
26
+ # options - Hash with the parameters for the client proxy and the environment
27
+ #
28
+ # Examples
29
+ # options = {
30
+ # :environment => :sandbox,
31
+ # :username => "username",
32
+ # :password => "password",
33
+ # :developer_token => "DEV_TOKEN",
34
+ # :customer_id => "123456",
35
+ # :account_id => "654321"
36
+ # }
37
+ # service = BingAdsApi::CampaignManagement.new(options)
38
+ def initialize(options={})
39
+ super(options)
40
+ end
41
+
42
+
43
+ #########################
44
+ ## Operations Wrappers ##
45
+ #########################
46
+
47
+ # Public : Returns all the campaigns found in the specified account
48
+ #
49
+ # Author:: jlopezn@neonline.cl
50
+ #
51
+ # === Parameters
52
+ # account_id - account who owns the campaigns
53
+ #
54
+ # === Examples
55
+ # campaign_management_service.get_campaigns_by_account_id(1)
56
+ # # => Array[BingAdsApi::Campaign]
57
+ #
58
+ # Returns:: Array of BingAdsApi::Campaign
59
+ #
60
+ # Raises:: exception
61
+ def get_campaigns_by_account_id(account_id)
62
+ response = call(:get_campaigns_by_account_id,
63
+ {account_id: account_id})
64
+ response_hash = get_response_hash(response, __method__)
65
+ campaigns = response_hash[:campaigns][:campaign].map do |camp_hash|
66
+ BingAdsApi::Campaign.new(camp_hash)
67
+ end
68
+ return campaigns
69
+ end
70
+
71
+
72
+ # Public : Adds a campaign to the specified account
73
+ #
74
+ # Author:: jlopezn@neonline.cl
75
+ #
76
+ # === Parameters
77
+ # account_id - account who will own the newly campaigns
78
+ # campaigns - An array of BingAdsApi::Campaign
79
+ #
80
+ # === Examples
81
+ # service.add_campaigns(1, [<BingAdsApi::Campaign>])
82
+ # # => <Hash>
83
+ #
84
+ # Returns:: hash with the 'add_campaigns_response' structure
85
+ #
86
+ # Raises:: exception
87
+ def add_campaigns(account_id, campaigns)
88
+
89
+ camps = []
90
+ if campaigns.is_a? Array
91
+ camps = campaigns.map{ |camp| camp.to_hash(:camelcase) }
92
+ elsif campaigns.is_a? BingAdsApi::Campaign
93
+ camps = campaigns.to_hash
94
+ else
95
+ raise "campaigns must be an array of BingAdsApi::Campaigns"
96
+ end
97
+ message = {
98
+ :account_id => account_id,
99
+ :campaigns => {:campaign => camps} }
100
+ puts message
101
+ response = call(:add_campaigns, message)
102
+ return get_response_hash(response, __method__)
103
+ end
104
+
105
+
106
+ # Public : Updates on or more campaigns for the specified account
107
+ #
108
+ # Author:: jlopezn@neonline.cl
109
+ #
110
+ # === Parameters
111
+ # account_id - account who own the updated campaigns
112
+ # campaigns - Array with the campaigns to be updated
113
+ #
114
+ # === Examples
115
+ # service_update_campaigns(1, [<BingAdsApi::Campaign])
116
+ # # => true
117
+ #
118
+ # Returns:: boolean. true if the update was successful. false otherwise
119
+ #
120
+ # Raises:: exception
121
+ def update_campaigns(account_id, campaigns)
122
+ camps = []
123
+ if campaigns.is_a? Array
124
+ camps = campaigns.map do |camp|
125
+ camp.to_hash(:camelcase)
126
+ end
127
+ elsif campaigns.is_a? BingAdsApi::Campaign
128
+ camps = campaigns.to_hash
129
+ else
130
+ raise "campaigns must be an array of BingAdsApi::Campaigns"
131
+ end
132
+ message = {
133
+ :account_id => account_id,
134
+ :campaigns => {:campaign => camps} }
135
+ puts message
136
+ response = call(:update_campaigns, message)
137
+ return get_response_hash(response, __method__)
138
+
139
+ end
140
+
141
+
142
+ # Public : Returns all the ad groups that belongs to the
143
+ # specified campaign
144
+ #
145
+ # Author:: jlopezn@neonline.cl
146
+ #
147
+ # === Parameters
148
+ # campaign_id - campaign id
149
+ #
150
+ # === Examples
151
+ # service.get_ad_groups_by_campaign_id(1)
152
+ # # => Array[AdGroups]
153
+ #
154
+ # Returns:: Array with all the ad groups present in campaign_id
155
+ #
156
+ # Raises:: exception
157
+ def get_ad_groups_by_campaign_id(campaign_id)
158
+ response = call(:get_ad_groups_by_campaign_id,
159
+ {campaign_id: campaign_id})
160
+ response_hash = get_response_hash(response, __method__)
161
+ ad_groups = response_hash[:ad_groups][:ad_group].map do |ad_group_hash|
162
+ BingAdsApi::AdGroup.new(ad_group_hash)
163
+ end
164
+ return ad_groups
165
+ end
166
+
167
+
168
+ # Public : Returns the specified ad groups that belongs to the
169
+ # specified campaign
170
+ #
171
+ # Author:: jlopezn@neonline.cl
172
+ #
173
+ # === Parameters
174
+ # campaign_id - campaign id
175
+ # ad_groups_ids - array with ids from ad groups
176
+ #
177
+ # === Examples
178
+ # service.get_ad_groups_by_ids(1, [1,2,3])
179
+ # # => Array[AdGroups]
180
+ #
181
+ # Returns:: Array with the ad groups specified in the ad_groups_ids array
182
+ #
183
+ # Raises:: exception
184
+ def get_ad_groups_by_ids(campaign_id, ad_groups_ids)
185
+
186
+ message = {
187
+ :campaign_id => campaign_id,
188
+ :ad_group_ids => {"ins1:long" => ad_groups_ids} }
189
+ response = call(:get_ad_groups_by_ids, message)
190
+ response_hash = get_response_hash(response, __method__)
191
+ ad_groups = response_hash[:ad_groups][:ad_group].map do |ad_group_hash|
192
+ BingAdsApi::AdGroup.new(ad_group_hash)
193
+ end
194
+ return ad_groups
195
+
196
+ end
197
+
198
+
199
+ # Public : Adds 1 or more AdGroups to a Campaign
200
+ #
201
+ # Author:: jlopezn@neonline.cl
202
+ #
203
+ # === Parameters
204
+ # campaing_id - the campaign id where the ad groups will be added
205
+ # ad_groups - Array[BingAdsApi::AdGroup] ad groups to be added
206
+ #
207
+ # === Examples
208
+ # service.add_ad_groups(1, [<BingAdsApi::AdGroup>])
209
+ # # => <Hash>
210
+ #
211
+ # Returns:: Hash with the 'add_ad_groups_response' structure
212
+ #
213
+ # Raises:: exception
214
+ def add_ad_groups(campaign_id, ad_groups)
215
+
216
+ groups = []
217
+ if ad_groups.is_a? Array
218
+ groups = ad_groups.map{ |gr| gr.to_hash(:camelcase) }
219
+ elsif ad_groups.is_a? BingAdsApi::AdGroup
220
+ groups = ad_groups.to_hash
221
+ else
222
+ raise "ad_groups must be an array of BingAdsApi::AdGroup"
223
+ end
224
+ message = {
225
+ :campaign_id => campaign_id,
226
+ :ad_groups => {:ad_group => groups} }
227
+ puts message
228
+ response = call(:add_ad_groups, message)
229
+ return get_response_hash(response, __method__)
230
+ end
231
+
232
+
233
+ # Public : Updates on or more ad groups in a specified campaign
234
+ #
235
+ # Author:: jlopezn@neonline.cl
236
+ #
237
+ # === Parameters
238
+ # campaign_id - campaign who owns the updated ad groups
239
+ #
240
+ # === Examples
241
+ # service.update_ad_groups(1, [<BingAdsApi::AdGroup])
242
+ # # => true
243
+ #
244
+ # Returns:: boolean. true if the updates is successfull. false otherwise
245
+ #
246
+ # Raises:: exception
247
+ def update_ad_groups(campaign_id, ad_groups)
248
+ groups = []
249
+ if ad_groups.is_a? Array
250
+ groups = ad_groups.map{ |gr| gr.to_hash(:camelcase) }
251
+ elsif ad_groups.is_a? BingAdsApi::AdGroup
252
+ groups = ad_groups.to_hash(:camelcase)
253
+ else
254
+ raise "ad_groups must be an array or instance of BingAdsApi::AdGroup"
255
+ end
256
+ message = {
257
+ :campaign_id => campaign_id,
258
+ :ad_groups => {:ad_group => groups} }
259
+ puts message
260
+ response = call(:update_ad_groups, message)
261
+ return get_response_hash(response, __method__)
262
+ end
263
+
264
+
265
+ # Public : Obtains all the ads associated to the specified ad group
266
+ #
267
+ # Author:: jlopezn@neonline.cl
268
+ #
269
+ # === Parameters
270
+ # ad_group_id - long with the ad group id
271
+ #
272
+ # === Examples
273
+ # service.get_ads_by_ad_group_id(1)
274
+ # # => [<BingAdsApi::Ad]
275
+ #
276
+ # Returns:: An array of BingAdsApi::Ad
277
+ #
278
+ # Raises:: exception
279
+ def get_ads_by_ad_group_id(ad_group_id)
280
+ response = call(:get_ads_by_ad_group_id,
281
+ {ad_group_id: ad_group_id})
282
+ response_hash = get_response_hash(response, __method__)
283
+
284
+ if response_hash[:ads][:ad].is_a?(Array)
285
+ ads = response_hash[:ads][:ad].map do |ad_hash|
286
+ initialize_ad(ad_hash)
287
+ end
288
+ else
289
+ ads = [ initialize_ad(response_hash[:ads][:ad]) ]
290
+ end
291
+ return ads
292
+ end
293
+
294
+
295
+ # Public : Obtains the ads indicated in ad_ids associated to the specified ad group
296
+ #
297
+ # Author:: jlopezn@neonline.cl
298
+ #
299
+ # === Parameters
300
+ # ad_group_id - long with the ad group id
301
+ # ads_id - an Array io ads ids, that are associated to the ad_group_id provided
302
+ #
303
+ # === Examples
304
+ # service.get_ads_by_ids(1, [1,2,3])
305
+ # # => [<BingAdsApi::Ad>]
306
+ #
307
+ # Returns:: An array of BingAdsApi::Ad
308
+ #
309
+ # Raises:: exception
310
+ def get_ads_by_ids(ad_group_id, ad_ids)
311
+
312
+
313
+ message = {
314
+ :ad_group_id => ad_group_id,
315
+ :ad_ids => {"ins1:long" => ad_ids} }
316
+ response = call(:get_ads_by_ids, message)
317
+ response_hash = get_response_hash(response, __method__)
318
+
319
+ if response_hash[:ads][:ad].is_a?(Array)
320
+ ads = response_hash[:ads][:ad].map do |ad_hash|
321
+ initialize_ad(ad_hash)
322
+ end
323
+ else
324
+ ads = [ initialize_ad(response_hash[:ads][:ad]) ]
325
+ end
326
+ return ads
327
+ end
328
+
329
+
330
+ # Public : Add ads into a specified ad group
331
+ #
332
+ # Author:: jlopezn@neonline.cl
333
+ #
334
+ # === Parameters
335
+ # ad_group_id - a number with the id where the ads should be added
336
+ # ads - an array of BingAdsApi::Ad instances
337
+ #
338
+ # === Examples
339
+ # # if the operation returns partial errors
340
+ # service.add_ads(1, [BingAdsApi::Ad])
341
+ # # => {:ad_ids => [], :partial_errors => BingAdsApi::PartialErrors }
342
+ #
343
+ # # if the operation doesn't return partial errors
344
+ # service.add_ads(1, [BingAdsApi::Ad])
345
+ # # => {:ad_ids => [] }
346
+ #
347
+ # Returns:: Hash with the AddAdsResponse structure.
348
+ # If the operation returns 'PartialErrors' key,
349
+ # this methods returns those errors as an BingAdsApi::PartialErrors
350
+ # instance
351
+ #
352
+ # Raises:: exception
353
+ def add_ads(ad_group_id, ads)
354
+
355
+ ads_for_soap = []
356
+ if ads.is_a? Array
357
+ ads_for_soap = ads.map{ |ad| ad_to_hash(ad, :camelcase) }
358
+ elsif ads.is_a? BingAdsApi::Ad
359
+ ads_for_soap = ad_to_hash(ads, :camelcase)
360
+ else
361
+ raise "ads must be an array or instance of BingAdsApi::Ad"
362
+ end
363
+ message = {
364
+ :ad_group_id => ad_group_id,
365
+ :ads => {:ad => ads_for_soap} }
366
+ puts message
367
+ response = call(:add_ads, message)
368
+
369
+ response_hash = get_response_hash(response, __method__)
370
+
371
+ # Checks if there are partial errors in the request
372
+ if response_hash[:partial_errors].key?(:batch_error)
373
+ partial_errors = BingAdsApi::PartialErrors.new(
374
+ response_hash[:partial_errors])
375
+ response_hash[:partial_errors] = partial_errors
376
+ else
377
+ response_hash.delete(:partial_errors)
378
+ end
379
+
380
+ return response_hash
381
+ end
382
+
383
+
384
+ # Public : Updates ads for the specified ad group
385
+ #
386
+ # Author:: jlopezn@neonline.cl
387
+ #
388
+ # === Parameters
389
+ # ad_group_id - long with the ad group id
390
+ # ads - array of BingAdsApi::Ad subclasses instances to update
391
+ #
392
+ # === Examples
393
+ # service.update_ads(1, [<BingAdsApi::Ad>])
394
+ # # => Hash
395
+ #
396
+ # Returns:: Hash with the UpdateAddsResponse structure
397
+ #
398
+ # Raises:: exception
399
+ def update_ads(ad_group_id, ads)
400
+
401
+ ads_for_soap = []
402
+ if ads.is_a? Array
403
+ ads_for_soap = ads.map{ |ad| ad_to_hash(ad, :camelcase) }
404
+ elsif ads.is_a? BingAdsApi::Ad
405
+ ads_for_soap = ad_to_hash(ads, :camelcase)
406
+ else
407
+ raise "ads must be an array or instance of BingAdsApi::Ad"
408
+ end
409
+ message = {
410
+ :ad_group_id => ad_group_id,
411
+ :ads => {:ad => ads_for_soap} }
412
+ puts message
413
+ response = call(:update_ads, message)
414
+
415
+ response_hash = get_response_hash(response, __method__)
416
+
417
+ # Checks if there are partial errors in the request
418
+ if response_hash[:partial_errors].key?(:batch_error)
419
+ partial_errors = BingAdsApi::PartialErrors.new(
420
+ response_hash[:partial_errors])
421
+ response_hash[:partial_errors] = partial_errors
422
+ else
423
+ response_hash.delete(:partial_errors)
424
+ end
425
+
426
+ return response_hash
427
+ end
428
+
429
+
430
+ private
431
+ def get_service_name
432
+ "campaign_management"
433
+ end
434
+
435
+ # Private : Returns an instance of any of the subclases of BingAdsApi::Ad based on the '@i:type' value in the hash
436
+ #
437
+ # Author:: jlopezn@neonline.cl
438
+ #
439
+ # ad_hash - Hash returned by the SOAP request with the Ad attributes
440
+ #
441
+ # Examples
442
+ # initialize_ad({:device_preference=>"0", :editorial_status=>"Active",
443
+ # :forward_compatibility_map=>{:"@xmlns:a"=>"http://schemas.datacontract.org/2004/07/System.Collections.Generic"},
444
+ # :id=>"1", :status=>"Active", :type=>"Text",
445
+ # :destination_url=>"www.some-url.com", :display_url=>"http://www.some-url.com",
446
+ # :text=>"My Page", :title=>"My Page",
447
+ # :"@i:type"=>"TextAd"})
448
+ # # => BingAdsApi::TextAd
449
+ #
450
+ # Returns:: BingAdsApi::Ad subclass instance
451
+ def initialize_ad(ad_hash)
452
+ ad = BingAdsApi::Ad.new(ad_hash)
453
+ case ad_hash["@i:type".to_sym]
454
+ when "TextAd"
455
+ ad = BingAdsApi::TextAd.new(ad_hash)
456
+ when "MobileAd"
457
+ ad = BingAdsApi::MobileAd.new(ad_hash)
458
+ when "ProductAd"
459
+ ad = BingAdsApi::ProductAd.new(ad_hash)
460
+ end
461
+ return ad
462
+ end
463
+
464
+
465
+ # Private : Helper method to correctly assemble the Ad XML for SOAP requests
466
+ #
467
+ # Author:: jlopezn@neonline.cl
468
+ #
469
+ # ad - BingAdsApi::Ad subclass instance
470
+ #
471
+ # Examples
472
+ # ad_to_hash(BingAdsApi::Ad, :camelcase)
473
+ # # => Hash
474
+ #
475
+ # Returns:: The same hash that ad.to_hash returns plus the needed key for the Ad Type
476
+ def ad_to_hash(ad, keys)
477
+ hash = ad.to_hash(keys)
478
+ hash["@xsi:type"] = self.client_proxy.class::NAMESPACE.to_s + ":" + ad.class.to_s.demodulize
479
+ return hash
480
+ end
481
+ end
482
+
483
+ end