rhoconnect-adapters 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG +4 -0
  3. data/Gemfile +18 -0
  4. data/README.md +239 -0
  5. data/Rakefile +31 -0
  6. data/bin/rhoconnect-adapters +35 -0
  7. data/generators/crm/templates/application/application.rb +34 -0
  8. data/generators/crm/templates/source/source_adapter.rb +10 -0
  9. data/generators/crm/templates/source/source_spec.rb +25 -0
  10. data/generators/crm/templates/spec/spec_helper.rb +64 -0
  11. data/generators/crm/vendor/ms_dynamics/adapter.rb +301 -0
  12. data/generators/crm/vendor/ms_dynamics/application.rb +56 -0
  13. data/generators/crm/vendor/ms_dynamics/lib/crm_metadata_service.rb +43 -0
  14. data/generators/crm/vendor/ms_dynamics/lib/crm_service.rb +141 -0
  15. data/generators/crm/vendor/ms_dynamics/lib/discovery_service.rb +51 -0
  16. data/generators/crm/vendor/ms_dynamics/lib/wlid_service.rb +159 -0
  17. data/generators/crm/vendor/ms_dynamics/ms_dynamics.rb +45 -0
  18. data/generators/crm/vendor/ms_dynamics/settings/Account.yml +46 -0
  19. data/generators/crm/vendor/ms_dynamics/settings/Contact.yml +40 -0
  20. data/generators/crm/vendor/ms_dynamics/settings/GenericObject.yml +18 -0
  21. data/generators/crm/vendor/ms_dynamics/settings/Lead.yml +53 -0
  22. data/generators/crm/vendor/ms_dynamics/settings/Opportunity.yml +41 -0
  23. data/generators/crm/vendor/ms_dynamics/settings/settings.yml +9 -0
  24. data/generators/crm/vendor/ms_dynamics/spec/application_spec.rb +23 -0
  25. data/generators/crm/vendor/ms_dynamics/spec/sources/account_spec.rb +49 -0
  26. data/generators/crm/vendor/ms_dynamics/spec/sources/contact_spec.rb +49 -0
  27. data/generators/crm/vendor/ms_dynamics/spec/sources/lead_spec.rb +49 -0
  28. data/generators/crm/vendor/ms_dynamics/spec/sources/opportunity_spec.rb +62 -0
  29. data/generators/crm/vendor/ms_dynamics/spec/spec_helper.rb +78 -0
  30. data/generators/crm/vendor/ms_dynamics/spec_data/Account.yml +6 -0
  31. data/generators/crm/vendor/ms_dynamics/spec_data/Contact.yml +7 -0
  32. data/generators/crm/vendor/ms_dynamics/spec_data/GenericObject.yml +3 -0
  33. data/generators/crm/vendor/ms_dynamics/spec_data/Lead.yml +12 -0
  34. data/generators/crm/vendor/ms_dynamics/spec_data/Opportunity.yml +6 -0
  35. data/generators/crm/vendor/ms_dynamics/templates.rb +57 -0
  36. data/generators/crm/vendor/oracle_on_demand/adapter.rb +421 -0
  37. data/generators/crm/vendor/oracle_on_demand/application.rb +64 -0
  38. data/generators/crm/vendor/oracle_on_demand/settings/Account.yml +91 -0
  39. data/generators/crm/vendor/oracle_on_demand/settings/Contact.yml +54 -0
  40. data/generators/crm/vendor/oracle_on_demand/settings/GenericObject.yml +21 -0
  41. data/generators/crm/vendor/oracle_on_demand/settings/Lead.yml +72 -0
  42. data/generators/crm/vendor/oracle_on_demand/settings/Opportunity.yml +69 -0
  43. data/generators/crm/vendor/oracle_on_demand/settings/settings.yml +8 -0
  44. data/generators/crm/vendor/oracle_on_demand/spec/application_spec.rb +14 -0
  45. data/generators/crm/vendor/oracle_on_demand/spec/sources/account_spec.rb +50 -0
  46. data/generators/crm/vendor/oracle_on_demand/spec/sources/contact_spec.rb +50 -0
  47. data/generators/crm/vendor/oracle_on_demand/spec/sources/lead_spec.rb +51 -0
  48. data/generators/crm/vendor/oracle_on_demand/spec/sources/opportunity_spec.rb +51 -0
  49. data/generators/crm/vendor/oracle_on_demand/spec_data/Account.yml +8 -0
  50. data/generators/crm/vendor/oracle_on_demand/spec_data/Contact.yml +8 -0
  51. data/generators/crm/vendor/oracle_on_demand/spec_data/GenericObject.yml +4 -0
  52. data/generators/crm/vendor/oracle_on_demand/spec_data/Lead.yml +14 -0
  53. data/generators/crm/vendor/oracle_on_demand/spec_data/Opportunity.yml +6 -0
  54. data/generators/crm/vendor/oracle_on_demand/templates.rb +52 -0
  55. data/generators/crm/vendor/salesforce/adapter.rb +315 -0
  56. data/generators/crm/vendor/salesforce/application.rb +80 -0
  57. data/generators/crm/vendor/salesforce/settings/Account.yml +53 -0
  58. data/generators/crm/vendor/salesforce/settings/Contact.yml +61 -0
  59. data/generators/crm/vendor/salesforce/settings/GenericObject.yml +13 -0
  60. data/generators/crm/vendor/salesforce/settings/Lead.yml +73 -0
  61. data/generators/crm/vendor/salesforce/settings/Opportunity.yml +48 -0
  62. data/generators/crm/vendor/salesforce/settings/settings.yml +6 -0
  63. data/generators/crm/vendor/salesforce/spec/application_spec.rb +14 -0
  64. data/generators/crm/vendor/salesforce/spec/sources/account_spec.rb +50 -0
  65. data/generators/crm/vendor/salesforce/spec/sources/contact_spec.rb +50 -0
  66. data/generators/crm/vendor/salesforce/spec/sources/lead_spec.rb +51 -0
  67. data/generators/crm/vendor/salesforce/spec/sources/opportunity_spec.rb +51 -0
  68. data/generators/crm/vendor/salesforce/spec_data/Account.yml +14 -0
  69. data/generators/crm/vendor/salesforce/spec_data/Contact.yml +8 -0
  70. data/generators/crm/vendor/salesforce/spec_data/GenericObject.yml +3 -0
  71. data/generators/crm/vendor/salesforce/spec_data/Lead.yml +10 -0
  72. data/generators/crm/vendor/salesforce/spec_data/Opportunity.yml +10 -0
  73. data/generators/crm/vendor/salesforce/templates.rb +45 -0
  74. data/generators/crm/vendor/sugar/adapter.rb +291 -0
  75. data/generators/crm/vendor/sugar/application.rb +50 -0
  76. data/generators/crm/vendor/sugar/settings/Account.yml +49 -0
  77. data/generators/crm/vendor/sugar/settings/Contact.yml +62 -0
  78. data/generators/crm/vendor/sugar/settings/GenericObject.yml +12 -0
  79. data/generators/crm/vendor/sugar/settings/Lead.yml +76 -0
  80. data/generators/crm/vendor/sugar/settings/Opportunity.yml +49 -0
  81. data/generators/crm/vendor/sugar/settings/settings.yml +9 -0
  82. data/generators/crm/vendor/sugar/spec/application_spec.rb +25 -0
  83. data/generators/crm/vendor/sugar/spec/sources/account_spec.rb +53 -0
  84. data/generators/crm/vendor/sugar/spec/sources/contact_spec.rb +53 -0
  85. data/generators/crm/vendor/sugar/spec/sources/lead_spec.rb +54 -0
  86. data/generators/crm/vendor/sugar/spec/sources/opportunity_spec.rb +54 -0
  87. data/generators/crm/vendor/sugar/spec_data/Account.yml +13 -0
  88. data/generators/crm/vendor/sugar/spec_data/Contact.yml +8 -0
  89. data/generators/crm/vendor/sugar/spec_data/GenericObject.yml +3 -0
  90. data/generators/crm/vendor/sugar/spec_data/Lead.yml +16 -0
  91. data/generators/crm/vendor/sugar/spec_data/Opportunity.yml +10 -0
  92. data/generators/crm/vendor/sugar/sugar.rb +33 -0
  93. data/generators/crm/vendor/sugar/templates.rb +58 -0
  94. data/generators/rhoconnect-adapters.rb +217 -0
  95. data/lib/rhoconnect-adapters/crm/crm.rb +31 -0
  96. data/lib/rhoconnect-adapters/soap_service.rb +70 -0
  97. data/lib/rhoconnect-adapters/version.rb +3 -0
  98. data/lib/rhoconnect-adapters.rb +2 -0
  99. data/rhoconnect-adapters.gemspec +36 -0
  100. data/spec/apps/ms_dynamics_spec.rb +19 -0
  101. data/spec/apps/oracle_on_demand_spec.rb +20 -0
  102. data/spec/apps/salesforce_spec.rb +18 -0
  103. data/spec/apps/sugar_spec.rb +18 -0
  104. data/spec/generator/generator_spec.rb +113 -0
  105. data/spec/spec_helper.rb +57 -0
  106. metadata +288 -0
