rhoconnect-adapters 1.0.0.beta1
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.
- data/.gitignore +4 -0
- data/CHANGELOG +4 -0
- data/Gemfile +18 -0
- data/README.md +239 -0
- data/Rakefile +31 -0
- data/bin/rhoconnect-adapters +35 -0
- data/generators/crm/templates/application/application.rb +34 -0
- data/generators/crm/templates/source/source_adapter.rb +10 -0
- data/generators/crm/templates/source/source_spec.rb +25 -0
- data/generators/crm/templates/spec/spec_helper.rb +64 -0
- data/generators/crm/vendor/ms_dynamics/adapter.rb +301 -0
- data/generators/crm/vendor/ms_dynamics/application.rb +56 -0
- data/generators/crm/vendor/ms_dynamics/lib/crm_metadata_service.rb +43 -0
- data/generators/crm/vendor/ms_dynamics/lib/crm_service.rb +141 -0
- data/generators/crm/vendor/ms_dynamics/lib/discovery_service.rb +51 -0
- data/generators/crm/vendor/ms_dynamics/lib/wlid_service.rb +159 -0
- data/generators/crm/vendor/ms_dynamics/ms_dynamics.rb +45 -0
- data/generators/crm/vendor/ms_dynamics/settings/Account.yml +46 -0
- data/generators/crm/vendor/ms_dynamics/settings/Contact.yml +40 -0
- data/generators/crm/vendor/ms_dynamics/settings/GenericObject.yml +18 -0
- data/generators/crm/vendor/ms_dynamics/settings/Lead.yml +53 -0
- data/generators/crm/vendor/ms_dynamics/settings/Opportunity.yml +41 -0
- data/generators/crm/vendor/ms_dynamics/settings/settings.yml +9 -0
- data/generators/crm/vendor/ms_dynamics/spec/application_spec.rb +23 -0
- data/generators/crm/vendor/ms_dynamics/spec/sources/account_spec.rb +49 -0
- data/generators/crm/vendor/ms_dynamics/spec/sources/contact_spec.rb +49 -0
- data/generators/crm/vendor/ms_dynamics/spec/sources/lead_spec.rb +49 -0
- data/generators/crm/vendor/ms_dynamics/spec/sources/opportunity_spec.rb +62 -0
- data/generators/crm/vendor/ms_dynamics/spec/spec_helper.rb +78 -0
- data/generators/crm/vendor/ms_dynamics/spec_data/Account.yml +6 -0
- data/generators/crm/vendor/ms_dynamics/spec_data/Contact.yml +7 -0
- data/generators/crm/vendor/ms_dynamics/spec_data/GenericObject.yml +3 -0
- data/generators/crm/vendor/ms_dynamics/spec_data/Lead.yml +12 -0
- data/generators/crm/vendor/ms_dynamics/spec_data/Opportunity.yml +6 -0
- data/generators/crm/vendor/ms_dynamics/templates.rb +57 -0
- data/generators/crm/vendor/oracle_on_demand/adapter.rb +421 -0
- data/generators/crm/vendor/oracle_on_demand/application.rb +64 -0
- data/generators/crm/vendor/oracle_on_demand/settings/Account.yml +91 -0
- data/generators/crm/vendor/oracle_on_demand/settings/Contact.yml +54 -0
- data/generators/crm/vendor/oracle_on_demand/settings/GenericObject.yml +21 -0
- data/generators/crm/vendor/oracle_on_demand/settings/Lead.yml +72 -0
- data/generators/crm/vendor/oracle_on_demand/settings/Opportunity.yml +69 -0
- data/generators/crm/vendor/oracle_on_demand/settings/settings.yml +8 -0
- data/generators/crm/vendor/oracle_on_demand/spec/application_spec.rb +14 -0
- data/generators/crm/vendor/oracle_on_demand/spec/sources/account_spec.rb +50 -0
- data/generators/crm/vendor/oracle_on_demand/spec/sources/contact_spec.rb +50 -0
- data/generators/crm/vendor/oracle_on_demand/spec/sources/lead_spec.rb +51 -0
- data/generators/crm/vendor/oracle_on_demand/spec/sources/opportunity_spec.rb +51 -0
- data/generators/crm/vendor/oracle_on_demand/spec_data/Account.yml +8 -0
- data/generators/crm/vendor/oracle_on_demand/spec_data/Contact.yml +8 -0
- data/generators/crm/vendor/oracle_on_demand/spec_data/GenericObject.yml +4 -0
- data/generators/crm/vendor/oracle_on_demand/spec_data/Lead.yml +14 -0
- data/generators/crm/vendor/oracle_on_demand/spec_data/Opportunity.yml +6 -0
- data/generators/crm/vendor/oracle_on_demand/templates.rb +52 -0
- data/generators/crm/vendor/salesforce/adapter.rb +315 -0
- data/generators/crm/vendor/salesforce/application.rb +80 -0
- data/generators/crm/vendor/salesforce/settings/Account.yml +53 -0
- data/generators/crm/vendor/salesforce/settings/Contact.yml +61 -0
- data/generators/crm/vendor/salesforce/settings/GenericObject.yml +13 -0
- data/generators/crm/vendor/salesforce/settings/Lead.yml +73 -0
- data/generators/crm/vendor/salesforce/settings/Opportunity.yml +48 -0
- data/generators/crm/vendor/salesforce/settings/settings.yml +6 -0
- data/generators/crm/vendor/salesforce/spec/application_spec.rb +14 -0
- data/generators/crm/vendor/salesforce/spec/sources/account_spec.rb +50 -0
- data/generators/crm/vendor/salesforce/spec/sources/contact_spec.rb +50 -0
- data/generators/crm/vendor/salesforce/spec/sources/lead_spec.rb +51 -0
- data/generators/crm/vendor/salesforce/spec/sources/opportunity_spec.rb +51 -0
- data/generators/crm/vendor/salesforce/spec_data/Account.yml +14 -0
- data/generators/crm/vendor/salesforce/spec_data/Contact.yml +8 -0
- data/generators/crm/vendor/salesforce/spec_data/GenericObject.yml +3 -0
- data/generators/crm/vendor/salesforce/spec_data/Lead.yml +10 -0
- data/generators/crm/vendor/salesforce/spec_data/Opportunity.yml +10 -0
- data/generators/crm/vendor/salesforce/templates.rb +45 -0
- data/generators/crm/vendor/sugar/adapter.rb +291 -0
- data/generators/crm/vendor/sugar/application.rb +50 -0
- data/generators/crm/vendor/sugar/settings/Account.yml +49 -0
- data/generators/crm/vendor/sugar/settings/Contact.yml +62 -0
- data/generators/crm/vendor/sugar/settings/GenericObject.yml +12 -0
- data/generators/crm/vendor/sugar/settings/Lead.yml +76 -0
- data/generators/crm/vendor/sugar/settings/Opportunity.yml +49 -0
- data/generators/crm/vendor/sugar/settings/settings.yml +9 -0
- data/generators/crm/vendor/sugar/spec/application_spec.rb +25 -0
- data/generators/crm/vendor/sugar/spec/sources/account_spec.rb +53 -0
- data/generators/crm/vendor/sugar/spec/sources/contact_spec.rb +53 -0
- data/generators/crm/vendor/sugar/spec/sources/lead_spec.rb +54 -0
- data/generators/crm/vendor/sugar/spec/sources/opportunity_spec.rb +54 -0
- data/generators/crm/vendor/sugar/spec_data/Account.yml +13 -0
- data/generators/crm/vendor/sugar/spec_data/Contact.yml +8 -0
- data/generators/crm/vendor/sugar/spec_data/GenericObject.yml +3 -0
- data/generators/crm/vendor/sugar/spec_data/Lead.yml +16 -0
- data/generators/crm/vendor/sugar/spec_data/Opportunity.yml +10 -0
- data/generators/crm/vendor/sugar/sugar.rb +33 -0
- data/generators/crm/vendor/sugar/templates.rb +58 -0
- data/generators/rhoconnect-adapters.rb +217 -0
- data/lib/rhoconnect-adapters/crm/crm.rb +31 -0
- data/lib/rhoconnect-adapters/soap_service.rb +70 -0
- data/lib/rhoconnect-adapters/version.rb +3 -0
- data/lib/rhoconnect-adapters.rb +2 -0
- data/rhoconnect-adapters.gemspec +36 -0
- data/spec/apps/ms_dynamics_spec.rb +19 -0
- data/spec/apps/oracle_on_demand_spec.rb +20 -0
- data/spec/apps/salesforce_spec.rb +18 -0
- data/spec/apps/sugar_spec.rb +18 -0
- data/spec/generator/generator_spec.rb +113 -0
- data/spec/spec_helper.rb +57 -0
- metadata +288 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
|
|
3
|
+
# Set environment to test
|
|
4
|
+
ENV['RHO_ENV'] = 'test'
|
|
5
|
+
ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
|
6
|
+
|
|
7
|
+
require 'bundler'
|
|
8
|
+
Bundler.require(:default, ENV['RHO_ENV'].to_sym)
|
|
9
|
+
|
|
10
|
+
# Try to load vendor-ed rhoconnect, otherwise load the gem
|
|
11
|
+
begin
|
|
12
|
+
require 'vendor/rhoconnect/lib/rhoconnect'
|
|
13
|
+
rescue LoadError
|
|
14
|
+
require 'rhoconnect'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
$:.unshift File.join(File.dirname(__FILE__), "..") # FIXME:
|
|
18
|
+
# Load our rhoconnect application
|
|
19
|
+
require 'application'
|
|
20
|
+
include Rhoconnect
|
|
21
|
+
|
|
22
|
+
require 'rhoconnect/test_methods'
|
|
23
|
+
|
|
24
|
+
# Monkey patch to fix the following issue:
|
|
25
|
+
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.5.1/lib/rspec/core/shared_example_group.rb:45:
|
|
26
|
+
# in `ensure_shared_example_group_name_not_taken': Shared example group '...' already exists (ArgumentError)
|
|
27
|
+
module RSpec
|
|
28
|
+
module Core
|
|
29
|
+
module SharedExampleGroup
|
|
30
|
+
private
|
|
31
|
+
def ensure_shared_example_group_name_not_taken(name)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module TestHelpers
|
|
38
|
+
class << self
|
|
39
|
+
@created_records = {}
|
|
40
|
+
attr_accessor :created_records
|
|
41
|
+
|
|
42
|
+
@already_authenticated = false
|
|
43
|
+
attr_accessor :already_authenticated
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
shared_examples_for "SpecHelper" do
|
|
48
|
+
include Rhoconnect::TestMethods
|
|
49
|
+
|
|
50
|
+
def load_credentials(backend)
|
|
51
|
+
file = YAML.load_file(File.join(ROOT_PATH,'..','rhoconnect-adapters-test',"#{Rhoconnect.under_score(backend)}.yml"))
|
|
52
|
+
return file.nil? ? {} : file
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
before(:all) do
|
|
56
|
+
credentials = load_credentials(Application.backend)
|
|
57
|
+
@test_user = "#{credentials[:test_user]}"
|
|
58
|
+
@test_password = "#{credentials[:test_password]}"
|
|
59
|
+
puts "Specify test user before running these specs" unless @test_user.length > 0
|
|
60
|
+
puts "Specify test user password before running these specs" unless @test_password.length > 0
|
|
61
|
+
unless TestHelpers.already_authenticated
|
|
62
|
+
Store.db.flushdb
|
|
63
|
+
if @test_user.length > 0 and @test_password.length > 0
|
|
64
|
+
puts "Performing authentication with #{Application.backend} CRM instance for the user [#{@test_user}]"
|
|
65
|
+
TestHelpers.already_authenticated = Application.authenticate(@test_user,@test_password)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
before(:each) do
|
|
71
|
+
# preserving auth info
|
|
72
|
+
auth_info = RhoconnectAdapters::CRM::MsDynamics.load_auth_info(@test_user)
|
|
73
|
+
Store.db.flushdb
|
|
74
|
+
Application.initializer(ROOT_PATH)
|
|
75
|
+
# restoring auth info in the DB
|
|
76
|
+
RhoconnectAdapters::CRM::MsDynamics.save_auth_info(@test_user,auth_info) unless auth_info.nil?
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Lead:
|
|
2
|
+
firstname: John
|
|
3
|
+
lastname: Smith
|
|
4
|
+
mobilephone: (555)111-1111
|
|
5
|
+
emailaddress1: john.smith@example.com
|
|
6
|
+
companyname: ABC Company
|
|
7
|
+
jobtitle: Sales Assistant
|
|
8
|
+
estimatedvalue: 40000
|
|
9
|
+
estimatedclosedate: 5/15/2011
|
|
10
|
+
address1_country: USA
|
|
11
|
+
address1_city: San Francisco
|
|
12
|
+
address1_line1: 111 Market St.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# these are MsDynamics-specific Templater::Generator templates
|
|
2
|
+
module RhoconnectAdapters
|
|
3
|
+
module CRM
|
|
4
|
+
module MsDynamics
|
|
5
|
+
class << self
|
|
6
|
+
def configure_gemfile
|
|
7
|
+
# put all specific dependencies here
|
|
8
|
+
# in the form of hash {'gem' => 'version'}
|
|
9
|
+
{}
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
RhoconnectAdapters::CRMAppGenerator.add_vendor_templates :directory, :msdynamics_lib_files do |dir,name,crm|
|
|
17
|
+
dir.source = File.join('..','..','vendor','ms_dynamics','lib')
|
|
18
|
+
dir.destination = File.join("#{name}", 'vendor','ms_dynamics','lib')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
RhoconnectAdapters::CRMAppGenerator.add_vendor_templates :file, :ms_dynamics_main_require do |file,name,crm|
|
|
22
|
+
file.source = File.join('..','..','vendor','ms_dynamics','ms_dynamics.rb')
|
|
23
|
+
file.destination = File.join("#{name}", 'vendor','ms_dynamics','ms_dynamics.rb')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
RhoconnectAdapters::CRMAppGenerator.add_vendor_templates :file, :settings_yml do |file,name,crm|
|
|
27
|
+
file.source = File.join('..','..','vendor','ms_dynamics','settings','settings.yml')
|
|
28
|
+
file.destination = File.join("#{name}", 'vendor','ms_dynamics','settings','settings.yml')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
RhoconnectAdapters::CRMAppGenerator.add_vendor_templates :file, :application_spec do |file,name,crm|
|
|
32
|
+
file.source = File.join('..','..','vendor','ms_dynamics','spec','application_spec.rb')
|
|
33
|
+
file.destination = File.join("#{name}", 'spec','application_spec.rb')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
RhoconnectAdapters::CRMSourceGenerator.add_vendor_templates :file, :object_yml do |file,name,crm|
|
|
37
|
+
source_name = name.gsub('-', '_').camel_case
|
|
38
|
+
source_filename = File.join('..','..','vendor','ms_dynamics','settings',"#{source_name}.yml")
|
|
39
|
+
if File.exists? File.join(CRMSourceGenerator.source_root, source_filename)
|
|
40
|
+
file.source = source_filename
|
|
41
|
+
else
|
|
42
|
+
file.source = File.join('..','..','vendor','ms_dynamics','settings',"GenericObject.yml")
|
|
43
|
+
end
|
|
44
|
+
file.destination = File.join('vendor','ms_dynamics','settings', "#{source_name}.yml")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
RhoconnectAdapters::CRMSourceGenerator.add_vendor_templates :template, :spec_data do |template,name,crm|
|
|
48
|
+
source_name = name.gsub('-', '_').camel_case
|
|
49
|
+
source_filename = File.join('..','..','vendor','ms_dynamics','spec_data',"#{source_name}.yml")
|
|
50
|
+
if File.exists? File.join(CRMSourceGenerator.source_root, source_filename)
|
|
51
|
+
template.source = source_filename
|
|
52
|
+
else
|
|
53
|
+
template.source = File.join('..','..','vendor','ms_dynamics','spec_data',"GenericObject.yml")
|
|
54
|
+
end
|
|
55
|
+
template.destination = File.join('vendor','ms_dynamics','spec_data', "#{source_name}.yml")
|
|
56
|
+
end
|
|
57
|
+
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
require 'rhoconnect-adapters'
|
|
2
|
+
require 'rhoconnect-adapters/soap_service'
|
|
3
|
+
require 'active_support/inflector'
|
|
4
|
+
|
|
5
|
+
module RhoconnectAdapters
|
|
6
|
+
module CRM
|
|
7
|
+
module OracleOnDemand
|
|
8
|
+
RhoconnectAdapters::SoapService.node_namespaces.merge!({'s' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
|
9
|
+
'plns' => 'urn:crmondemand/ws/picklist/',
|
|
10
|
+
'pldoc' => 'urn:/crmondemand/xml/picklist'});
|
|
11
|
+
RhoconnectAdapters::SoapService.envelope_namespaces += <<-DESC
|
|
12
|
+
xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"
|
|
13
|
+
DESC
|
|
14
|
+
|
|
15
|
+
class Adapter < SourceAdapter
|
|
16
|
+
@picklist_namespaces = RhoconnectAdapters::SoapService.envelope_namespaces + "\nxmlns:wsdl=\"urn:crmondemand/ws/picklist/\""
|
|
17
|
+
attr_accessor :crm_object
|
|
18
|
+
attr_accessor :crm_object_namespaces
|
|
19
|
+
attr_accessor :fields
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
attr_accessor :picklist_namespaces
|
|
23
|
+
|
|
24
|
+
def get_columns(fields)
|
|
25
|
+
columns = ""
|
|
26
|
+
fields.each do |key,val|
|
|
27
|
+
columns += "<wsdl:#{key}></wsdl:#{key}>"
|
|
28
|
+
end
|
|
29
|
+
columns
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_columns_values(fields)
|
|
33
|
+
columns = ""
|
|
34
|
+
fields.each do |key,val|
|
|
35
|
+
if not val
|
|
36
|
+
next
|
|
37
|
+
end
|
|
38
|
+
columns += "<wsdl:#{key}>#{val}</wsdl:#{key}>"
|
|
39
|
+
end
|
|
40
|
+
columns
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(source)
|
|
45
|
+
super(source)
|
|
46
|
+
@fields = {}
|
|
47
|
+
@crm_object = self.class.name
|
|
48
|
+
@title_fields = ['Id']
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def configure_fields
|
|
52
|
+
# this is going to be used in XPath searches
|
|
53
|
+
RhoconnectAdapters::SoapService.node_namespaces.merge!({"#{crm_object}doc" => "urn:/crmondemand/xml/#{crm_object}/Data"});
|
|
54
|
+
|
|
55
|
+
# this is going to be passed in SOAP requests
|
|
56
|
+
@crm_object_namespaces = RhoconnectAdapters::SoapService.envelope_namespaces
|
|
57
|
+
@crm_object_namespaces += "\nxmlns:wsdl=\"urn:crmondemand/ws/ecbs/#{crm_object.downcase}/\""
|
|
58
|
+
|
|
59
|
+
# initialize fields map
|
|
60
|
+
@fields = get_object_settings['Query_Fields']
|
|
61
|
+
|
|
62
|
+
@field_picklists = {}
|
|
63
|
+
static_picklists = get_object_settings['StaticPicklist']
|
|
64
|
+
if static_picklists != nil
|
|
65
|
+
static_picklists.each do |element_name, values|
|
|
66
|
+
@field_picklists[element_name] = values
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@object_fields = get_object_settings['ObjectFields']
|
|
71
|
+
@object_fields = {} if @object_fields == nil
|
|
72
|
+
|
|
73
|
+
# title fields are used in metadata to show
|
|
74
|
+
# records in the list
|
|
75
|
+
@title_fields = get_object_settings['TitleFields']
|
|
76
|
+
|
|
77
|
+
@fields
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def get_object_settings
|
|
81
|
+
return @object_settings if @object_settings
|
|
82
|
+
begin
|
|
83
|
+
@object_settings = RhoconnectAdapters::CRM::Field.load_file(File.join(ROOT_PATH,'vendor','oracle_on_demand','settings',"#{crm_object}.yml"))
|
|
84
|
+
rescue Exception => e
|
|
85
|
+
puts "Error opening CRMObjects settings file: #{e}"
|
|
86
|
+
puts e.backtrace.join("\n")
|
|
87
|
+
raise e
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def get_picklists
|
|
92
|
+
begin
|
|
93
|
+
nonquery_fields = get_object_settings['NonQuery_MappingWS_Fields']
|
|
94
|
+
fields.each do |element_name, element_def|
|
|
95
|
+
# use object field only of it has not been excluded
|
|
96
|
+
# explicitly in the object's settings
|
|
97
|
+
next if nonquery_fields.has_key? element_name
|
|
98
|
+
|
|
99
|
+
data_type = element_def['Type']
|
|
100
|
+
# for picklists - get values
|
|
101
|
+
# but only for those that are not
|
|
102
|
+
# already defined statically
|
|
103
|
+
if data_type == 'Picklist' and not @field_picklists.has_key?(element_name)
|
|
104
|
+
@field_picklists[element_name] = get_picklist(element_name)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
rescue RestClient::Exception => e
|
|
108
|
+
raise e
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def get_picklist(element_name)
|
|
113
|
+
# check if we already have it in Store
|
|
114
|
+
picklist = Store.get_data("#{crm_object}:#{element_name}_picklist",Array)
|
|
115
|
+
return picklist if picklist.size != 0
|
|
116
|
+
|
|
117
|
+
password = Store.get_value("#{current_user.login}:password")
|
|
118
|
+
wsse = RhoconnectAdapters::SoapService.compose_wsse_header(current_user.login, password)
|
|
119
|
+
body = "<wsdl:PicklistWS_GetPicklistValues_Input>
|
|
120
|
+
<wsdl:RecordType>#{crm_object}</wsdl:RecordType>
|
|
121
|
+
<wsdl:FieldName>#{element_name}</wsdl:FieldName>
|
|
122
|
+
</wsdl:PicklistWS_GetPicklistValues_Input>"
|
|
123
|
+
req = RhoconnectAdapters::SoapService.compose_message(wsse, body, Adapter.picklist_namespaces)
|
|
124
|
+
|
|
125
|
+
field_values = []
|
|
126
|
+
response = nil
|
|
127
|
+
begin
|
|
128
|
+
response = RhoconnectAdapters::SoapService.send_request_raw("#{@endpoint_url}/GetPicklistValues",
|
|
129
|
+
req,
|
|
130
|
+
"\"document/urn:crmondemand/ws/picklist/:GetPicklistValues\"",
|
|
131
|
+
@session_cookie);
|
|
132
|
+
|
|
133
|
+
oracle_rec = RhoconnectAdapters::SoapService.select_node(Nokogiri::XML(response), '//pldoc:PicklistValue')
|
|
134
|
+
oracle_rec.each do |pval|
|
|
135
|
+
disabled = RhoconnectAdapters::SoapService.select_node_text(pval, 'pldoc:Disabled')
|
|
136
|
+
field_values << RhoconnectAdapters::SoapService.select_node_text(pval, 'pldoc:DisplayValue') if not disabled == 'Y'
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
rescue RestClient::Exception => e
|
|
140
|
+
raise e
|
|
141
|
+
end
|
|
142
|
+
# server stateless session id is returned with the response
|
|
143
|
+
@session_cookie = response.cookies
|
|
144
|
+
Store.put_data("#{crm_object}:#{element_name}_picklist", field_values)
|
|
145
|
+
field_values
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def login
|
|
149
|
+
@endpoint_url = Store.get_value("#{current_user.login}:service_url")
|
|
150
|
+
|
|
151
|
+
# get types information from the GetPicklistValues WS
|
|
152
|
+
get_picklists
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def execute_soap_action(action, soap_body)
|
|
156
|
+
action_prefix = "#{crm_object}" + action
|
|
157
|
+
soapaction = "\"document/urn:crmondemand/ws/ecbs/#{crm_object.downcase}/:"
|
|
158
|
+
soapaction += action_prefix + '"'
|
|
159
|
+
|
|
160
|
+
password = Store.get_value("#{current_user.login}:password")
|
|
161
|
+
wsse = RhoconnectAdapters::SoapService.compose_wsse_header(current_user.login, password)
|
|
162
|
+
body = "<wsdl:#{crm_object}#{action}_Input>
|
|
163
|
+
#{soap_body}
|
|
164
|
+
</wsdl:#{crm_object}#{action}_Input>"
|
|
165
|
+
req = RhoconnectAdapters::SoapService.compose_message(wsse, body, crm_object_namespaces)
|
|
166
|
+
|
|
167
|
+
response = nil
|
|
168
|
+
begin
|
|
169
|
+
response = RhoconnectAdapters::SoapService.send_request_raw("#{@endpoint_url}/#{crm_object}",
|
|
170
|
+
req,
|
|
171
|
+
soapaction,
|
|
172
|
+
@session_cookie);
|
|
173
|
+
rescue RestClient::Exception => e
|
|
174
|
+
raise e
|
|
175
|
+
end
|
|
176
|
+
# server stateless session id is returned with the response
|
|
177
|
+
@session_cookie = response.cookies
|
|
178
|
+
|
|
179
|
+
RhoconnectAdapters::SoapService.select_node(Nokogiri::XML(response), "//#{crm_object}doc:ListOf#{crm_object}")[0]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def query(params=nil)
|
|
183
|
+
# TODO: Query your backend data source and assign the records
|
|
184
|
+
# to a nested hash structure called @result. For example:
|
|
185
|
+
# @result = {
|
|
186
|
+
# "1"=>{"name"=>"Acme", "industry"=>"Electronics"},
|
|
187
|
+
# "2"=>{"name"=>"Best", "industry"=>"Software"}
|
|
188
|
+
# }
|
|
189
|
+
@result = {}
|
|
190
|
+
fetch_more = 'true'
|
|
191
|
+
start_row = 0
|
|
192
|
+
begin
|
|
193
|
+
|
|
194
|
+
soap_body = "<wsdl:ListOf#{crm_object} recordcountneeded=\"true\" pagesize=\"100\" startrownum=\"#{start_row.to_s}\">
|
|
195
|
+
<wsdl:#{crm_object} searchspec=\"\">
|
|
196
|
+
#{Adapter.get_columns(fields)}
|
|
197
|
+
</wsdl:#{crm_object}>
|
|
198
|
+
</wsdl:ListOf#{crm_object}>"
|
|
199
|
+
|
|
200
|
+
query_results = execute_soap_action('QueryPage', soap_body)
|
|
201
|
+
fetch_more = query_results['lastpage'] == 'true' ? false : true;
|
|
202
|
+
|
|
203
|
+
query_results.children.each do |record|
|
|
204
|
+
if record.name == "#{crm_object}"
|
|
205
|
+
id_field = RhoconnectAdapters::SoapService.select_node_text(record, "#{crm_object}doc:Id")
|
|
206
|
+
converted_record = {}
|
|
207
|
+
# grab only the allowed fields
|
|
208
|
+
fields.each do |element_name,element_def|
|
|
209
|
+
converted_record[element_name] = RhoconnectAdapters::SoapService.select_node_text(record, "#{crm_object}doc:#{element_name}")
|
|
210
|
+
end
|
|
211
|
+
@result[id_field] = converted_record
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
start_row = @result.size
|
|
215
|
+
end while fetch_more
|
|
216
|
+
@result
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def sync
|
|
220
|
+
# Manipulate @result before it is saved, or save it
|
|
221
|
+
# yourself using the Rhoconnect::Store interface.
|
|
222
|
+
# By default, super is called below which simply saves @result
|
|
223
|
+
super
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def metadata
|
|
227
|
+
# define the metadata
|
|
228
|
+
show_fields = []
|
|
229
|
+
new_fields = []
|
|
230
|
+
edit_fields = []
|
|
231
|
+
model_name = "" + crm_object
|
|
232
|
+
model_name[0] = model_name[0,1].downcase
|
|
233
|
+
record_sym = '@' + "#{model_name}"
|
|
234
|
+
|
|
235
|
+
fields.each do |element_name,element_def|
|
|
236
|
+
next if element_name == 'Id'
|
|
237
|
+
|
|
238
|
+
# 1) - read-only show fields
|
|
239
|
+
field_type = 'labeledvalueli'
|
|
240
|
+
field = {
|
|
241
|
+
:name => "#{model_name}\[#{element_name}\]",
|
|
242
|
+
:label => element_def['Label'],
|
|
243
|
+
:type => field_type,
|
|
244
|
+
:value => "{{#{record_sym}/#{element_name}}}"
|
|
245
|
+
}
|
|
246
|
+
show_fields << field
|
|
247
|
+
|
|
248
|
+
new_field = field.clone
|
|
249
|
+
new_field[:type] = 'labeledinputli'
|
|
250
|
+
new_field.delete(:value)
|
|
251
|
+
case element_def['Type']
|
|
252
|
+
when 'Picklist'
|
|
253
|
+
new_field[:type] = 'select'
|
|
254
|
+
values = []
|
|
255
|
+
# make first element a blanc value
|
|
256
|
+
values[0] = nil
|
|
257
|
+
values.concat @field_picklists[element_name]
|
|
258
|
+
new_field[:values] = values
|
|
259
|
+
new_field[:value] = values[0]
|
|
260
|
+
when 'object'
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
new_fields << new_field if not element_def['Type'] == 'object'
|
|
264
|
+
|
|
265
|
+
edit_field = new_field.clone
|
|
266
|
+
edit_field[:value] = "{{#{record_sym}/#{element_name}}}"
|
|
267
|
+
edit_fields << edit_field
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Show
|
|
271
|
+
show_list = { :name => 'list', :type => 'list', :children => show_fields }
|
|
272
|
+
show_form = {
|
|
273
|
+
:name => "#{crm_object}_show",
|
|
274
|
+
:type => 'show_form',
|
|
275
|
+
:title => "#{crm_object} details",
|
|
276
|
+
:object => "#{crm_object}",
|
|
277
|
+
:model => "#{model_name}",
|
|
278
|
+
:id => "{{#{record_sym}/object}}",
|
|
279
|
+
:children => [show_list]
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# New
|
|
283
|
+
new_list = show_list.clone
|
|
284
|
+
new_list[:children] = new_fields
|
|
285
|
+
new_form = {
|
|
286
|
+
:type => 'new_form',
|
|
287
|
+
:title => "New #{crm_object}",
|
|
288
|
+
:object => "#{crm_object}",
|
|
289
|
+
:model => "#{model_name}",
|
|
290
|
+
:children => [new_list]
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
# Edit
|
|
294
|
+
edit_list = show_list.clone
|
|
295
|
+
edit_list[:children] = edit_fields
|
|
296
|
+
edit_form = {
|
|
297
|
+
:type => 'update_form',
|
|
298
|
+
:title => "Edit #{crm_object}",
|
|
299
|
+
:object => "#{crm_object}",
|
|
300
|
+
:model => "#{model_name}",
|
|
301
|
+
:id => "{{#{record_sym}/object}}",
|
|
302
|
+
:children => [edit_list]
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Index
|
|
306
|
+
title_field_metadata = @title_fields.collect { |field_name | "{{#{field_name.to_s}}} " }.join(' ')
|
|
307
|
+
object_rec = {
|
|
308
|
+
:object => "#{crm_object}",
|
|
309
|
+
:id => "{{object}}",
|
|
310
|
+
:type => 'linkobj',
|
|
311
|
+
:text => "#{title_field_metadata}"
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
index_form = {
|
|
315
|
+
:object => "#{crm_object}",
|
|
316
|
+
:title => "#{crm_object.pluralize}",
|
|
317
|
+
:type => 'index_form',
|
|
318
|
+
:children => [object_rec],
|
|
319
|
+
:repeatable => "{{#{record_sym.pluralize}}}"
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
# return JSON
|
|
323
|
+
{ 'index' => index_form, 'show' => show_form, 'new' => new_form, 'edit' => edit_form }.to_json
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def create(create_hash,blob=nil)
|
|
327
|
+
# TODO: Create a new record in your backend data source
|
|
328
|
+
# If your rhodes rhom object contains image/binary data
|
|
329
|
+
# (has the image_uri attribute), then a blob will be provided
|
|
330
|
+
created_object_id = nil
|
|
331
|
+
request_fields = {}
|
|
332
|
+
fields.each do |element_name, element_def|
|
|
333
|
+
field_value = create_hash[element_name]
|
|
334
|
+
if field_value != nil and element_name != 'Id'
|
|
335
|
+
request_fields[element_name] = field_value
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
soap_body = "<wsdl:ListOf#{crm_object}>
|
|
340
|
+
<wsdl:#{crm_object}>
|
|
341
|
+
#{Adapter.get_columns_values(request_fields)}
|
|
342
|
+
</wsdl:#{crm_object}>
|
|
343
|
+
</wsdl:ListOf#{crm_object}>"
|
|
344
|
+
|
|
345
|
+
begin
|
|
346
|
+
oracle_rec = execute_soap_action('Insert', soap_body)
|
|
347
|
+
created_object_id = RhoconnectAdapters::SoapService.select_node_text(oracle_rec, "//#{crm_object}doc:Id").to_s
|
|
348
|
+
rescue RestClient::Exception => e
|
|
349
|
+
raise e
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# return new object ids
|
|
353
|
+
created_object_id
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def update(update_hash)
|
|
357
|
+
updated_object_id = nil
|
|
358
|
+
request_fields = {}
|
|
359
|
+
fields.each do |element_name,element_def|
|
|
360
|
+
field_value = update_hash[element_name]
|
|
361
|
+
if field_value != nil
|
|
362
|
+
request_fields[element_name] = field_value
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
# check if 'Id' is present
|
|
366
|
+
# it may be available as an 'id'
|
|
367
|
+
if request_fields['Id'] == nil
|
|
368
|
+
request_fields['Id'] = update_hash['id']
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
if request_fields['Id'] == nil
|
|
372
|
+
raise SourceAdapterObjectConflictError.new("'Id' field must be specified for the Update request")
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
soap_body = "<wsdl:ListOf#{crm_object}>
|
|
376
|
+
<wsdl:#{crm_object}>
|
|
377
|
+
#{Adapter.get_columns_values(request_fields)}
|
|
378
|
+
</wsdl:#{crm_object}>
|
|
379
|
+
</wsdl:ListOf#{crm_object}>"
|
|
380
|
+
|
|
381
|
+
begin
|
|
382
|
+
oracle_rec = execute_soap_action('Update', soap_body)
|
|
383
|
+
updated_object_id = RhoconnectAdapters::SoapService.select_node_text(oracle_rec, "#{crm_object}doc:Id")
|
|
384
|
+
rescue RestClient::Exception => e
|
|
385
|
+
raise e
|
|
386
|
+
end
|
|
387
|
+
updated_object_id
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def delete(delete_hash)
|
|
391
|
+
deleted_object_id = delete_hash['Id'] || delete_hash['id']
|
|
392
|
+
|
|
393
|
+
if deleted_object_id == nil
|
|
394
|
+
raise SourceAdapterObjectConflictError.new("'Id' field must be specified for the Delete request")
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
request_fields = {}
|
|
398
|
+
request_fields['Id'] = deleted_object_id
|
|
399
|
+
|
|
400
|
+
soap_body = "<wsdl:ListOf#{crm_object}>
|
|
401
|
+
<wsdl:#{crm_object}>
|
|
402
|
+
#{Adapter.get_columns_values(request_fields)}
|
|
403
|
+
</wsdl:#{crm_object}>
|
|
404
|
+
</wsdl:ListOf#{crm_object}>"
|
|
405
|
+
|
|
406
|
+
begin
|
|
407
|
+
execute_soap_action('Delete', soap_body)
|
|
408
|
+
rescue RestClient::Exception => e
|
|
409
|
+
raise e
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
deleted_object_id
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def logoff
|
|
416
|
+
# logoff if necessary
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'rhoconnect-adapters'
|
|
2
|
+
require 'rest-client'
|
|
3
|
+
|
|
4
|
+
module RhoconnectAdapters
|
|
5
|
+
module CRM
|
|
6
|
+
module OracleOnDemand
|
|
7
|
+
class Application < Rhoconnect::Base
|
|
8
|
+
class << self
|
|
9
|
+
def authenticate(username,password,session)
|
|
10
|
+
begin
|
|
11
|
+
oraclecrm_url = Application.get_settings[:oraclecrm_service_url]
|
|
12
|
+
request_url = oraclecrm_url + "?command=" + 'login'
|
|
13
|
+
|
|
14
|
+
# here we just verifying the credetials
|
|
15
|
+
# by logging in and immediately logging out
|
|
16
|
+
in_headers = {
|
|
17
|
+
"UserName" => username,
|
|
18
|
+
"Password" => password
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
RestClient.get(request_url, in_headers) do |response,request,result,&block|
|
|
22
|
+
case response.code
|
|
23
|
+
when 200
|
|
24
|
+
# store password to be used by SourceAdaptors
|
|
25
|
+
Store.put_value("#{username}:password", password)
|
|
26
|
+
Store.put_value("#{username}:service_url", oraclecrm_url)
|
|
27
|
+
|
|
28
|
+
# since we established the session only
|
|
29
|
+
# to verify the credentials - close the session here
|
|
30
|
+
request_url = "#{oraclecrm_url}" + '?command=' + 'logoff'
|
|
31
|
+
in_headers = { "Cookie" => response.headers[:set_cookie] };
|
|
32
|
+
RestClient.get(request_url, in_headers)
|
|
33
|
+
else
|
|
34
|
+
raise "LOGIN/PASSWORD ERROR : #{response.code} : #{response}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
rescue Exception => e
|
|
38
|
+
warn "Can't authenticate user #{username}: " + e.inspect
|
|
39
|
+
return false
|
|
40
|
+
end
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
def get_settings
|
|
44
|
+
return @settings if @settings
|
|
45
|
+
begin
|
|
46
|
+
file = YAML.load_file(File.join(ROOT_PATH,'settings','settings.yml'))
|
|
47
|
+
env = (ENV['RHO_ENV'] || :development).to_sym
|
|
48
|
+
@settings = file[env]
|
|
49
|
+
|
|
50
|
+
# vendor-specific settings
|
|
51
|
+
file = YAML.load_file(File.join(ROOT_PATH,'vendor','oracle_on_demand','settings','settings.yml'))
|
|
52
|
+
@settings.merge!(file[env])
|
|
53
|
+
rescue Exception => e
|
|
54
|
+
puts "Error opening settings file: #{e}"
|
|
55
|
+
puts e.backtrace.join("\n")
|
|
56
|
+
raise e
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|