ppc 1.3.0 → 1.3.2

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/LICENSE +334 -17
  4. data/README.md +75 -3
  5. data/lib/ppc.rb +3 -1
  6. data/lib/ppc/api.rb +137 -2
  7. data/lib/ppc/api/baidu.rb +20 -99
  8. data/lib/ppc/api/baidu/account.rb +21 -21
  9. data/lib/ppc/api/baidu/bulk.rb +39 -3
  10. data/lib/ppc/api/baidu/creative.rb +33 -33
  11. data/lib/ppc/api/baidu/group.rb +14 -14
  12. data/lib/ppc/api/baidu/keyword.rb +57 -46
  13. data/lib/ppc/api/baidu/phone_new_creative.rb +51 -0
  14. data/lib/ppc/api/baidu/plan.rb +34 -31
  15. data/lib/ppc/api/baidu/rank.rb +23 -0
  16. data/lib/ppc/api/baidu/report.rb +100 -81
  17. data/lib/ppc/api/qihu.rb +150 -0
  18. data/lib/ppc/api/qihu/account.rb +86 -0
  19. data/lib/ppc/api/qihu/bulk.rb +35 -0
  20. data/lib/ppc/api/qihu/creative.rb +108 -0
  21. data/lib/ppc/api/qihu/group.rb +96 -0
  22. data/lib/ppc/api/qihu/keyword.rb +113 -0
  23. data/lib/ppc/api/qihu/plan.rb +64 -0
  24. data/lib/ppc/api/qihu/rank.rb +25 -0
  25. data/lib/ppc/api/qihu/report.rb +159 -0
  26. data/lib/ppc/api/qihu/sublink.rb +71 -0
  27. data/lib/ppc/api/shenma.rb +64 -0
  28. data/lib/ppc/api/shenma/report.rb +135 -0
  29. data/lib/ppc/api/sm.rb +50 -0
  30. data/lib/ppc/api/sm/account.rb +44 -0
  31. data/lib/ppc/api/sm/bulk.rb +69 -0
  32. data/lib/ppc/api/sm/creative.rb +86 -0
  33. data/lib/ppc/api/sm/group.rb +94 -0
  34. data/lib/ppc/api/sm/keyword.rb +132 -0
  35. data/lib/ppc/api/sm/phone_new_creative.rb +51 -0
  36. data/lib/ppc/api/sm/plan.rb +63 -0
  37. data/lib/ppc/api/sm/report.rb +136 -0
  38. data/lib/ppc/api/sogou.rb +118 -0
  39. data/lib/ppc/api/sogou/account.rb +42 -0
  40. data/lib/ppc/api/sogou/bulk.rb +69 -0
  41. data/lib/ppc/api/sogou/creative.rb +117 -0
  42. data/lib/ppc/api/sogou/group.rb +123 -0
  43. data/lib/ppc/api/sogou/keyword.rb +188 -0
  44. data/lib/ppc/api/sogou/plan.rb +66 -0
  45. data/lib/ppc/api/sogou/report.rb +129 -0
  46. data/lib/ppc/ext.rb +17 -0
  47. data/lib/ppc/operation.rb +50 -36
  48. data/lib/ppc/operation/account.rb +19 -7
  49. data/lib/ppc/operation/creative.rb +7 -7
  50. data/lib/ppc/operation/group.rb +2 -2
  51. data/lib/ppc/operation/keyword.rb +11 -8
  52. data/lib/ppc/operation/report.rb +23 -0
  53. data/ppc.gemspec +14 -4
  54. data/spec/baidu/api_baidu_account_spec.rb +16 -0
  55. data/spec/baidu/api_baidu_creative_spec.rb +73 -0
  56. data/spec/{api_baidu_group_spec.rb → baidu/api_baidu_group_spec.rb} +12 -17
  57. data/spec/baidu/api_baidu_keyword_spec.rb +61 -0
  58. data/spec/baidu/api_baidu_phone_spec.rb +22 -0
  59. data/spec/{api_baidu_plan_spec.rb → baidu/api_baidu_plan_spec.rb} +11 -10
  60. data/spec/baidu/api_baidu_report_spec.rb +44 -0
  61. data/spec/{api_baidu_spec.rb → baidu/api_baidu_spec.rb} +10 -15
  62. data/spec/operation/operation_baidu_report_spec.rb +17 -0
  63. data/spec/operation/operation_baidu_spec.rb +126 -0
  64. data/spec/operation/operation_qihu_report_spec.rb +18 -0
  65. data/spec/operation/operation_qihu_spec.rb +94 -0
  66. data/spec/operation/operation_sm_report_spec.rb +21 -0
  67. data/spec/operation/operation_sogou_report_spec.rb +17 -0
  68. data/spec/operation/operation_sogou_spec.rb +88 -0
  69. data/spec/{operation_spec_helper.rb → operation/operation_spec_helper.rb} +3 -5
  70. data/spec/qihu/api_qihu_account_spec.rb +29 -0
  71. data/spec/qihu/api_qihu_creative_spec.rb +48 -0
  72. data/spec/qihu/api_qihu_group_spec.rb +40 -0
  73. data/spec/qihu/api_qihu_keyword_spec.rb +50 -0
  74. data/spec/qihu/api_qihu_plan_spec.rb +39 -0
  75. data/spec/qihu/api_qihu_report_spec.rb +54 -0
  76. data/spec/qihu/api_qihu_sublink_spec.rb +36 -0
  77. data/spec/sm/api_sm_account_spec.rb +8 -0
  78. data/spec/sm/api_sm_creative_spec.rb +52 -0
  79. data/spec/sm/api_sm_group_spec.rb +75 -0
  80. data/spec/sm/api_sm_keyword_spec.rb +59 -0
  81. data/spec/sm/api_sm_plan_spec.rb +39 -0
  82. data/spec/sm/api_sm_report_spec.rb +30 -0
  83. data/spec/sogou/api_sogou_account_spec.rb +17 -0
  84. data/spec/sogou/api_sogou_creative_spec.rb +51 -0
  85. data/spec/sogou/api_sogou_group_spec.rb +50 -0
  86. data/spec/sogou/api_sogou_keyword_spec.rb +54 -0
  87. data/spec/sogou/api_sogou_plan_spec.rb +43 -0
  88. data/spec/sogou/api_sogou_report_spec.rb +51 -0
  89. data/spec/spec_helper.rb +49 -10
  90. metadata +140 -46
  91. data/lib/ppc/baidu.rb +0 -152
  92. data/lib/ppc/baidu/account.rb +0 -88
  93. data/lib/ppc/baidu/bulk.rb +0 -52
  94. data/lib/ppc/baidu/group.rb +0 -99
  95. data/lib/ppc/baidu/key.rb +0 -38
  96. data/lib/ppc/baidu/plan.rb +0 -85
  97. data/lib/ppc/baidu/report.rb +0 -82
  98. data/spec/api_baidu_account_spec.rb +0 -18
  99. data/spec/api_baidu_creative_spec.rb +0 -71
  100. data/spec/api_baidu_keyword_spec.rb +0 -64
  101. data/spec/api_baidu_report_spec.rb +0 -32
  102. data/spec/baidu_account_spec.rb +0 -32
  103. data/spec/baidu_bulk_spec.rb +0 -21
  104. data/spec/baidu_group_spec.rb +0 -56
  105. data/spec/baidu_plan_spec.rb +0 -129
  106. data/spec/baidu_report_spec.rb +0 -24
  107. data/spec/operation_spec.rb +0 -87