@@ -0,0 +1,301 @@
1
+ require 'rhoconnect-adapters'
2
+ require 'vendor/ms_dynamics/ms_dynamics'
3
+ require 'active_support/inflector'
4
+
5
+ module RhoconnectAdapters
6
+ module CRM
7
+ module MsDynamics
8
+ class Adapter < SourceAdapter
9
+ attr_accessor :crm_object
10
+ attr_accessor :fields
11
+
12
+ def initialize(source)
13
+ super(source)
14
+ @crm_object = self.class.name
15
+ @fields = {}
16
+ @title_fields = ["#{crm_object.downcase}id"]
17
+ end
18
+
19
+ def configure_fields
20
+ # initialize fields map
21
+ @fields = get_object_settings['Query_Fields']
22
+ @field_picklists = {}
23
+
24
+ # obtain attribute type picklists
25
+ @attrtype_picklists = {}
26
+ attribute_type_picklists = get_object_settings['AttributeTypePicklists']
27
+ if attribute_type_picklists != nil
28
+ attribute_type_picklists.each do |element_name, values|
29
+ @attrtype_picklists[element_name] = values
30
+ end
31
+ end
32
+
33
+ @object_fields = get_object_settings['ObjectFields']
34
+ @object_fields = {} if @object_fields == nil
35
+
36
+ # title fields are used in metadata to show
37
+ # records in the list
38
+ @title_fields = get_object_settings['TitleFields']
39
+
40
+ @fields
41
+ end
42
+
43
+ def get_object_settings
44
+ return @object_settings if @object_settings
45
+ begin
46
+ @object_settings = RhoconnectAdapters::CRM::Field.load_file(File.join(ROOT_PATH,'vendor','ms_dynamics','settings',"#{crm_object.downcase}.yml"))
47
+ rescue Exception => e
48
+ puts "Error opening CRMObjects settings file: #{e}"
49
+ puts e.backtrace.join("\n")
50
+ raise e
51
+ end
52
+ end
53
+
54
+ def get_picklists
55
+ begin
56
+ fields.each do |element_name, element_def|
57
+ # exclude artificial attribute type fields
58
+ next if @attrtype_picklists.has_key?(element_name)
59
+ data_type = element_def['Type']
60
+ # for picklists - get values
61
+ # but only for those that are not
62
+ # already defined statically
63
+ if data_type == 'Picklist' and not @field_picklists.has_key?(element_name)
64
+ @field_picklists[element_name] = get_picklist(element_name)
65
+ end
66
+ end
67
+ rescue RestClient::Exception => e
68
+ raise e
69
+ end
70
+ end
71
+
72
+ def get_picklist(element_name)
73
+ # check if we already have it in Store
74
+ picklist = Store.get_data("#{crm_object}:#{element_name}_picklist",Hash)
75
+ return picklist['picklist_vals'] if picklist.size != 0
76
+
77
+ field_values = @crm_metadata_service.request_picklist("#{crm_object.downcase}",element_name)
78
+ Store.put_data("#{crm_object}:#{element_name}_picklist", { 'picklist_vals' => field_values })
79
+ field_values
80
+ end
81
+
82
+ def login
83
+ auth_info = RhoconnectAdapters::CRM::MsDynamics.load_auth_info("#{current_user.login}")
84
+ @endpoint_url = auth_info['crm_service_url']
85
+ @crm_service = RhoconnectAdapters::CRM::MsDynamics::CrmService.new(@endpoint_url, auth_info['crm_ticket'], auth_info['user_organization'])
86
+ @crm_metadata_service = RhoconnectAdapters::CRM::MsDynamics::CrmMetadataService.new(auth_info['crm_metadata_service_url'], auth_info['crm_ticket'], auth_info['user_organization'])
87
+ # query picklist values
88
+ get_picklists
89
+ end
90
+
91
+ def query(params=nil)
92
+ # TODO: Query your backend data source and assign the records
93
+ # to a nested hash structure called @result. For example:
94
+ # @result = {
95
+ # "1"=>{"name"=>"Acme", "industry"=>"Electronics"},
96
+ # "2"=>{"name"=>"Best", "industry"=>"Software"}
97
+ # }
98
+ @result = {}
99
+
100
+ attributes = []
101
+ # strip out artificial 'attrtype' fields
102
+ fields.each do |key, val|
103
+ attributes << key unless key.index('_attrtype') != nil
104
+ end
105
+
106
+ @result = @crm_service.retrieve_multiple(crm_object.downcase,attributes,@field_picklists)
107
+ end
108
+
109
+ def metadata
110
+ # define the metadata
111
+ show_fields = []
112
+ new_fields = []
113
+ edit_fields = []
114
+ model_name = "" + crm_object
115
+ model_name[0] = model_name[0,1].downcase
116
+ record_sym = '@' + "#{model_name}"
117
+ fields.each do |element_name,element_def|
118
+ next if element_name == "#{crm_object.downcase}id"
119
+
120
+ # 1) - read-only show fields
121
+ field_type = 'labeledvalueli'
122
+ field = {
123
+ :name => "#{model_name}\[#{element_name}\]",
124
+ :label => element_def['Label'],
125
+ :type => field_type,
126
+ :value => "{{#{record_sym}/#{element_name}}}"
127
+ }
128
+ show_fields << field
129
+
130
+ new_field = field.clone
131
+ new_field[:type] = 'labeledinputli'
132
+ new_field.delete(:value)
133
+ case element_def['Type']
134
+ when 'Picklist'
135
+ new_field[:type] = 'select'
136
+ values = []
137
+ # attribute type fields should be treated specially
138
+ if element_name.index('_attrtype') != nil
139
+ values.concat @attrtype_picklists[element_name]
140
+ else
141
+ values[0] = nil
142
+ values.concat @field_picklists[element_name].values
143
+ end
144
+ new_field[:values] = values
145
+ new_field[:value] = values[0]
146
+ when 'object'
147
+ end
148
+
149
+ new_fields << new_field if not element_def['Type'] == 'object'
150
+
151
+ edit_field = new_field.clone
152
+ edit_field[:value] = "{{#{record_sym}/#{element_name}}}"
153
+ edit_fields << edit_field
154
+ end
155
+
156
+ # Show
157
+ show_list = { :name => 'list', :type => 'list', :children => show_fields }
158
+ show_form = {
159
+ :name => "#{crm_object}_show",
160
+ :type => 'show_form',
161
+ :title => "#{crm_object} details",
162
+ :object => "#{crm_object}",
163
+ :model => "#{model_name}",
164
+ :id => "{{#{record_sym}/object}}",
165
+ :children => [show_list]
166
+ }
167
+
168
+ # New
169
+ new_list = show_list.clone
170
+ new_list[:children] = new_fields
171
+ new_form = {
172
+ :type => 'new_form',
173
+ :title => "New #{crm_object}",
174
+ :object => "#{crm_object}",
175
+ :model => "#{model_name}",
176
+ :children => [new_list]
177
+ }
178
+
179
+ # Edit
180
+ edit_list = show_list.clone
181
+ edit_list[:children] = edit_fields
182
+ edit_form = {
183
+ :type => 'update_form',
184
+ :title => "Edit #{crm_object}",
185
+ :object => "#{crm_object}",
186
+ :model => "#{model_name}",
187
+ :id => "{{#{record_sym}/object}}",
188
+ :children => [edit_list]
189
+ }
190
+
191
+ # Index
192
+ title_field_metadata = @title_fields.collect { |field_name | "{{#{field_name.to_s}}} " }.join(' ')
193
+ object_rec = {
194
+ :object => "#{crm_object}",
195
+ :id => "{{object}}",
196
+ :type => 'linkobj',
197
+ :text => "#{title_field_metadata}"
198
+ }
199
+
200
+ index_form = {
201
+ :title => "#{crm_object.pluralize}",
202
+ :object => "#{crm_object}",
203
+ :type => 'index_form',
204
+ :children => [object_rec],
205
+ :repeatable => "{{#{record_sym.pluralize}}}"
206
+ }
207
+
208
+ # return JSON
209
+ { 'index' => index_form, 'show' => show_form, 'new' => new_form, 'edit' => edit_form }.to_json
210
+ end
211
+
212
+ def create(create_hash,blob=nil)
213
+ # TODO: Create a new record in your backend data source
214
+ # If your rhodes rhom object contains image/binary data
215
+ # (has the image_uri attribute), then a blob will be provided
216
+ created_object_id = nil
217
+ request_fields = {}
218
+ field_types = {}
219
+ fields.each do |element_name, element_def|
220
+ field_value = create_hash[element_name]
221
+
222
+ # special case scenario where the field is
223
+ # actually a 'type' attribute of another field
224
+ type_index = element_name.index('_attrtype')
225
+ if type_index != nil
226
+ field_name = element_name.slice(0, type_index)
227
+ field_types[field_name] = field_value
228
+ next
229
+ end
230
+
231
+ # convert Picklist field values from User-friendly form
232
+ # into Integers that are accepted by MsDynamics
233
+ if @field_picklists.has_key?(element_name)
234
+ field_picklist_indexes = @field_picklists[element_name].invert
235
+ field_value = field_picklist_indexes[field_value]
236
+ end
237
+
238
+ if field_value != nil and element_name != "#{crm_object.downcase}id"
239
+ request_fields[element_name] = field_value
240
+ end
241
+ end
242
+
243
+ created_object_id = @crm_service.create(crm_object.downcase, request_fields, field_types)
244
+ end
245
+ def update(update_hash)
246
+ # it may be there as 'id' field
247
+ updated_object_id = update_hash["#{crm_object.downcase}id"] || update_hash['id']
248
+ if updated_object_id == nil
249
+ raise SourceAdapterObjectConflictError.new("Either '#{crm_object.downcase}id' or 'id' field must be specified for the Update request")
250
+ end
251
+
252
+ request_fields = {}
253
+ field_types = {}
254
+ fields.each do |element_name,element_def|
255
+ next unless element_name != "#{crm_object.downcase}id"
256
+
257
+ field_value = update_hash[element_name]
258
+
259
+ # special case scenario where the field is
260
+ # actually a 'type' attribute of another field
261
+ type_index = element_name.index('_attrtype')
262
+ if type_index != nil
263
+ field_name = element_name.slice(0, type_index)
264
+ field_types[field_name] = field_value
265
+ next
266
+ end
267
+
268
+ # convert Picklist field values from User-friendly form
269
+ # into Integers that are accepted by MsDynamics
270
+ if @field_picklists.has_key?(element_name)
271
+ field_picklist_indexes = @field_picklists[element_name].invert
272
+ field_value = field_picklist_indexes[field_value]
273
+ end
274
+
275
+ if field_value != nil
276
+ request_fields[element_name] = field_value
277
+ end
278
+ end
279
+
280
+ @crm_service.update(crm_object.downcase, updated_object_id, request_fields, field_types)
281
+ updated_object_id
282
+ end
283
+
284
+ def delete(delete_hash)
285
+ deleted_object_id = delete_hash["#{crm_object.downcase}id"] || delete_hash['id']
286
+
287
+ if deleted_object_id == nil
288
+ raise SourceAdapterObjectConflictError.new("Either '#{crm_object.downcase}id' or 'id' field must be specified for the Delete request")
289
+ end
290
+
291
+ @crm_service.delete(crm_object.downcase, deleted_object_id)
292
+ deleted_object_id
293
+ end
294
+
295
+ def logoff
296
+ # logoff if necessary
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,56 @@
1
+ require 'rhoconnect-adapters'
2
+ require 'vendor/ms_dynamics/ms_dynamics'
3
+
4
+ module RhoconnectAdapters
5
+ module CRM
6
+ module MsDynamics
7
+ class Application < Rhoconnect::Base
8
+ class << self
9
+ def authenticate(username,password,session)
10
+ begin
11
+ # TODO: handle exceptions
12
+ # From time to time Win Live doesn't respond or returns 400 (Bad Request);
13
+ # we probably should retry in such cases
14
+ wlid_ticket, wlid_expires =
15
+ RhoconnectAdapters::CRM::MsDynamics::WlidService.get_ticket(username,password)
16
+ crm_service_url, crm_metadata_service_url, crm_ticket, crm_ticket_expires, user_organization =
17
+ RhoconnectAdapters::CRM::MsDynamics::DiscoveryService.get_crm_ticket(get_settings[:msdynamics_ticket_url],wlid_ticket)
18
+ # store recieved tickets and associated information in redis for the future reference
19
+ RhoconnectAdapters::CRM::MsDynamics.save_auth_info(username,
20
+ {
21
+ "wlid_ticket" => wlid_ticket,
22
+ "wlid_expires" => wlid_expires.to_s,
23
+ "crm_service_url" => crm_service_url,
24
+ "crm_metadata_service_url" => crm_metadata_service_url,
25
+ "crm_ticket" => crm_ticket,
26
+ "crm_ticket_expires" => crm_ticket_expires.to_s,
27
+ "user_organization" => user_organization
28
+ })
29
+ rescue Exception => ex
30
+ warn "Can't authenticate user #{username}: " + ex.inspect
31
+ return false
32
+ end
33
+ true
34
+ end
35
+
36
+ def get_settings
37
+ return @settings if @settings
38
+ begin
39
+ file = YAML.load_file(File.join(ROOT_PATH,'settings','settings.yml'))
40
+ env = (ENV['RHO_ENV'] || :development).to_sym
41
+ @settings = file[env]
42
+
43
+ # vendor-specific settings
44
+ file = YAML.load_file(File.join(ROOT_PATH,'vendor','ms_dynamics','settings','settings.yml'))
45
+ @settings.merge!(file[env])
46
+ rescue Exception => e
47
+ puts "Error opening settings file: #{e}"
48
+ puts e.backtrace.join("\n")
49
+ raise e
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,43 @@
1
+ module RhoconnectAdapters
2
+ module CRM
3
+ module MsDynamics
4
+ class CrmMetadataService < SoapService
5
+ def initialize(crm_metadata_service_url,crm_ticket,user_organization)
6
+ @crm_metadata_service_url = crm_metadata_service_url
7
+ @message_header = "
8
+ <CrmAuthenticationToken xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">
9
+ <AuthenticationType xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">1</AuthenticationType>
10
+ <CrmTicket xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">#{crm_ticket}</CrmTicket>
11
+ <OrganizationName xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">#{user_organization}</OrganizationName>
12
+ <CallerId xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">00000000-0000-0000-0000-000000000000</CallerId>
13
+ </CrmAuthenticationToken>"
14
+ end
15
+
16
+ def request_picklist(entity_name,attribute)
17
+ message = SoapService.compose_message(@message_header,
18
+ "<Execute xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">
19
+ <Request xsi:type=\"RetrieveAttributeRequest\">
20
+ <EntityLogicalName>#{entity_name}</EntityLogicalName>
21
+ <LogicalName>#{attribute}</LogicalName>
22
+ <RetrieveAsIfPublished>1</RetrieveAsIfPublished>
23
+ </Request>
24
+ </Execute>")
25
+ doc = SoapService.send_request(@crm_metadata_service_url,message,get_action('Execute'))
26
+ result = {}
27
+ options = SoapService.select_node(doc, '//cws7:Option')
28
+ options.each do |option|
29
+ value = SoapService.select_node_text(option, 'cws7:Value')
30
+ result[value] = SoapService.select_node_text(option, 'cws7:Label/cws7:LocLabels/cws7:LocLabel/cws7:Label')
31
+ end
32
+ result
33
+ end
34
+
35
+ private
36
+ def get_action(name)
37
+ "http://schemas.microsoft.com/crm/2007/WebServices/#{name}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,141 @@
1
+ module RhoconnectAdapters
2
+ module CRM
3
+ module MsDynamics
4
+ class CrmService < SoapService
5
+ def initialize(crm_service_url,crm_ticket,user_organization)
6
+ @crm_service_url = crm_service_url
7
+ @message_header = "
8
+ <CrmAuthenticationToken xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">
9
+ <AuthenticationType xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">1</AuthenticationType>
10
+ <CrmTicket xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">#{crm_ticket}</CrmTicket>
11
+ <OrganizationName xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">#{user_organization}</OrganizationName>
12
+ <CallerId xmlns=\"http://schemas.microsoft.com/crm/2007/CoreTypes\">00000000-0000-0000-0000-000000000000</CallerId>
13
+ </CrmAuthenticationToken>"
14
+ end
15
+
16
+ def request(request_name)
17
+ message = SoapService.compose_message(@message_header,
18
+ "<Execute xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">
19
+ <Request xsi:type=\"#{request_name}\"/>
20
+ </Execute>")
21
+ SoapService.send_request(@crm_service_url,message,get_action('Execute'))
22
+ end
23
+
24
+ def retrieve(entity_name,entity_id,attributes)
25
+ message = SoapService.compose_message(@message_header,
26
+ "<Retrieve xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>
27
+ <entityName>#{entity_name}</entityName>
28
+ <id>#{entity_id}</id>
29
+ <columnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>
30
+ <q1:Attributes>
31
+ #{get_columns(attributes)}
32
+ </q1:Attributes>
33
+ </columnSet>
34
+ </Retrieve>")
35
+ doc = SoapService.send_request(@crm_service_url,message,get_action('Retrieve'))
36
+ res = {}
37
+ attributes.each do |attribute|
38
+ res.merge!(attribute => SoapService.select_node_text(doc,"//cws7:#{attribute}"))
39
+ end
40
+ res
41
+ end
42
+
43
+ def retrieve_multiple(entity_name, attributes, field_picklists_map, distinct=true, criteria_xml="")
44
+ message = SoapService.compose_message(@message_header,
45
+ "<RetrieveMultiple xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>
46
+ <query xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:QueryExpression'>
47
+ <q1:EntityName>#{entity_name}</q1:EntityName>
48
+ <q1:ColumnSet xsi:type='q1:ColumnSet'>
49
+ <q1:Attributes>
50
+ #{get_columns(attributes)}
51
+ </q1:Attributes>
52
+ </q1:ColumnSet>
53
+ <q1:Distinct>#{distinct.to_s}</q1:Distinct>
54
+ #{criteria_xml}
55
+ </query>
56
+ </RetrieveMultiple>")
57
+ doc = SoapService.send_request(@crm_service_url,message,get_action('RetrieveMultiple'))
58
+ business_entities = SoapService.select_node(doc,'//cws6:BusinessEntity')
59
+ result = {}
60
+ business_entities.each do |business_entity|
61
+ record = {}
62
+ business_entity.children.each do |field|
63
+ type_field = field.attributes['type']
64
+ record.merge!("#{field.name}_attrtype" => type_field) unless type_field.nil?
65
+ field_value = field.text
66
+ # convert IntegerValues for Picklist types into User-friendly strings
67
+ field_value = field_picklists_map[field.name][field.text] unless field_picklists_map[field.name].nil?
68
+ record.merge!(field.name => field_value)
69
+ end
70
+ clean_attributes(entity_name,record)
71
+ field_id = record["#{entity_name}id"]
72
+ result[field_id] = record unless field_id.nil?
73
+ end
74
+ result
75
+ end
76
+
77
+ def create(entity_name,params,types={})
78
+ message = SoapService.compose_message(@message_header,
79
+ "<Create xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>
80
+ <entity xsi:type='#{entity_name}'>
81
+ #{get_params(params,types)}
82
+ </entity>
83
+ </Create>")
84
+ doc = SoapService.send_request(@crm_service_url,message,get_action('Create'))
85
+ SoapService.select_node_text(doc,'//cws7:CreateResult')
86
+ end
87
+
88
+ def update(entity_name,entity_id,params,types={})
89
+ message = SoapService.compose_message(@message_header,
90
+ "<Update xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>
91
+ <entity xsi:type='#{entity_name}'>
92
+ #{get_params(params,types)}
93
+ <#{entity_name}id>#{entity_id}</#{entity_name}id>
94
+ </entity>
95
+ </Update>")
96
+ SoapService.send_request(@crm_service_url,message,get_action('Update'))
97
+ end
98
+
99
+ def delete(entity_name,entity_id)
100
+ message = SoapService.compose_message(@message_header,
101
+ "<Delete xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>
102
+ <entityName>#{entity_name}</entityName>
103
+ <id>#{entity_id}</id>
104
+ </Delete>")
105
+ SoapService.send_request(@crm_service_url,message,get_action('Delete'))
106
+ end
107
+
108
+ def get_current_user
109
+ doc = request('WhoAmIRequest')
110
+ SoapService.select_node_text(doc,'//cws7:UserId')
111
+ end
112
+
113
+ private
114
+ def get_action(name)
115
+ "http://schemas.microsoft.com/crm/2007/WebServices/#{name}"
116
+ end
117
+
118
+ def get_columns(attributes)
119
+ columns = attributes.collect { |attrib| "<q1:Attribute>#{attrib}</q1:Attribute>" }
120
+ columns.to_s
121
+ end
122
+
123
+ def get_params(params, types = {})
124
+ res = []
125
+ params.each do |name, value|
126
+ type_attr = " type='#{types[name].to_s}'" unless types[name].nil?
127
+ res << "<#{name}#{type_attr}>#{value}</#{name}>"
128
+ end
129
+ res.to_s
130
+ end
131
+
132
+ def clean_attributes(entity_name,attributes)
133
+ name = "#{entity_name}id"
134
+ id = attributes[name]
135
+ attributes[name] = id[1..-2] if id
136
+ attributes
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,51 @@
1
+ module RhoconnectAdapters
2
+ module CRM
3
+ module MsDynamics
4
+ class DiscoveryService < SoapService
5
+
6
+ # Get the Crm Service Url, Crm Ticket, Crm Ticket expiration date/time, and Unique User Organization Name
7
+ def self.get_crm_ticket(host_name,wlid_ticket)
8
+ @wlid_ticket = wlid_ticket
9
+ @discovery_service_url = "https://#{host_name}/MSCRMServices/2007/Passport/CrmDiscoveryService.asmx"
10
+ retrieve_ticket(get_user_organization)
11
+ end
12
+
13
+ private
14
+ class << self
15
+ def execute_discovery_request(request,params='')
16
+ body = "
17
+ <Execute xmlns=\"http://schemas.microsoft.com/crm/2007/CrmDiscoveryService\">
18
+ <Request xsi:type=\"#{request}\">
19
+ #{params}
20
+ <PassportTicket>#{@wlid_ticket}</PassportTicket>
21
+ </Request>
22
+ </Execute>"
23
+ send_request(@discovery_service_url,compose_message(nil,body),
24
+ "http://schemas.microsoft.com/crm/2007/CrmDiscoveryService/Execute")
25
+ end
26
+
27
+ # Retrieve a list of organizations that the logged on user is a member of
28
+ # and select unique name of the first one
29
+ # TODO: do we need to handle case when user is member of more then one org?
30
+ def get_user_organization
31
+ doc = execute_discovery_request('RetrieveOrganizationsRequest')
32
+ select_node_text(doc,'//cds:OrganizationName[1]')
33
+ end
34
+
35
+ # Retrieve the Crm Service Url, Crm Ticket, Crm Ticket expiration date/time, and Unique User Organization Name
36
+ def retrieve_ticket(user_organization)
37
+ doc = execute_discovery_request('RetrieveCrmTicketRequest',"<OrganizationName>#{user_organization}</OrganizationName>")
38
+ crm_ticket = select_node_text(doc,'//cds:CrmTicket')
39
+ crm_ticket_expires = DateTime.parse(select_node_text(doc,'//cds:ExpirationDate'))
40
+ crm_service_url = select_node_text(doc,'//cds:CrmServiceUrl')
41
+ crm_metadata_service_url = select_node_text(doc, '//cds:CrmMetadataServiceUrl')
42
+ [crm_service_url, crm_metadata_service_url, crm_ticket, crm_ticket_expires, user_organization]
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+ end
51
+