bing-ads 0.1.11 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 423587915177b9c676bd2534087b0a8f233cbbc9
4
- data.tar.gz: 5377b102e6a1512fbd268c97bada27af95482184
3
+ metadata.gz: 69fd2b5280eafbb14724463be4492828935ebbc4
4
+ data.tar.gz: 0fa11c1a1c80a3788b42637248340933455488d9
5
5
  SHA512:
6
- metadata.gz: 56a1313389de341e937e47b94ec8fec9be888f619a547000bbfc305f28dd78de618b5578b8e6f345e7117ca2dc89a6f2693cca82ea9c43666283bf9344e2be33
7
- data.tar.gz: 5dbd8a412d30767047a3a7dc6380fdb134f240d543ba121653f7857d0247e22470ae2ae8ca8cee07f660b1bfc07fcdd2ef2d9c772048c67b1b7d292cf968dfda
6
+ metadata.gz: c07d81eb68e2f058b0ec7a1ca6fca6a426e89c61f4efad82d8f12a8ead814c1771859f74ac3b7ec5dc114e36ca067f302baa4352dc511e3f567c8dbb64501a32
7
+ data.tar.gz: b7ed4a73f67e5daa38b16e12512e49322cc5b74f05ce7b4645a72c419dde7f961a9ad8452e48b82ee18406cfe9840496d7f121a0d4e78d24cd910158599fe6ad
data/README.md CHANGED
@@ -312,16 +312,121 @@ response = service.delete_keywords(ad_group_id, keyword_ids_to_delete)
312
312
  ```
313
313
 
314
314
  ### Bulk Service
315
- Not yet supported
315
+ #### Initialization
316
+ ```ruby
317
+ # Authentication token is not supported in sandbox, use `username` and `password` instead
318
+ # https://msdn.microsoft.com/en-us/library/dn277356.aspx
319
+
320
+ options = {
321
+ environment: :sandbox,
322
+ authentication_token: '39b290146bea6ce975c37cfc23',
323
+ developer_token: 'BBD37VB98',
324
+ customer_id: '21027149',
325
+ account_id: '5278183',
326
+ # client_settings: { logger: LOGGER::STDOUT }
327
+ }
328
+
329
+ service = Bing::Ads::API::V11::Services::Bulk.new(options)
330
+ ```
331
+
332
+ #### Submit a request for a URL where a bulk upload file may be posted.
333
+ ```ruby
334
+ response = service.get_bulk_upload_url
335
+
336
+ # @return
337
+ # {
338
+ # request_id: 4981237213
339
+ # upload_url: '-'
340
+ # }
341
+ ```
342
+
343
+ #### Get the status and completion percentage of a bulk upload request.
344
+ ```ruby
345
+ response = service.get_bulk_upload_status(request_id)
346
+
347
+ # @return
348
+ # {
349
+ # errors: [],
350
+ # percent_complete: 100,
351
+ # request_status: '-',
352
+ # result_file_url: '-'
353
+ # }
354
+ ```
316
355
 
317
356
  ### Reporting Service
318
- Not yet supported. Use: https://github.com/FindHotel/bing-ads-reporting
357
+
358
+ #### Initialization
359
+ ```ruby
360
+ # Authentication token is not supported in sandbox, use `username` and `password` instead
361
+ # https://msdn.microsoft.com/en-us/library/dn277356.aspx
362
+
363
+ options = {
364
+ environment: :sandbox,
365
+ authentication_token: '39b290146bea6ce975c37cfc23',
366
+ developer_token: 'BBD37VB98',
367
+ customer_id: '21027149',
368
+ # client_settings: { logger: LOGGER::STDOUT }
369
+ }
370
+
371
+ service = Bing::Ads::API::V11::Services::Reporting.new(options)
372
+ ```
373
+
374
+ #### Submit Generate Report
375
+ To get reports from Bing, you must first submit a report generation request.
376
+
377
+ The method `submit_generate_report` receive two params as input, first the `report_type` and then a hash with the report options.
378
+
379
+ Example:
380
+
381
+ ```ruby
382
+ response = service.submit_generate_report(:keyword_performance, {
383
+ exclude_column_headers: false,
384
+ exclude_report_footer: false,
385
+ exclude_report_header: false,
386
+ language: 'English',
387
+ format: 'Tsv',
388
+ report_name: 'keyword_performance_report',
389
+ return_only_complete_data: false,
390
+ aggregation: 'Daily',
391
+ columns: [:destination_url, :average_cpc],
392
+ from_date: '2017-10-23',
393
+ to_date: '2017-10-25'
394
+ account_ids: [144012349, 224002158]
395
+ })
396
+ ```
397
+
398
+ The required options depend on the report type you are using.
399
+
400
+ Response example:
401
+
402
+ ```ruby
403
+ {:report_request_id=>"30000000999745662", :@xmlns=>"https://bingads.microsoft.com/Reporting/v11"}
404
+ ```
405
+
406
+ #### Poll Generate Report
407
+
408
+ To retrieve the report generated you have a few options:
409
+
410
+ You can check if the report is ready and then get the url:
411
+ ```ruby
412
+ service.report_url(report_request_id) if service.report_ready?(report_request_id)
413
+ ```
414
+
415
+ Or you can download the body of the report when it's ready. (and then write to a file for example)
416
+ ```ruby
417
+ service.report_body(report_request_id) if service.report_ready?(report_request_id)
418
+ ```
419
+
420
+ You can also get the entire poll_generate_reportl report object:
421
+ ```ruby
422
+ service.poll_generate_report(report_request_id)
423
+ ```
319
424
 
320
425
  ### Errors raised
321
- * `Bing::Ads::API::Errors::AuthenticationParamsMissing`
322
- No username/password or authentication_token.
426
+ * `Bing::Ads::API::Errors::AuthenticationParamsMissing` No username/password or authentication_token.
323
427
  * `Bing::Ads::API::Errors::AuthenticationTokenExpired` Authentication token needs to be refreshed.
324
428
  * `Bing::Ads::API::Errors::LimitError` An API limit has been exceeded on a specific request. Check message for details.
429
+ * `Bing::Ads::API::Errors::DownloadError` Error when downloading a report body.
325
430
 
326
431
  ## Development
327
432
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -7,6 +7,7 @@ require 'savon'
7
7
 
8
8
  require 'bing/ads/api/errors'
9
9
  require 'bing/ads/api/soap_client'
10
+ require 'bing/ads/api/http_client'
10
11
  require 'bing/ads/api/v11'
11
12
  require 'bing/ads/api/v11/constants'
12
13
  require 'bing/ads/api/v11/data'
@@ -11,6 +11,9 @@ module Bing
11
11
  # Bing::Ads::API::Errors::UnhandledSOAPFault
12
12
  class UnhandledSOAPFault < RuntimeError; end;
13
13
 
14
+ # Bing::Ads::API::Errors::DownloadError
15
+ class DownloadError < RuntimeError; end;
16
+
14
17
  # Bing::Ads::API::Errors::LimitError
15
18
  class LimitError < RuntimeError
16
19
  def initialize(operation, limit, type)
@@ -0,0 +1,22 @@
1
+ module Bing
2
+ module Ads
3
+ module API
4
+ # Bing::Ads::API::HttpClient
5
+ class HttpClient
6
+ API_CALL_RETRY_COUNT = 3
7
+
8
+ def self.download(url, retry_count = API_CALL_RETRY_COUNT)
9
+ 1.upto(retry_count + 1) do |retry_index|
10
+ response = Net::HTTP.get_response(URI(url))
11
+ if response.is_a?(Net::HTTPSuccess)
12
+ break response.body
13
+ else
14
+ next if retry_index <= retry_count
15
+ raise Bing::Ads::API::Errors::DownloadError, "#{response.code} #{response.msg}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,3 +2,4 @@ require_relative './data/ad_group'
2
2
  require_relative './data/expanded_text_ad'
3
3
  require_relative './data/campaign'
4
4
  require_relative './data/keyword'
5
+ require_relative './data/report_request'
@@ -0,0 +1,106 @@
1
+ module Bing
2
+ module Ads
3
+ module API
4
+ module V11
5
+ module Data
6
+ # Bing::Ads::API::V11::Data::ReportRequest
7
+ class ReportRequest
8
+
9
+ # @order
10
+ # https://msdn.microsoft.com/en-us/library/bing-ads-reporting-reportrequest.aspx
11
+ KEYS_ORDER = [
12
+ :exclude_column_headers,
13
+ :exclude_report_footer,
14
+ :exclude_report_header,
15
+ :format,
16
+ :language,
17
+ :report_name,
18
+ :return_only_complete_data,
19
+ :aggregation,
20
+ :columns,
21
+ :filter,
22
+ :scope,
23
+ :time
24
+ ]
25
+
26
+ class << self
27
+ def prepare(type, report_request_raw)
28
+ report_request_raw[:columns] = prepare_columns(
29
+ columns: report_request_raw[:columns],
30
+ type: type.to_s.classify
31
+ )
32
+
33
+ report_request_raw[:scope] = prepare_scope(
34
+ account_ids: report_request_raw[:account_ids]
35
+ )
36
+
37
+ report_request_raw[:time] = prepare_time_period(
38
+ from_date: report_request_raw[:from_date],
39
+ to_date: report_request_raw[:to_date]
40
+ )
41
+
42
+ report_request_raw.except!(:from_date, :to_date, :account_ids)
43
+
44
+ report_request = Bing::Ads::Utils.sort_keys(report_request_raw, KEYS_ORDER)
45
+ namespace_identifier = Bing::Ads::API::V11::NAMESPACE_IDENTIFIER
46
+ {
47
+ report_request: Bing::Ads::Utils.camelcase_keys(report_request),
48
+ :attributes! => {
49
+ report_request: {
50
+ "xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance",
51
+ "i:type" => "#{namespace_identifier}:#{type.to_s.classify}ReportRequest"
52
+ }
53
+ }
54
+ }
55
+ end
56
+
57
+ private
58
+
59
+ def prepare_columns(type:, columns:)
60
+ {
61
+ "#{type}ReportColumn" => columns.map(&:to_s).map(&:camelcase)
62
+ }
63
+ end
64
+
65
+ def prepare_scope(account_ids:)
66
+ account_ids_elements =
67
+ if account_ids.nil?
68
+ nil
69
+ else
70
+ {
71
+ 'a1:long' => account_ids,
72
+ '@xmlns:a1' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
73
+ }
74
+ end
75
+
76
+ {
77
+ account_ids: account_ids_elements,
78
+ ad_groups: nil,
79
+ campaigns: nil
80
+ }
81
+ end
82
+
83
+ def prepare_time_period(from_date:, to_date:)
84
+ from_date = Date.parse(from_date)
85
+ to_date = Date.parse(to_date)
86
+
87
+ {
88
+ custom_date_range_end: {
89
+ day: to_date.day,
90
+ month: to_date.month,
91
+ year: to_date.year
92
+ },
93
+ custom_date_range_start: {
94
+ day: from_date.day,
95
+ month: from_date.month,
96
+ year: from_date.year
97
+ }
98
+ }
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -2,3 +2,4 @@ require_relative './services/base'
2
2
  require_relative './services/bulk'
3
3
  require_relative './services/campaign_management'
4
4
  require_relative './services/customer_management'
5
+ require_relative './services/reporting'
@@ -51,11 +51,12 @@ module Bing
51
51
  response = soap_client.call(operation: operation.to_sym, payload: payload)
52
52
  return response.hash
53
53
  rescue Savon::SOAPFault => error
54
- fault_detail = error.to_hash[:fault][:detail]
55
- if fault_detail.key?(:api_fault_detail)
56
- handle_soap_fault(operation, fault_detail, :api_fault_detail)
57
- elsif fault_detail.key?(:ad_api_fault_detail)
58
- handle_soap_fault(operation, fault_detail, :ad_api_fault_detail)
54
+ fault = error.to_hash[:fault]
55
+
56
+ if fault.dig(:detail, :api_fault_detail)
57
+ handle_soap_fault(operation, fault[:detail], :api_fault_detail)
58
+ elsif fault.dig(:detail, :ad_api_fault_detail)
59
+ handle_soap_fault(operation, fault[:detail], :ad_api_fault_detail)
59
60
  else
60
61
  if retries_made < retry_attempts
61
62
  sleep(2**retries_made)
@@ -63,7 +64,7 @@ module Bing
63
64
  retry
64
65
  else
65
66
  raise Bing::Ads::API::Errors::UnhandledSOAPFault,
66
- "SOAP error (#{fault_detail.keys.join(', ')}) while calling #{operation}. #{error.message}"
67
+ "SOAP error (#{fault.keys.join(', ')}) while calling #{operation}. #{error.message}"
67
68
  end
68
69
  end
69
70
  rescue Savon::HTTPError => error
@@ -23,6 +23,8 @@ module Bing
23
23
  response_body.slice(:errors, :percent_complete, :request_status, :result_file_url)
24
24
  end
25
25
 
26
+ # TODO operations: https://msdn.microsoft.com/en-us/library/bing-ads-bulk-service-operations.aspx
27
+
26
28
  private
27
29
 
28
30
  def service_name
@@ -0,0 +1,51 @@
1
+ module Bing
2
+ module Ads
3
+ module API
4
+ module V11
5
+ module Services
6
+ # Bing::Ads::API::V11::Services::CampaignManagement
7
+ class Reporting < Base
8
+ def initialize(options = {})
9
+ super(options)
10
+ end
11
+
12
+ def submit_generate_report(type, report_options)
13
+ payload = Bing::Ads::API::V11::Data::ReportRequest.prepare(type, report_options)
14
+ response = call(:submit_generate_report, payload)
15
+ response_body = response_body(response, __method__)
16
+ response_body
17
+ end
18
+
19
+ def poll_generate_report(report_request_id)
20
+ response = call(:poll_generate_report, report_request_id: report_request_id)
21
+ response_body = response_body(response, __method__)
22
+ response_body
23
+ end
24
+
25
+ def report_ready?(report_request_id)
26
+ polled = poll_generate_report(report_request_id)
27
+ status = polled.dig(:report_request_status, :status)
28
+ raise "Report status: Error for ID: #{report_request_id}" if status == "Error"
29
+ status == "Success"
30
+ end
31
+
32
+ def report_url(report_request_id)
33
+ polled = poll_generate_report(report_request_id)
34
+ polled.dig(:report_request_status, :report_download_url)
35
+ end
36
+
37
+ def report_body(report_request_id)
38
+ HttpClient.download(report_url(report_request_id))
39
+ end
40
+
41
+ private
42
+
43
+ def service_name
44
+ 'reporting'
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,5 +1,5 @@
1
1
  module Bing
2
2
  module Ads
3
- VERSION = '0.1.11'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bing-ads
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - oss92
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-12 00:00:00.000000000 Z
11
+ date: 2017-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: savon
@@ -117,6 +117,7 @@ files:
117
117
  - bing-ads.gemspec
118
118
  - lib/bing/ads.rb
119
119
  - lib/bing/ads/api/errors.rb
120
+ - lib/bing/ads/api/http_client.rb
120
121
  - lib/bing/ads/api/soap_client.rb
121
122
  - lib/bing/ads/api/v11.rb
122
123
  - lib/bing/ads/api/v11/constants.rb
@@ -130,11 +131,13 @@ files:
130
131
  - lib/bing/ads/api/v11/data/campaign.rb
131
132
  - lib/bing/ads/api/v11/data/expanded_text_ad.rb
132
133
  - lib/bing/ads/api/v11/data/keyword.rb
134
+ - lib/bing/ads/api/v11/data/report_request.rb
133
135
  - lib/bing/ads/api/v11/services.rb
134
136
  - lib/bing/ads/api/v11/services/base.rb
135
137
  - lib/bing/ads/api/v11/services/bulk.rb
136
138
  - lib/bing/ads/api/v11/services/campaign_management.rb
137
139
  - lib/bing/ads/api/v11/services/customer_management.rb
140
+ - lib/bing/ads/api/v11/services/reporting.rb
138
141
  - lib/bing/ads/utils.rb
139
142
  - lib/bing/ads/version.rb
140
143
  homepage: https://github.com/FindHotel/bing-ads
@@ -157,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
160
  version: '0'
158
161
  requirements: []
159
162
  rubyforge_project:
160
- rubygems_version: 2.6.12
163
+ rubygems_version: 2.6.13
161
164
  signing_key:
162
165
  specification_version: 4
163
166
  summary: Enhances the experience of developing Bing Ads applications with Ruby