@@ -0,0 +1,135 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Shenma
5
+ class Report< Shenma
6
+ Service = 'Report'
7
+
8
+ # 需要用到的映射集合
9
+ Type_map = { 'account' =>2, 'plan'=> 10, 'group'=> 11,
10
+ 'keyword'=> 14, 'creative'=> 12, 'region'=> 3,
11
+ 'query'=> 6, 'phone' => 22, 'app' => 23 }
12
+
13
+ Level_map = { 'account' => 2, 'plan' => 3, 'group' => 5,
14
+ 'creative' => 7, 'keyword' => 11, 'phone' => 22,
15
+ 'app' => 23, 'pair' => 12 }
16
+
17
+ Unit_map = { 'day' => 5, 'month' => 3, 'default' => 8 }
18
+
19
+ def self.get_id( auth, params, debug = false )
20
+ request = make_reportrequest( params )
21
+ body = { ReportRequestType: request }
22
+ response = request( auth, '/report/getReport' ,body)
23
+ process( response, 'reportId', debug ){ |x| x }
24
+ end
25
+
26
+ def self.get_state( auth, id, debug = false)
27
+ '''
28
+ input id should be string
29
+ '''
30
+ status = {1=>'Waiting' ,2=>'Opearting' ,3=>'Finished'}
31
+ body = { taskId: id }
32
+ response = request( auth, '/task/getTaskState' ,body)
33
+ process( response, 'isGenerated', debug ){ |x| status[x] }
34
+ end
35
+
36
+ # todo : rewrite method
37
+ def self.download( auth, id, debug = false )
38
+ body = { fileId: id }
39
+ response = request( auth, '/file/download' ,body)
40
+ process( response, 'reportPath', debug ){ |x| x }
41
+ end
42
+
43
+ private
44
+ def self.make_reportrequest( param )
45
+ '''
46
+ make RepoerRequestType
47
+ ======================
48
+ For more docs please have a look at
49
+ ::PPC::API::Baidu::Report:make_reportrequest()
50
+ '''
51
+ requesttype = {}
52
+ requesttype[:performanceData] = param[:fields]
53
+ requesttype[:reportType] = Type_map[ param[:type] ] if param[:type]
54
+ requesttype[:levelOfDetails] = Level_map[ param[:level] ] if param[:level]
55
+ requesttype[:statRange] = Level_map[ param[:range] ] if param[:range]
56
+ requesttype[:unitOfTime] = Unit_map[ param[:unit] ] if param[:unit]
57
+ requesttype[:idOnly] = param[:id_only] || false
58
+ requesttype[:statIds] = param[:ids] if param[:ids] != nil
59
+ requesttype[:startDate] = parse_date( param[:startDate] )
60
+ requesttype[:endDate] = parse_date( param[:endDate] )
61
+ return requesttype
62
+ end
63
+
64
+ private
65
+ def self.parse_date( date )
66
+ """
67
+ Cast string to time:
68
+ 'YYYYMMDD' => Time
69
+ """
70
+ if date
71
+ y = date[0..3]
72
+ m = date[4..5]
73
+ d = date[6..7]
74
+ date = Time.new( y, m, d )
75
+ else
76
+ date = (Time.now - 24*3600)
77
+ end
78
+ date.to_s[0,10]
79
+ end
80
+
81
+ def download_report( auth, param, debug = false )
82
+ response = call('report').get_id( auth, param )
83
+ if response[:succ]
84
+ id = response[:result]
85
+ p "Got report id:" + id.to_s if debug
86
+ loop do
87
+ sleep 2
88
+ break if call('report').get_state( auth, id )[:result] == 'Finished'
89
+ p "Report is not generated, waiting..." if debug
90
+ end
91
+ # need to rewrite the download method here.
92
+ url = call('report').get_url( auth, id )[:result]
93
+ return open(url).read.force_encoding('gb18030').encode('utf-8')
94
+ else
95
+ raise response[:failure][0]["message"]
96
+ end
97
+ end
98
+
99
+ ###########################
100
+ # intreface for Operation #
101
+ ###########################
102
+ def query_report( auth, param = nil, debug = false )
103
+ param = {} if not param
104
+ param[:type] ||= 'query'
105
+ param[:fields] ||= %w(click)
106
+ param[:level] ||= 'pair'
107
+ param[:range] ||= 'account'
108
+ param[:unit] ||= 'day'
109
+ download_report( param, debug )
110
+ end
111
+
112
+ def creative_report( auth, param = nil, debug = false )
113
+ param = {} if not param
114
+ param[:type] ||= 'creative'
115
+ param[:fields] ||= %w( cost cpc click impression ctr )
116
+ param[:level] ||= 'creative'
117
+ param[:range] ||= 'creative'
118
+ param[:unit] ||= 'day'
119
+ download_report( param, debug )
120
+ end
121
+
122
+ def keyword_report( auth, param = nil, debug = false )
123
+ param = {} if not param
124
+ param[:type] ||= 'keyword'
125
+ param[:fields] ||= %w( cost cpc click impression ctr )
126
+ param[:level] ||= 'keywordid'
127
+ param[:range] ||= 'keywordid'
128
+ param[:unit] ||= 'day'
129
+ download_report( param, debug )
130
+ end
131
+
132
+ end # Repost
133
+ end # Baidu
134
+ end # API
135
+ end # PPC
data/lib/ppc/api/sm.rb ADDED
@@ -0,0 +1,50 @@
1
+ # -*- coding:utf-8 -*-
2
+ require 'ppc/api/sm/account'
3
+ require 'ppc/api/sm/plan'
4
+ require 'ppc/api/sm/bulk'
5
+ require 'ppc/api/sm/group'
6
+ require 'ppc/api/sm/keyword'
7
+ require 'ppc/api/sm/report'
8
+ require 'ppc/api/sm/creative'
9
+ module PPC
10
+ module API
11
+ class Sm
12
+
13
+ extend ::PPC::API
14
+
15
+ def self.request_uri(param = {})
16
+ URI("https://e.sm.cn/api/#{param[:service]}/#{param[:method]}")
17
+ end
18
+
19
+ def self.process( response, key, &func)
20
+ '''
21
+ Process Http response. If operation successes, return value of given keys.
22
+ You can process the result using function &func, or do nothing by passing
23
+ block {|x|x}
24
+ ===========================
25
+ @Output: resultType{ desc: boolean, failure: Array, result: Array }
26
+
27
+ failure is the failures part of response\'s header
28
+ result is the processed response body.
29
+ '''
30
+ result = {}
31
+ result[:succ] = response['header']['desc'] =='success'
32
+ result[:failure] = response['header']['failures']
33
+ if !response['body'].nil? && response['body'][key]
34
+ result[:result] = func[ response['body'][key] ]
35
+ end
36
+ result[:no_quota] = is_no_quota(response['header']['failures'], '8501')
37
+ result
38
+ end # process
39
+
40
+ def self.reverse_type( types, maps = @map )
41
+ types = [ types ] unless types.is_a? Array
42
+ types.map do |item|
43
+ maps.each{|m| item.filter_and_replace_key(m[0],m[1].to_s)}
44
+ item
45
+ end
46
+ end
47
+
48
+ end # Sm
49
+ end # API
50
+ end # PPC
@@ -0,0 +1,44 @@
1
+ module PPC
2
+ module API
3
+ class Sm
4
+ class Account < Sm
5
+ Service = 'account'
6
+
7
+ @map = [
8
+ [:id,:userId],
9
+ [:balance,:balance],
10
+ [:cost,:cost],
11
+ [:payment,:payment],
12
+ [:budget_type,:budgetType],
13
+ [:budget,:budget],
14
+ [:region,:regionTarget],
15
+ [:exclude_ip,:excludeIp],
16
+ [:open_domains,:openDomains],
17
+ [:reg_domain,:regDomain],
18
+ [:offline_time,:budgetOfflineTime],
19
+ [:weekly_budget,:weeklyBudget]
20
+ ]
21
+
22
+ def self.info( auth )
23
+ response = request(auth, Service, 'getAccount', {requestData: ["account_all"]})
24
+ p response
25
+ return process( response, 'accountInfoType' ){ |x|reverse_type(x)[0] }
26
+ end
27
+
28
+ def self.update(auth, param = {} )
29
+ """
30
+ update account info
31
+ @ params : account_info_type
32
+ @return : account info_type
33
+ """
34
+ # for account service, there is not bulk operation
35
+ infoType = make_type( param )[0]
36
+ body = { accountInfoType: infoType }
37
+ response = request(auth, Service, 'updateAccount', body)
38
+ return process( response, 'accountInfoType' ){ |x|reverse_type(x)[0] }
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,69 @@
1
+ module PPC
2
+ module API
3
+ class Sm
4
+ class Bulk < Sm
5
+ Service = 'bulkJob'
6
+
7
+ def self.get_all_object( auth,params = {})
8
+
9
+ plan_ids = params[:plan_ids]
10
+
11
+ unless plan_ids.nil?
12
+ plan_ids = plan_ids.class == Array ? plan_ids : [plan_ids]
13
+ end
14
+
15
+ options = {
16
+ bulkJobRequestType: {
17
+ campaignIds: plan_ids || []
18
+ }
19
+ }
20
+ response = request( auth, Service, 'getAllObjects',options )
21
+ process( response, 'taskId'){ |x| x }
22
+ end
23
+
24
+ def self.get_file_id( auth, id)
25
+ raise "empty id" if id.nil?
26
+ response = request(auth, 'task', 'getTaskState',{taskId: id})
27
+ process( response, 'fileId'){ |x| x }
28
+ end
29
+
30
+ def self.do_download(auth, id)
31
+ request(auth, 'file', 'download',{fileId: id})
32
+ end
33
+
34
+ ###########################
35
+ # interface for operation #
36
+ ###########################
37
+ def self.download( auth, params = {} )
38
+ """
39
+ """
40
+ begin
41
+ result = get_all_object( auth, params )
42
+ if result[:succ]
43
+ task_id = result[:result]
44
+ else
45
+ raise "获取task id 失败"
46
+ end
47
+
48
+ puts "task_id: #{task_id}" if @debug
49
+
50
+ loop do
51
+ file_id = get_file_id( auth, task_id )[:result]
52
+ if file_id.nil?
53
+ sleep 15
54
+ next
55
+ end
56
+ File.open("sm_#{file_id}.zip", "w") do |f|
57
+ f.puts do_download(auth, file_id)
58
+ end
59
+ return
60
+ end
61
+ rescue => e
62
+ p "Error encounter:#{e.to_s}"
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,86 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Sm
5
+ class Creative< Sm
6
+ Service = 'creative'
7
+
8
+ @map =[
9
+ [:id, :creativeId],
10
+ [:group_id, :adgroupId],
11
+ [:title, :title],
12
+ [:description1, :description1],
13
+ [:pause, :pause],
14
+ [:mobile_destination, :destinationUrl],
15
+ [:mobile_display, :displayUrl],
16
+ [:status, :status]
17
+ ]
18
+
19
+ def self.add(auth, creatives)
20
+ body = {creativeTypes: make_type(creatives)}
21
+ response = request(auth, Service, 'addCreative', body)
22
+ process(response, 'creativeTypes'){|x| reverse_type(x)}
23
+ end
24
+
25
+ def self.get(auth, ids)
26
+ ids = [ids] unless ids.is_a? Array
27
+ body = {creativeIds: ids}
28
+ response = request(auth, Service, 'getCreativeByCreativeId', body)
29
+ process(response, 'creativeTypes'){|x| reverse_type(x)}
30
+ end
31
+
32
+ def self.update(auth, creatives)
33
+ body = {creativeTypes: make_type(creatives)}
34
+ response = request(auth, Service, 'updateCreative', body)
35
+ process(response, 'creativeTypes'){|x| reverse_type(x)}
36
+ end
37
+
38
+ def self.delete(auth, ids)
39
+ ids = [ids] unless ids.is_a? Array
40
+ body = {creativeIds: ids}
41
+ response = request(auth, Service, 'deleteCreative', body, 'delete')
42
+ process(response, 'result'){|x| x}
43
+ end
44
+
45
+ def self.search_id_by_group_id(auth, ids)
46
+ ids = [ids] unless ids.is_a? Array
47
+ body = {adgroupIds: ids}
48
+ response = request(auth, Service, 'getCreativeIdByAdgroupId', body)
49
+ process(response, 'groupCreativeIds'){|x| make_groupCreativeIds(x)}
50
+ end
51
+
52
+ def self.search_by_group_id(auth, ids)
53
+ ids = [ids] unless ids.is_a? Array
54
+ body = {adgroupIds: ids}
55
+ response = request(auth, Service, 'getCreativeByAdgroupId', body)
56
+ process(response, 'groupCreatives'){|x| make_groupCreatives(x)}
57
+ end
58
+
59
+ private
60
+ def self.make_groupCreativeIds( groupCreativeIds )
61
+ group_creative_ids = []
62
+ groupCreativeIds.each do |groupCreativeId|
63
+ group_creative_id = { }
64
+ group_creative_id[:group_id] = groupCreativeId['adgroupId']
65
+ group_creative_id[:creative_ids] = groupCreativeId['creativeIds']
66
+ group_creative_ids << group_creative_id
67
+ end
68
+ return group_creative_ids
69
+ end
70
+
71
+ private
72
+ def self.make_groupCreatives( groupCreatives )
73
+ group_creatives = []
74
+ groupCreatives.each do |groupCreative |
75
+ group_creative = {}
76
+ group_creative[:group_id] = groupCreative['adgroupId']
77
+ group_creative[:creatives] = reverse_type( groupCreative['creativeTypes'] )
78
+ group_creatives << group_creative
79
+ end
80
+ return group_creatives
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,94 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Sm
5
+ class Group < Sm
6
+ Service = 'adgroup'
7
+
8
+ @map =[
9
+ [:plan_id, :campaignId],
10
+ [:id, :adgroupId],
11
+ [:name, :adgroupName],
12
+ [:price, :maxPrice],
13
+ [:negative, :negativeWords],
14
+ [:exact_negative, :exactNegativeWords],
15
+ [:pause, :pause],
16
+ [:status, :status],
17
+ [:os, :adPlatformOS]
18
+ ]
19
+
20
+ def self.ids( auth )
21
+ response = request(auth, Service, "getAllAdgroupId")
22
+ process(response, 'campaignAdgroupIds'){|x| make_planGroupIds(x)}
23
+ end
24
+
25
+ def self.get(auth, ids)
26
+ ids = [ ids ] unless ids.is_a? Array
27
+ body = {adgroupIds: ids}
28
+ response = request(auth, Service, "getAdgroupByAdgroupId", body)
29
+ process(response, 'adgroupTypes'){|x| reverse_type(x)}
30
+ end
31
+
32
+ def self.add(auth, groups)
33
+ adgroup_types = make_type(groups)
34
+ body = {adgroupTypes: adgroup_types}
35
+ response = request(auth, Service, "addAdgroup", body)
36
+ process(response, 'adgroupTypes'){|x| reverse_type(x)}
37
+ end
38
+
39
+ def self.update(auth, groups)
40
+ adgroup_types = make_type(groups)
41
+ body = {adgroupTypes: adgroup_types}
42
+ response = request(auth, Service, "updateAdgroup", body)
43
+ process(response, 'adgroupTypes'){|x| reverse_type(x)}
44
+ end
45
+
46
+ def self.delete(auth, ids)
47
+ ids = [ids] unless ids.is_a? Array
48
+ body = {adgroupIds: ids}
49
+ response = request(auth, Service, "deleteAdgroup", body, "delete")
50
+ process(response, 'result'){ |x| x }
51
+ end
52
+
53
+ def self.search_by_plan_id(auth, ids)
54
+ ids = [ ids ] unless ids.class == Array
55
+ body = { campaignIds: ids }
56
+ response = request(auth, Service, "getAdgroupByCampaignId", body)
57
+ process(response, 'campaignAdgroups' ){ |x| make_planGroups( x ) }
58
+ end
59
+
60
+ def self.search_id_by_plan_id( auth, ids )
61
+ ids = [ ids ] unless ids.class == Array
62
+ body = { campaignIds: ids }
63
+ response = request(auth, Service, "getAdgroupIdByCampaignId", body)
64
+ process(response, 'campaignAdgroupIds'){ |x| make_planGroupIds( x ) }
65
+ end
66
+
67
+ private
68
+ def self.make_planGroupIds( campaignAdgroupIds )
69
+ planGroupIds = []
70
+ campaignAdgroupIds.each do |campaignAdgroupId|
71
+ planGroupId = { }
72
+ planGroupId[:plan_id] = campaignAdgroupId['campaignId']
73
+ planGroupId[:group_ids] = campaignAdgroupId['adgroupIds']
74
+ planGroupIds << planGroupId
75
+ end
76
+ return planGroupIds
77
+ end
78
+
79
+ private
80
+ def self.make_planGroups( campaignAdgroups )
81
+ planGroups = []
82
+ campaignAdgroups.each do |campaignAdgroup|
83
+ planGroup = {}
84
+ planGroup[:plan_id] = campaignAdgroup['campaignId']
85
+ planGroup[:groups] = reverse_type( campaignAdgroup['adgroupTypes'] )
86
+ planGroups << planGroup
87
+ end
88
+ return planGroups
89
+ end
90
+
91
+ end # class group
92
+ end # class baidu
93
+ end # API
94
+ end # module