autotask_api 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6021a61922f1e9db170a6d2bddc4f3b12b2ec204e38e6a34441aee39fa1c0482
4
+ data.tar.gz: 641aa14f45bd254a197b7b111c8aa9d81e6bbf0b6a79abf6ae98221a82724b12
5
+ SHA512:
6
+ metadata.gz: 407cff3284b60e5ddd0d4bc95f16b8d6dec3ec0853c5bfca8191d8b05d39e3555f8ee0579673ae6a72445e71ac94fd9d1707633274b59add8f42fe5bcff45bae
7
+ data.tar.gz: 36eb930031433176d1a5374cc05774dc882ebdd66f4763cd2e3b61821a1189275b321cfc1968380e9df77946d6af3060a0e3efa15468965d07a227df7d81f61a
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Kevin Pheasey
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,182 @@
1
+ # AutotaskApi
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'autotask_api'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install autotask_api
22
+ ```
23
+
24
+ ## Query
25
+
26
+ ### Simple field test
27
+
28
+ SQL:
29
+ ```sql
30
+ firstname = 'Joe'
31
+ ```
32
+
33
+ Objects:
34
+ ```ruby
35
+ e1 = AutotaskApi::Expression.new('firstname', 'equals', 'Joe')
36
+ c = AutotaskApi::Condition.new(e1)
37
+
38
+ AutotaskApi::Contact.where(c)
39
+ ```
40
+
41
+ Hash:
42
+ ```ruby
43
+ AutotaskApi::Condition.from_hash(
44
+ expressions: [
45
+ { field: 'firstname', operator: 'equals', value: 'Joe' }
46
+ ]
47
+ )
48
+ ```
49
+
50
+ ### Multiple Field Test
51
+
52
+ SQL:
53
+ ```sql
54
+ firstname = ‘Joe’ AND lastname = ‘Smith’
55
+ ```
56
+
57
+ Objects:
58
+ ```ruby
59
+ e1 = AutotaskApi::Expression.new('firstname', 'equals', 'Joe')
60
+ e2 = AutotaskApi::Expression.new('lastname', 'equals', 'Smith')
61
+ c = AutotaskApi::Condition.new([e1, e2])
62
+
63
+ AutotaskApi::Contact.where(c)
64
+ ```
65
+
66
+ Hash:
67
+ ```ruby
68
+ c = AutotaskApi::Condition.from_hash(
69
+ expressions: [
70
+ { field: 'firstname', operator: 'equals', value: 'Joe' },
71
+ { field: 'lastname', operator: 'equals', value: 'Smith' }
72
+ ]
73
+ )
74
+
75
+ AutotaskApi::Contact.where(c)
76
+ ```
77
+
78
+ ### Multiple Fields combined with OR
79
+
80
+ SQL:
81
+ ```sql
82
+ firstname = ‘Joe’ OR lastname = ‘Brown’
83
+ ```
84
+
85
+ Objects:
86
+ ```ruby
87
+ e1 = AutotaskApi::Expression.new('firstname', 'equals', 'Joe')
88
+ e2 = AutotaskApi::Expression.new('lastname', 'equals', 'Brown')
89
+ c = AutotaskApi::Condition.new([e1, e2], 'OR')
90
+
91
+ AutotaskApi::Contact.where(c)
92
+ ```
93
+
94
+ Hash:
95
+ ```ruby
96
+ c = AutotaskApi::Condition.from_hash(
97
+ expressions: [
98
+ { field: 'firstname', operator: 'equals', value: 'Joe' },
99
+ { field: 'lastname', operator: 'equals', value: 'Brown' }
100
+ ],
101
+ operator: 'OR'
102
+ )
103
+
104
+ AutotaskApi::Contact.where(c)
105
+ ```
106
+
107
+ ### Nested Conditions
108
+
109
+ SQL:
110
+ ```sql
111
+ (
112
+ firstname = ‘Joe’
113
+ OR
114
+ (
115
+ (firstname = ‘Larry’ and lastname = ‘Brown’)
116
+ OR
117
+ (firstname = ‘Mary’ and lastname = ‘Smith’)
118
+ )
119
+ )
120
+ # AND city != 'Albany'
121
+ ```
122
+
123
+ Objects:
124
+ ```ruby
125
+ e1 = AutotaskApi::Expression.new('firstname', 'equals', 'Larry')
126
+ e2 = AutotaskApi::Expression.new('lastname', 'equals', 'Brown')
127
+ c1 = AutotaskApi::Condition.new([e1, e2])
128
+
129
+ e3 = AutotaskApi::Expression.new('firstname', 'equals', 'Mary')
130
+ e4 = AutotaskApi::Expression.new('lastname', 'equals', 'Smith')
131
+ c2 = AutotaskApi::Condition.new([e3, e4])
132
+
133
+ c3 = AutotaskApi::Condition.new([c1, c2], 'OR')
134
+
135
+ e5 = AutotaskApi::Expression.new('firstname', 'equals', 'Joe')
136
+ c4 = AutotaskApi::Condition.new([e5, c3], 'OR')
137
+
138
+ e6 = AutotaskApi::Expression.new('city', 'notequal', 'Albany')
139
+ c5 = AutotaskApi::Condition.new([c4, e6])
140
+
141
+ AutotaskApi::Query.new('contact', c5).fetch
142
+ ```
143
+
144
+ Hash:
145
+ ```
146
+ c = AutotaskApi::Condition.from_hash(
147
+ expressions: [
148
+ {
149
+ expressions: [
150
+ { field: 'firstname', operator: 'equals', value: 'Joe' },
151
+ {
152
+ expressions: [
153
+ {
154
+ expressions: [
155
+ { field: 'firstname', operator: 'equals', value: 'Larry' },
156
+ { field: 'lastname', operator: 'equals', value: 'Brown' }
157
+ ]
158
+ },
159
+ {
160
+ expressions: [
161
+ { field: 'firstname', operator: 'equals', value: 'Marry' },
162
+ { field: 'lastname', operator: 'equals', value: 'Smith' }
163
+ ]
164
+ }
165
+ ],
166
+ operator: 'OR'
167
+ }
168
+ ],
169
+ operator: 'OR'
170
+ },
171
+ { field: 'city', operator: 'notequal', value: 'Albany' }
172
+ ]
173
+ )
174
+
175
+ AutotaskApi::Contact.where(c)
176
+ ```
177
+
178
+ ## Contributing
179
+ Contribution directions go here.
180
+
181
+ ## License
182
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'AutotaskApi'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,22 @@
1
+ require 'nokogiri'
2
+ require 'savon'
3
+
4
+ require 'autotask_api/version'
5
+ require 'autotask_api/config'
6
+ require 'autotask_api/client'
7
+ require 'autotask_api/query'
8
+ require 'autotask_api/entity'
9
+ require 'autotask_api/entity_collection'
10
+
11
+ module AutotaskApi
12
+ class Error < StandardError
13
+ def initialize(msg)
14
+ # extract SOAP Exception message if present
15
+ if msg.include?('[SoapException:')
16
+ msg = msg[/\[SoapException:(.*?)\]/, 1]&.strip
17
+ end
18
+
19
+ super(msg)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ module AutotaskApi
2
+
3
+ class << self
4
+ attr_accessor :client
5
+ end
6
+
7
+ def self.client
8
+ @client ||= Client.new
9
+ end
10
+
11
+ class Client
12
+
13
+ NAMESPACE = 'http://autotask.net/ATWS/v1_5/'
14
+
15
+ attr_reader :config
16
+
17
+ def initialize
18
+ @config = AutotaskApi.config
19
+ yield @config if block_given?
20
+ end
21
+
22
+ def savon_client
23
+ @savon_client ||= Savon.client(
24
+ wsdl: config.wsdl,
25
+ logger: Rails.logger,
26
+ log_level: :debug,
27
+ log: config.debug,
28
+ basic_auth: [config.username, config.password]
29
+ )
30
+ end
31
+
32
+ def call(operation, message = {})
33
+ savon_client.call(operation, message: message, attributes: { xmlns: NAMESPACE })
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ module AutotaskApi
2
+
3
+ class << self
4
+ attr_accessor :config
5
+ end
6
+
7
+ def self.config
8
+ @config ||= Configuration.new
9
+ end
10
+
11
+ def self.configure
12
+ yield(config)
13
+ end
14
+
15
+ class Configuration
16
+ attr_accessor :wsdl, :username, :password, :read_timeout, :open_timeout, :debug
17
+
18
+ def initialize
19
+ @wsdl = 'https://webservices.autotask.net/atservices/1.5/atws.wsdl'
20
+ @read_timeout = 30
21
+ @open_timeout = 30
22
+ @debug = false
23
+ end
24
+
25
+ def set(options = {})
26
+ options.each { |k, v| self.send("#{k.to_s}=", v) }
27
+ end
28
+
29
+ def to_hash
30
+ hash = {}
31
+ instance_variables.each { |var| hash[var.to_s.delete('@').to_sym] = instance_variable_get(var) }
32
+ hash
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,322 @@
1
+ module AutotaskApi
2
+ class Entity
3
+
4
+ def self.all(client = AutotaskApi.client, id = 1)
5
+ where(Condition.new(Expression.new('id', 'GreaterThanorEquals', id)), client)
6
+ end
7
+
8
+ # @param conditions [Hash]
9
+ def self.where(condition, client = AutotaskApi.client)
10
+ query = Query.new(self::NAME, condition, client)
11
+
12
+ begin
13
+ response = query.fetch
14
+ rescue RuntimeError => e
15
+ raise Error.new(e.message)
16
+ end
17
+
18
+ # return empty collection if there were no results
19
+ return EntityCollection.new(self, [], condition, client) if response[:entity_results].nil?
20
+
21
+ results = response[:entity_results][:entity]
22
+ results = [results] unless results.is_a?(Array)
23
+ results = clean_results(results)
24
+
25
+ EntityCollection.new(self, results, condition, client)
26
+ end
27
+
28
+ def self.expression(value)
29
+ case value.class
30
+ when TrueClass
31
+ 1
32
+ when FalseClass
33
+ 0
34
+ else
35
+ value
36
+ end
37
+ end
38
+
39
+ # @param results [Array(Hash)]
40
+ def self.clean_results(results)
41
+ results.each do |record|
42
+ record.update(record) { |_k, v| v == { :"@xsi:type" => "xsd:string" } ? nil : v }
43
+ .delete('@xsi:type'.to_sym)
44
+ end
45
+
46
+ return results
47
+ end
48
+
49
+ end
50
+
51
+ class Account < Entity
52
+ NAME = 'Account'
53
+ end
54
+
55
+ class AccountLocation < Entity
56
+ NAME = 'AccountLocation'
57
+ end
58
+
59
+ class AccountTeam < Entity
60
+ NAME = 'AccountTeam'
61
+ end
62
+
63
+ class AllocationCode < Entity
64
+ NAME = 'AllocationCode'
65
+ end
66
+
67
+ class BillingItem < Entity
68
+ NAME = 'BillingItem'
69
+ end
70
+
71
+ class Contact < Entity
72
+ NAME = 'Contact'
73
+ end
74
+
75
+ class Contract < Entity
76
+ NAME = 'Contract'
77
+ end
78
+
79
+ class ContractBlock < Entity
80
+ NAME = 'ContractBlock'
81
+ end
82
+
83
+ class ContractCost < Entity
84
+ NAME = 'ContractCost'
85
+ end
86
+
87
+ class ContractExclusionAllocationCode < Entity
88
+ NAME = 'ContractExclusionAllocationCode'
89
+ end
90
+
91
+ class ContractExclusionRole < Entity
92
+ NAME = 'ContractExclusionRole'
93
+ end
94
+
95
+ class ContractFactor < Entity
96
+ NAME = 'ContractFactor'
97
+ end
98
+
99
+ class ContractMilestone < Entity
100
+ NAME = 'ContractMilestone'
101
+ end
102
+
103
+ class ContractRate < Entity
104
+ NAME = 'ContractRate'
105
+ end
106
+
107
+ class ContractRetainer < Entity
108
+ NAME = 'ContractRetainer'
109
+ end
110
+
111
+ class ContractRoleCost < Entity
112
+ NAME = 'ContractRoleCost'
113
+ end
114
+
115
+ class ContractService < Entity
116
+ NAME = 'ContractService'
117
+ end
118
+
119
+ class ContractServiceAdjustment < Entity
120
+ NAME = 'ContractServiceAdjustment'
121
+ end
122
+
123
+ class ContractServiceBundle < Entity
124
+ NAME = 'ContractServiceBundle'
125
+ end
126
+
127
+ class ContractServiceBundleAdjustment < Entity
128
+ NAME = 'ContractServiceBundleAdjustment'
129
+ end
130
+
131
+ class ContractServiceBundleUnit < Entity
132
+ NAME = 'ContractServiceBundleUnit'
133
+ end
134
+
135
+ class ContractServiceUnit < Entity
136
+ NAME = 'ContractServiceUnit'
137
+ end
138
+
139
+ class ContractTicketPurchase < Entity
140
+ NAME = 'ContractTicketPurchase'
141
+ end
142
+
143
+ class Country < Entity
144
+ NAME = 'Country'
145
+ end
146
+
147
+ class Department < Entity
148
+ NAME = 'Department'
149
+ end
150
+
151
+ class ExpenseItem < Entity
152
+ NAME = 'ExpenseItem'
153
+ end
154
+
155
+ class ExpenseReport < Entity
156
+ NAME = 'ExpenseReport'
157
+ end
158
+
159
+ class InstalledProduct < Entity
160
+ NAME = 'InstalledProduct'
161
+ end
162
+
163
+ class InstalledProductType < Entity
164
+ NAME = 'InstalledProductType'
165
+ end
166
+
167
+ class InternalLocation < Entity
168
+ NAME = 'InternalLocation'
169
+ end
170
+
171
+ class InventoryItem < Entity
172
+ NAME = 'InventoryItem'
173
+ end
174
+
175
+ class InventoryLocation < Entity
176
+ NAME = 'InventoryLocation'
177
+ end
178
+
179
+ class Invoice < Entity
180
+ NAME = 'Invoice'
181
+ end
182
+
183
+ class Opportunity < Entity
184
+ NAME = 'Opportunity'
185
+ end
186
+
187
+ class PaymentTerm < Entity
188
+ NAME = 'PaymentTerm'
189
+ end
190
+
191
+ class Phase < Entity
192
+ NAME = 'Phase'
193
+ end
194
+
195
+ class Product < Entity
196
+ NAME = 'Product'
197
+ end
198
+
199
+ class Project < Entity
200
+ NAME = 'Project'
201
+ end
202
+
203
+ class ProjectCost < Entity
204
+ NAME = 'ProjectCost'
205
+ end
206
+
207
+ class ProjectNote < Entity
208
+ NAME = 'ProjectNote'
209
+ end
210
+
211
+ class PurchaseOrderItem < Entity
212
+ NAME = 'PurchaseOrderItem'
213
+ end
214
+
215
+ class Quote < Entity
216
+ NAME = 'Quote'
217
+ end
218
+
219
+ class QuoteItem < Entity
220
+ NAME = 'QuoteItem'
221
+ end
222
+
223
+ class QuoteLocation < Entity
224
+ NAME = 'QuoteLocation'
225
+ end
226
+
227
+ class Resource < Entity
228
+ NAME = 'Resource'
229
+ end
230
+
231
+ class ResourceRole < Entity
232
+ NAME = 'ResourceRole'
233
+ end
234
+
235
+ class ResourceSkill < Entity
236
+ NAME = 'ResourceSkill'
237
+ end
238
+
239
+ class Role < Entity
240
+ NAME = 'Role'
241
+ end
242
+
243
+ class SalesOrder < Entity
244
+ NAME = 'SalesOrder'
245
+ end
246
+
247
+ class Service < Entity
248
+ NAME = 'Service'
249
+ end
250
+
251
+ class ServiceBundle < Entity
252
+ NAME = 'ServiceBundle'
253
+ end
254
+
255
+ class ServiceBundleService < Entity
256
+ NAME = 'ServiceBundleService'
257
+ end
258
+
259
+ class ServiceCall < Entity
260
+ NAME = 'ServiceCall'
261
+ end
262
+
263
+ class ServiceCallTask < Entity
264
+ NAME = 'ServiceCallTask'
265
+ end
266
+
267
+ class ServiceCallTaskResource < Entity
268
+ NAME = 'ServiceCallTaskResource'
269
+ end
270
+
271
+ class ServiceCallTicket < Entity
272
+ NAME = 'ServiceCallTicket'
273
+ end
274
+
275
+ class ServiceCallTicketResource < Entity
276
+ NAME = 'ServiceCallTicketResource'
277
+ end
278
+
279
+ class Skill < Entity
280
+ NAME = 'Skill'
281
+ end
282
+
283
+ class Task < Entity
284
+ NAME = 'Task'
285
+ end
286
+
287
+ class TaskPredecessor < Entity
288
+ NAME = 'TaskPredecessor'
289
+ end
290
+
291
+ class TaskSecondaryResource < Entity
292
+ NAME = 'TaskSecondaryResource'
293
+ end
294
+
295
+ class Tax < Entity
296
+ NAME = 'Tax'
297
+ end
298
+
299
+ class TaxCategory < Entity
300
+ NAME = 'TaxCategory'
301
+ end
302
+
303
+ class TaxRegion < Entity
304
+ NAME = 'TaxRegion'
305
+ end
306
+
307
+ class Ticket < Entity
308
+ NAME = 'Ticket'
309
+ end
310
+
311
+ class TicketCost < Entity
312
+ NAME = 'TicketCost'
313
+ end
314
+
315
+ class TicketSecondaryResource < Entity
316
+ NAME = 'TicketSecondaryResource'
317
+ end
318
+
319
+ class TimeEntry < Entity
320
+ NAME = 'TimeEntry'
321
+ end
322
+ end
@@ -0,0 +1,45 @@
1
+ module AutotaskApi
2
+ class EntityCollection
3
+ include Enumerable
4
+
5
+ PAGE_SIZE = 500
6
+
7
+ attr_accessor :condition
8
+
9
+ attr_reader :entities, :client, :class_name
10
+
11
+ def initialize(class_name, entities, condition, client = AutotaskApi.client)
12
+ @class_name = class_name
13
+ @entities = entities
14
+ @condition = condition
15
+ @client = client
16
+ end
17
+
18
+ def each(&block)
19
+ entities.each(&block)
20
+ end
21
+
22
+ def last(&block)
23
+ entities.last(&block)
24
+ end
25
+
26
+ def next_page?
27
+ entities.size >= PAGE_SIZE
28
+ end
29
+
30
+ def next_page
31
+ new_expression = Expression.new('id', 'GreaterThan', entities.last[:id])
32
+
33
+ condition.remove_expression_by_field('id')
34
+ params = condition.expressions.empty? ? new_expression : [condition, new_expression]
35
+
36
+ new_condition = Condition.new(params)
37
+
38
+ class_name.where(new_condition, client)
39
+ end
40
+
41
+ def empty?
42
+ entities.empty?
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,93 @@
1
+ module AutotaskApi
2
+ class Query
3
+ attr_accessor :entity, :client, :condition
4
+
5
+ def initialize(entity, condition = nil, client = AutotaskApi.client)
6
+ @entity = entity
7
+ @client = client
8
+ @condition = condition
9
+ end
10
+
11
+ def fetch
12
+ response = client.call :query, query_string
13
+
14
+ result = response.body[:query_response][:query_result]
15
+
16
+ if result[:return_code].to_i == -1
17
+ raise result[:errors][:atws_error][:message]
18
+ else
19
+ return result
20
+ end
21
+ end
22
+
23
+ def query_string
24
+ Nokogiri::XML::Builder.new do
25
+ sXML do
26
+ cdata(Nokogiri::XML::Builder.new do |xml|
27
+ xml.queryxml do
28
+ xml.entity entity
29
+ xml.query do
30
+ condition.to_xml(xml)
31
+ end
32
+ end
33
+ end.doc.root)
34
+ end
35
+ end.doc.root.to_s
36
+ end
37
+
38
+ end
39
+
40
+ class Condition
41
+
42
+ attr_reader :expressions, :operator
43
+
44
+ def initialize(expressions, operator = 'AND')
45
+ @expressions = expressions.is_a?(Array) ? expressions : [expressions]
46
+ @operator = operator
47
+ end
48
+
49
+ def to_xml(xml)
50
+ xml.condition operator: operator do
51
+ expressions.each { |expression| expression.to_xml(xml) }
52
+ end
53
+ end
54
+
55
+ def self.from_hash(condition = {})
56
+ expressions = condition[:expressions].map do |exprnewession|
57
+ expression.has_key?(:expressions) ? Condition.from_hash(expression) : Expression.from_hash(expression)
58
+ end
59
+
60
+ new expressions, condition[:operator] || 'AND'
61
+ end
62
+
63
+ def remove_expression_by_field(field)
64
+ expressions.reject! do |expression|
65
+ expression.is_a?(Condition) ? expression.remove_expression_by_field(field) : expression.field == field
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ class Expression
72
+
73
+ attr_reader :field, :operator, :value
74
+
75
+ def initialize(field, operator, value)
76
+ @field = field
77
+ @operator = operator
78
+ @value = value
79
+ end
80
+
81
+ def to_xml(xml)
82
+ xml.field field do
83
+ xml.expression value, op: operator
84
+ end
85
+ end
86
+
87
+ def self.from_hash(expression = {})
88
+ new(expression[:field], expression[:operator], expression[:value])
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,3 @@
1
+ module AutotaskApi
2
+ VERSION = '0.3.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :autotask_api do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: autotask_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Pheasey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: savon
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '3'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '2'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '3'
53
+ description: Abstracted Autotask API 1.5 wrapper
54
+ email:
55
+ - kevin@kpsoftware.io
56
+ executables: []
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - MIT-LICENSE
61
+ - README.md
62
+ - Rakefile
63
+ - lib/autotask_api.rb
64
+ - lib/autotask_api/client.rb
65
+ - lib/autotask_api/config.rb
66
+ - lib/autotask_api/entity.rb
67
+ - lib/autotask_api/entity_collection.rb
68
+ - lib/autotask_api/query.rb
69
+ - lib/autotask_api/version.rb
70
+ - lib/tasks/autotask_api_tasks.rake
71
+ homepage: https://github.com/MSPCFO/autotask_api
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.7.6
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Autotask API wrapper
95
+ test_files: []