connectwise_sdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f97ff9137957a443af0184ff9f5be0864b3abd0f
4
+ data.tar.gz: 7348114bd346b8b314659b5006c3cd9117c61e73
5
+ SHA512:
6
+ metadata.gz: a4c762a2424ccfd108bfcd55ccfb09be095ad2b9ec6abdb384711c36062dc87a045dc74949bbc3a6d67dcb9c406d97100b11000a8314febdae797702ad239a12
7
+ data.tar.gz: e94651ab74d558d127b9de456fe3bf794bf4c1d3b32078008f9f291f7e6371c6dd2e40e0e74504df08a9e3fb045d8faa689d011bfbe4353563b97c0dcbc3bbc2
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .ruby-version
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ spec/credentials.yml
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in connectwise_sdk.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Emery A. Miller
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ # ConnectwiseSdk
2
+
3
+ An SDK allowing integration into Connectwise
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'connectwise_sdk'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install connectwise_sdk
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ conn = Connectwise::Connection.new host: 'host.domain.com', company_name: 'company', integrator_login_id: 'username', integrator_password: 'password'
23
+ contact = Connectwise::Contact.new(conn, first_name: 'Malcom', last_name: 'Reynolds', email: 'captain@serenity.com')
24
+ contact.save # => creates a new contact and updates itself with the fields set by connectwise
25
+ contact.id # => 432
26
+
27
+ # Retrieve a list of members
28
+ member = Connectwise::Member.where(conn, email_address: 'captain@serenity.com')
29
+ ```
30
+
31
+ ### Using the low level connection object directly
32
+
33
+ In the event that a certain api you need to access isn't fully supported by the sdk yet, or if you simply want more direct access to the api, you can use the lower level call method on the connection object.
34
+
35
+ ```ruby
36
+ conn = Connectwise::Connection.new host: 'host.domain.com', company_name: 'company', integrator_login_id: 'username', integrator_password: 'password'
37
+ conn.call :contact, :find_contacts, conditions: 'EmailAddress like "test@test.com"'
38
+ ```
39
+
40
+ - The first parameter is the api you wish to use. In this case the `contactApi`.
41
+ - The second parameter is the specific api call you wish to use (from the Connectwise Api documentation)
42
+ - The third paramater is the data you wish to send the api
43
+
44
+ The connection object will add the credential fields to your api call automatically, and convert the data hash into a SOAP request. Note that because there is some inconsistency in the naming / case used by the api, all data fields must be passed as specified by the api and not in standard Ruby snake case. For example:
45
+
46
+ ```ruby
47
+ conn.call :contact, :add_or_update_contact, {contact: {
48
+ FirstName: contact.first_name,
49
+ LastName: contact.last_name,
50
+ Email: contact.email,
51
+ Phone: contact.phone,
52
+ }}
53
+ ```
54
+
55
+ Note how `contact` is lower case, while `FirstName` and the other fields are camel case with a leading capital. The Connectwise api requires that contact be lower case and the others camel case.
56
+
57
+ ## Current progress and TODOs
58
+
59
+ Currently only the `Member.where` method, and the low level `Connection.call` method are working.
60
+
61
+ 1. Complete Contact class
62
+ 2. Company class
63
+ 3. Opportunity class
64
+ 4. Ticket class
65
+ 5. Remaining api
66
+
67
+ ## Contributing
68
+
69
+ 1. Fork it
70
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
71
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
72
+ 4. Push to the branch (`git push origin my-new-feature`)
73
+ 5. Create new Pull Request
74
+
75
+ ### Adding support for other Connectwise Classes
76
+
77
+ There is a `Connectwise::Model` module that incorporates the core of what it is to be
78
+ connectwise model. Every Model should include this class.
79
+
80
+ Then it's a matter of figuring out the following for each class:
81
+ - What fields are returned from a find call
82
+ - What fields are returned from a create call (sometimes this differs from the find call)
83
+ - Adding these fields to the attr_accessible list to define what parameters are valid
84
+ - Handling the basic CRUD operations by using the connection object
85
+
86
+ Some issues that need to be resolved:
87
+ - How best to handle nested data structures (A contact has an email address list, a phone number list, etc.)
88
+ - How best to handle nested objects (A company has a contact)
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'connectwise/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "connectwise_sdk"
8
+ spec.version = Connectwise::VERSION
9
+ spec.authors = ["Emery A. Miller"]
10
+ spec.email = ["emery.miller@easyofficephone.com"]
11
+ spec.description = %q{This Gem is an SDK for accessing Connectwise}
12
+ spec.summary = %q{A Connectwise SDK for Ruby}
13
+ spec.homepage = "http://github.com/EasyOfficePhone/connectwise-sdk"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+
25
+ spec.add_runtime_dependency "savon", "~> 2.0"
26
+ end
@@ -0,0 +1,5 @@
1
+ module Connectwise
2
+ class Company
3
+ include Model
4
+ end
5
+ end
@@ -0,0 +1,70 @@
1
+ module Connectwise
2
+ class ConnectionError < StandardError; end
3
+ class UnknownHostError < ConnectionError; end
4
+ class UnknownCompanyError < ConnectionError; end
5
+ class BadCredentialsError < ConnectionError; end
6
+
7
+ class Connection
8
+ attr_reader :host, :custom_api_mapping
9
+ attr_accessor :log
10
+
11
+ def initialize(host: '', company_name: '', integrator_login_id: '', integrator_password: '', custom_api_mapping: {})
12
+ @custom_api_mapping = custom_api_mapping
13
+ @host = host
14
+ @credentials = {CompanyId: company_name, IntegratorLoginId: integrator_login_id, IntegratorPassword: integrator_password}
15
+ end
16
+
17
+ def call(api, action, message, options: {}, &err_handler)
18
+ err_handler ||= proc {|err| raise err}
19
+
20
+ client = Savon.client(default_options.merge(options).merge(wsdl: wsdl_url(api)))
21
+ response = client.call action, message: credentials.merge(message)
22
+ response.body["#{action}_response".to_sym]["#{action}_result".to_sym]
23
+ rescue Savon::SOAPFault, Savon::UnknownOperationError, SocketError, URI::InvalidURIError => err
24
+ begin
25
+ case err.message
26
+ when /username or password is incorrect/i
27
+ raise BadCredentialsError.new 'Login or Password are incorrect'
28
+ when /hostname nor servname/i
29
+ raise UnknownHostError.new "The host (#{@host}) is not reachable"
30
+ when /cannot find company.*connectwise config/i
31
+ raise UnknownCompanyError.new "The company (#{@credentials[:CompanyId]}) cannot be found by Connectwise"
32
+ else
33
+ raise ConnectionError.new "An unknown error occurred when contacting Connectwise : \n#{err.message}"
34
+ end
35
+ rescue BadCredentialsError, UnknownHostError, UnknownCompanyError, ConnectionError => err
36
+ err_handler.call(err)
37
+ end
38
+ end
39
+
40
+ private
41
+ def default_options
42
+ defaults = { convert_request_keys_to: :none, ssl_verify_mode: :none }
43
+ defaults = defaults.merge({ log: true, pretty_print_xml: true }) if @log
44
+ defaults
45
+ end
46
+
47
+ def wsdl_url(api_name)
48
+ "https://#{host}/v4_6_release/apis/1.5/#{api(api_name)}.asmx?wsdl"
49
+ end
50
+
51
+ def credentials
52
+ {credentials: @credentials}
53
+ end
54
+
55
+ def api(desired_api)
56
+ api = api_mapping.fetch(desired_api) {desired_api}.to_s
57
+ api.extend(Connectwise::Extensions::String)
58
+ api =~ /Api\z/ ? api : "#{api.camelize}Api"
59
+ end
60
+
61
+ def api_mapping
62
+ {
63
+ billing: :generic_billing_transaction,
64
+ config: :configuration,
65
+ device: :managed_device,
66
+ ticket: :service_ticket,
67
+ }.merge(custom_api_mapping)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,194 @@
1
+ module Connectwise
2
+ class ConnectionError < StandardError; end
3
+ class UnknownHostError < ConnectionError; end
4
+ class UnknownCompanyError < ConnectionError; end
5
+ class BadCredentialsError < ConnectionError; end
6
+
7
+ class Connection
8
+ attr_reader :host, :custom_api_mapping
9
+ attr_accessor :log
10
+
11
+ def initialize(host: '', company_name: '', integrator_login_id: '', integrator_password: '', custom_api_mapping: {})
12
+ @custom_api_mapping = custom_api_mapping
13
+ @host = host
14
+ @credentials = {CompanyId: company_name, IntegratorLoginId: integrator_login_id, IntegratorPassword: integrator_password}
15
+ end
16
+
17
+ def call(api, action, message, options: {}, &err_handler)
18
+ err_handler ||= proc {|err| raise err}
19
+
20
+ client = Savon.client(default_options.merge(options).merge(wsdl: wsdl_url(api)))
21
+ response = client.call action, message: credentials.merge(message)
22
+ response.body["#{action}_response".to_sym]["#{action}_result".to_sym]
23
+ rescue Savon::SOAPFault, Savon::UnknownOperationError, SocketError, URI::InvalidURIError => err
24
+ begin
25
+ case err.message
26
+ when /username or password is incorrect/i
27
+ raise BadCredentialsError.new 'Login or Password are incorrect'
28
+ when /hostname nor servname/i
29
+ raise UnknownHostError.new "The host (#{@host}) is not reachable"
30
+ when /cannot find company.*connectwise config/i
31
+ raise UnknownCompanyError.new "The company (#{@credentials[:CompanyId]}) cannot be found by Connectwise"
32
+ else
33
+ raise ConnectionError.new "An unknown error occurred when contacting Connectwise"
34
+ end
35
+ rescue BadCredentialsError, UnknownHostError, UnknownCompanyError, ConnectionError => err
36
+ err_handler.call(err)
37
+ end
38
+ end
39
+
40
+ private
41
+ def default_options
42
+ defaults = { convert_request_keys_to: :none, ssl_verify_mode: :none }
43
+ defaults = defaults.merge({ log: true, pretty_print_xml: true }) if @log
44
+ defaults
45
+ end
46
+
47
+ def wsdl_url(api_name)
48
+ "https://#{host}/v4_6_release/apis/1.5/#{api(api_name)}.asmx?wsdl"
49
+ end
50
+
51
+ def credentials
52
+ {credentials: @credentials}
53
+ end
54
+
55
+ def api(desired_api)
56
+ api = api_mapping.fetch(desired_api) {desired_api}.to_s
57
+ api =~ /Api\z/ ? api : "#{camelize(api)}Api"
58
+ end
59
+
60
+ def camelize(term)
61
+ string = term.to_s.sub(/^[a-z\d]*/) { $&.capitalize }
62
+ string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
63
+ end
64
+
65
+ def api_mapping
66
+ {
67
+ billing: :generic_billing_transaction,
68
+ config: :configuration,
69
+ device: :managed_device,
70
+ ticket: :service_ticket,
71
+ }.merge(custom_api_mapping)
72
+ end
73
+ end
74
+
75
+ module Model
76
+ def initialize(**attributes)
77
+ attributes.each do |attr, value|
78
+ public_send "#{attr}=", value
79
+ end
80
+ end
81
+ end
82
+
83
+ class Client
84
+ include Model
85
+ attr_accessor :first_name, :last_name, :email_address
86
+ end
87
+
88
+ class Company
89
+ include Model
90
+ attr_accessor :company_name, :url
91
+ end
92
+
93
+ class Opportunity
94
+ include Model
95
+
96
+ end
97
+
98
+ class ServiceTicket
99
+ include Model
100
+
101
+ end
102
+
103
+ class BaseAPI
104
+ attr_reader :connection
105
+ def initialize(connection)
106
+ @connection = connection
107
+ end
108
+
109
+ # Members
110
+ def find_member(user, &err_handler)
111
+ resp = connection.call 'MemberApi', :find_members, {conditions: "EmailAddress like '#{user.email}'"}, &err_handler
112
+ (result = resp[:member_find_result]) ? Array(result) : resp
113
+ end
114
+
115
+ # Contact
116
+ def create_contact(contact, company_id=nil, &err_handler)
117
+ message = {
118
+ FirstName: contact.first_name,
119
+ LastName: contact.last_name,
120
+ Email: contact.email,
121
+ Phone: contact.phone,
122
+ }
123
+ message = message.merge(CompanyId: company_id) if company_id
124
+ connection.call 'ContactApi', :add_or_update_contact, {contact: message}, &err_handler
125
+ end
126
+
127
+ def delete_contact(contact, &err_handler)
128
+ connection.call 'ContactApi', :delete_contact, {id: contact.id}, &err_handler
129
+ end
130
+
131
+ # Companies
132
+ def find_company(company, &err_handler)
133
+ resp = connection.call 'CompanyApi', :find_companies, { conditions: "CompanyName like '%#{company.name}%' or CompanyID = '#{company.id}'" }, &err_handler
134
+ (result = resp[:company_find_result]) ? Array(result) : resp
135
+ end
136
+
137
+ def create_company(company, &err_handler)
138
+ message = {
139
+ Id: 0,
140
+ CompanyName: company.name,
141
+ CompanyID: company.id.to_s,
142
+ WebSite: company.url,
143
+ Status: 'Active',
144
+ }
145
+ connection.call 'CompanyApi', :add_company, {company: message}, &err_handler
146
+ end
147
+
148
+ def delete_company(company, &err_handler)
149
+ connection.call 'CompanyApi', :delete_company, {id: company.id}, &err_handler
150
+ end
151
+
152
+ # Opportunity
153
+ def create_opportunity(opportunity, company_id, contact_id, &err_handler)
154
+ message = {
155
+ Id: 0,
156
+ OpportunityName: "Opportunity from Easyofficephone - #{opportunity.company.name}",
157
+ Company: {CompanyID: company_id},
158
+ Contact: {Id: contact_id},
159
+ Source: 'Easy Office Phone opportunity',
160
+ PrimarySalesRep: opportunity.user.full_name,
161
+ Notes: {
162
+ Note: {
163
+ note_text: opportunity.note,
164
+ }
165
+ },
166
+ }
167
+
168
+ connection.call 'OpportunityApi', :add_opportunity, {opportunity: message}, &err_handler
169
+ end
170
+
171
+ def delete_opportunity(opportunity, &err_handler)
172
+ connection.call 'OpportunityApi', :delete_opportunity, {id: opportunity.id}, &err_handler
173
+ end
174
+
175
+ # Ticket
176
+ #TODO - these find methods are too limited, need to allow proper query
177
+ def find_ticket(ticket, company)
178
+ resp = connection.call 'ServiceTicketApi', :find_service_tickets, {conditions: "CompanyName like '%#{company.name}%' or SRServiceRecID = '#{ticket.id}'"}
179
+ (result = resp[:tickets]) ? Array(result) : resp
180
+ end
181
+
182
+ def create_ticket(ticket, company, &err_handler)
183
+ resp = connection.call 'ServiceTicketApi', :add_service_ticket_via_company_id, {
184
+ serviceTicket: {
185
+ Id: 0,
186
+ CompanyId: company.id,
187
+ Summary: ticket.subject,
188
+ Status: 'N',
189
+ ProblemDescription: ticket.description,
190
+ }
191
+ }, &err_handler
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,56 @@
1
+ module Connectwise
2
+ class Contact
3
+ include Model
4
+ #TODO - email or email_address - Member uses email_address, while here it's email - normalize
5
+ attr_accessor :id, :first_name, :last_name, :company_name, :phone, :email, :type, :relationship, :default_flag, :address_line1, :address_line2, :city, :state, :zip, :country,
6
+ :portal_security_level, :portal_security_caption, :disable_portal_login, :last_update
7
+
8
+ def self.where(connection, **attrs)
9
+ resp = connection.call :contact, :find_contacts, {conditions: attrs_to_query(attrs)}
10
+ Array(resp[:contact_find_result]).map {|attrs| p attrs; cw_find_to_model(connection, attrs) }
11
+ end
12
+
13
+ def save
14
+ #message = message.merge(CompanyId: company_id) if company_id
15
+ attrs = connection.call 'ContactApi', :add_or_update_contact, {contact: to_cw_h}
16
+ p attrs
17
+ self.class.cw_save_to_model(connection, attrs)
18
+ end
19
+
20
+ def destroy
21
+
22
+ end
23
+
24
+ def persisted?
25
+ !!@id
26
+ end
27
+
28
+ private
29
+ def self.cw_find_to_model(conn, attrs)
30
+ id = attrs.delete(:contact_rec_id)
31
+ #TODO - make use of company rec id - either run another query to create it, or find a way to defer until company is asked for
32
+ company_id = attrs.delete(:company_rec_id)
33
+ self.new(conn, id: id, **attrs)
34
+ end
35
+
36
+ def self.cw_save_to_model(conn, attrs)
37
+
38
+ end
39
+
40
+ def create_contact(contact, company_id=nil, &err_handler)
41
+ message = {
42
+ FirstName: contact.first_name,
43
+ LastName: contact.last_name,
44
+ Email: contact.email,
45
+ Phone: contact.phone,
46
+ }
47
+ message = message.merge(CompanyId: company_id) if company_id
48
+ connection.call 'ContactApi', :add_or_update_contact, {contact: message}, &err_handler
49
+ end
50
+
51
+ def delete_contact(contact, &err_handler)
52
+ connection.call 'ContactApi', :delete_contact, {id: contact.id}, &err_handler
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,10 @@
1
+ module Connectwise
2
+ module Extensions
3
+ module String
4
+ def camelize
5
+ string = self.sub(/^[a-z\d]*/) { $&.capitalize }
6
+ string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ module Connectwise
2
+ class Member
3
+ include Model
4
+ attr_accessor :email_address, :first_name, :last_name, :id
5
+
6
+ def self.where(connection, **attrs)
7
+ resp = connection.call :member, :find_members, {conditions: attrs_to_query(attrs)}
8
+ Array(resp[:member_find_result]).map {|attrs| cw_to_model(connection, attrs) }
9
+ end
10
+
11
+ private
12
+ def self.cw_to_model(conn, attrs)
13
+ id = attrs.delete(:member_id)
14
+ self.new(conn, id: id, **attrs)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,45 @@
1
+ module Connectwise
2
+ module Model
3
+ module ClassMethods
4
+ def attrs_to_query(attrs)
5
+ attrs.map do |k,v|
6
+ str = k.to_s
7
+ str.extend(Connectwise::Extensions::String)
8
+ "#{str.camelize} like '#{v}'"
9
+ end.join(' and ')
10
+ end
11
+ end
12
+
13
+ def self.included(klass)
14
+ klass.extend ClassMethods
15
+ end
16
+
17
+ def initialize(connection, **attributes)
18
+ @connection = connection
19
+ attributes.each do |attr, value|
20
+ public_send "#{attr}=", value
21
+ end
22
+ end
23
+
24
+ def persisted?
25
+ false
26
+ end
27
+
28
+ def to_h
29
+ defined_attributes.each_with_object({}) {|name, memo| memo[name] = public_send(name)}
30
+ end
31
+
32
+ def to_cw_h
33
+ defined_attributes.each_with_object({}) {|name, memo| key = name.to_s.extend(Extensions::String); memo[key.camelize] = public_send(name)}
34
+ end
35
+
36
+ def defined_attributes
37
+ instance_vars = instance_variables.map {|name| name.to_s.gsub(/@/, '').to_sym}
38
+ public_methods.select{|method| instance_vars.include?(method) }
39
+ end
40
+ protected
41
+ def connection
42
+ @connection
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module Connectwise
2
+ class Opportunity
3
+ include Model
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Connectwise
2
+ class Ticket
3
+ include Model
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Connectwise
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'savon'
2
+ require "connectwise/version"
3
+ require 'connectwise/extensions'
4
+ require 'connectwise/connection'
5
+ require 'connectwise/model'
6
+ require 'connectwise/member'
7
+ require 'connectwise/contact'
8
+ require 'connectwise/company'
9
+ require 'connectwise/opportunity'
10
+ require 'connectwise/ticket'
11
+
12
+ module Connectwise
13
+ end
@@ -0,0 +1,5 @@
1
+ connectwise_credentials:
2
+ host: 'test.connectwise.com'
3
+ company_name: ''
4
+ integrator_login_id: ''
5
+ integrator_password: ''
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise::Company do
4
+ it 'creates a company' do
5
+ expect(subject.create_company(company)[:id]).not_to be_empty
6
+ end
7
+
8
+ it 'fails to create a company' do
9
+ company.id = nil
10
+ expect {subject.create_company(company)}.to raise_error Connectwise::ConnectionError
11
+ end
12
+
13
+ it 'fails to create company and throws error' do
14
+ company.id = nil
15
+ expect {subject.create_company(company) do |err|
16
+ fail ArgumentError
17
+ end}.to raise_error ArgumentError
18
+ end
19
+
20
+ it 'deletes a company' do
21
+ new_company = subject.create_company(company)
22
+ expect(subject.delete_company(OpenStruct.new(id: new_company[:id]))).to be_nil
23
+ end
24
+
25
+ it 'finds a company' do
26
+ resp = subject.find_company(OpenStruct.new name: 'Blue Sun', id: '6417')
27
+ expect(resp).not_to be_empty
28
+ end
29
+
30
+ it 'creates a company and a contact and connects them' do
31
+ new_company = subject.create_company(company)
32
+ resp = subject.create_contact(contact, new_company[:company_id])
33
+ expect(resp[:company_id]).to eql new_company[:company_id]
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise::Connection do
4
+ let(:credentials) { connectwise_credentials }
5
+ subject { Connectwise::Connection.new(credentials) }
6
+
7
+ describe 'Failures' do
8
+ it 'raises an UnknownHostError' do
9
+ subject = Connectwise::Connection.new(credentials.merge(host: 'badhost.connectwisebad.com'))
10
+ expect {subject.call(:contact, :find_contacts, {})}.to raise_error Connectwise::UnknownHostError
11
+ end
12
+
13
+ it 'raises an UnknownCompanyError' do
14
+ subject = Connectwise::Connection.new(credentials.merge(company_name: 'badcompanyname'))
15
+ expect {subject.call(:contact, :find_contacts, {})}.to raise_error Connectwise::UnknownCompanyError
16
+ end
17
+
18
+ it 'raises a BadCredentialsError' do
19
+ subject = Connectwise::Connection.new(credentials.merge(integrator_login_id: 'badloginname'))
20
+ expect {subject.call(:contact, :find_contacts, {})}.to raise_error Connectwise::BadCredentialsError
21
+ end
22
+
23
+ it 'raises a ConnectionError' do
24
+ expect {subject.call(:contact, :delete_contact, {})}.to raise_error Connectwise::ConnectionError
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise::Contact do
4
+ let(:credentials) { connectwise_credentials }
5
+ let(:conn) { Connectwise::Connection.new(credentials) }
6
+ let(:contact) { OpenStruct.new first_name: 'Malcom', last_name: 'Reynolds' }
7
+ subject {Connectwise::Contact.new(conn, contact.to_h)}
8
+
9
+ it 'creates a contact' do
10
+ contact_id = contact.id
11
+ new_contact = subject.save
12
+ expect(new_contact.persisted?).to be_true
13
+ expect(new_contact.id).not_to be_empty
14
+ expect(contact_id).not_to eq new_contact.id
15
+ end
16
+
17
+ it 'finds a contact' do
18
+ new_contact = subject.save
19
+ new_contact = contact
20
+ found_contacts = Connectwise::Contact.where(conn, first_name: new_contact.first_name, last_name: new_contact.last_name)
21
+ expect(found_contacts).not_to be_empty
22
+ end
23
+
24
+ it 'finds no contact' do
25
+ new_contact = subject.save
26
+ found_contacts = Connectwise::Contact.where(conn, first_name: 'gobledy', last_name: 'gook')
27
+ expect(found_contacts).to be_empty
28
+ end
29
+
30
+ it 'deletes a contact' do
31
+ new_contact = subject.save
32
+ found_contacts = Connectwise::Contact.where(conn, first_name: new_contact.first_name, last_name: new_contact.last_name)
33
+ current_count = found_contacts.count
34
+ deleted_contact = found_contacts.first.destroy
35
+ expect(deleted_contact).not_to be_nil
36
+ found_contacts = Connectwise::Contact.where(conn, first_name: new_contact.first_name, last_name: new_contact.last_name)
37
+ expect(current_count - found_contacts.count).to eq 1
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise::Member do
4
+ let(:credentials) { connectwise_credentials }
5
+ let(:conn) { Connectwise::Connection.new(credentials) }
6
+ subject {Connectwise::Member}
7
+
8
+ # Note this test relies on the default connectwise test setup where 'test@test.com' is every member's email
9
+ it 'finds a member' do
10
+ response = subject.where(conn, email_address: 'test@test.com')
11
+ expect(response.first.class).to eq Connectwise::Member
12
+ expect(response.first.email_address).to eq 'test@test.com'
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise::Opportunity do
4
+ it 'creates an opportunity' do
5
+ new_company = subject.create_company(company)
6
+ new_contact = subject.create_contact(contact, new_company[:company_id])
7
+ resp = subject.create_opportunity(lead, new_company[:company_id], new_contact[:id])
8
+ expect(resp[:id]).not_to be_empty
9
+ end
10
+
11
+ it 'deletes an opportunity' do
12
+ new_company = subject.create_company(company)
13
+ new_contact = subject.create_contact(contact, new_company[:company_id])
14
+ new_opp = subject.create_opportunity(lead, new_company[:company_id], new_contact[:id])
15
+ expect(subject.delete_opportunity(OpenStruct.new(id: new_opp[:id]))).to be_nil
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise::Ticket do
4
+ it 'creates a ticket' do
5
+ new_company = subject.create_company(company)
6
+ resp = subject.create_ticket(OpenStruct.new(subject: 'help', description: 'abcd go boom'), OpenStruct.new(id: new_company[:company_id]))
7
+ expect(resp[:ticket_number]).not_to be_nil
8
+ end
9
+
10
+ it 'finds a service ticket' do
11
+ new_company = subject.create_company(company)
12
+ new_ticket = subject.create_ticket(OpenStruct.new(subject: 'help', description: 'abcd go boom'), OpenStruct.new(id: new_company[:company_id]))
13
+ resp = subject.find_ticket(OpenStruct.new(id: new_ticket[:ticket_number]), OpenStruct.new(name: 'Gobledygook ragnok ramastrodon'))
14
+ expect(resp).not_to be_empty
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connectwise do
4
+
5
+ end
@@ -0,0 +1,7 @@
1
+ require_relative '../lib/connectwise_sdk'
2
+ require 'ostruct'
3
+
4
+ def connectwise_credentials
5
+ conf = YAML::load_file(File.join(__dir__, 'credentials.yml'))
6
+ conf['connectwise_credentials'].each_with_object({}) {|(k,v), h| h[k.to_sym] = v}
7
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: connectwise_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Emery A. Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: savon
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ description: This Gem is an SDK for accessing Connectwise
70
+ email:
71
+ - emery.miller@easyofficephone.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - connectwise_sdk.gemspec
82
+ - lib/connectwise/company.rb
83
+ - lib/connectwise/connection.rb
84
+ - lib/connectwise/connectwise.rb
85
+ - lib/connectwise/contact.rb
86
+ - lib/connectwise/extensions.rb
87
+ - lib/connectwise/member.rb
88
+ - lib/connectwise/model.rb
89
+ - lib/connectwise/opportunity.rb
90
+ - lib/connectwise/ticket.rb
91
+ - lib/connectwise/version.rb
92
+ - lib/connectwise_sdk.rb
93
+ - spec/credentials.yml.sample
94
+ - spec/lib/connectwise/company_spec.rb
95
+ - spec/lib/connectwise/connection_spec.rb
96
+ - spec/lib/connectwise/contact_spec.rb
97
+ - spec/lib/connectwise/member_spec.rb
98
+ - spec/lib/connectwise/opportunity_spec.rb
99
+ - spec/lib/connectwise/ticket_spec.rb
100
+ - spec/lib/connectwise_sdk_spec.rb
101
+ - spec/spec_helper.rb
102
+ homepage: http://github.com/EasyOfficePhone/connectwise-sdk
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.2.2
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: A Connectwise SDK for Ruby
126
+ test_files:
127
+ - spec/credentials.yml.sample
128
+ - spec/lib/connectwise/company_spec.rb
129
+ - spec/lib/connectwise/connection_spec.rb
130
+ - spec/lib/connectwise/contact_spec.rb
131
+ - spec/lib/connectwise/member_spec.rb
132
+ - spec/lib/connectwise/opportunity_spec.rb
133
+ - spec/lib/connectwise/ticket_spec.rb
134
+ - spec/lib/connectwise_sdk_spec.rb
135
+ - spec/spec_helper.rb