cherby 0.0.1
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 +6 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/.yardopts +4 -0
- data/Gemfile +6 -0
- data/README.md +83 -0
- data/Rakefile +12 -0
- data/cherby.gemspec +29 -0
- data/lib/cherby.rb +11 -0
- data/lib/cherby/business_object.rb +159 -0
- data/lib/cherby/cherwell.rb +230 -0
- data/lib/cherby/client.rb +147 -0
- data/lib/cherby/exceptions.rb +6 -0
- data/lib/cherby/incident.rb +141 -0
- data/lib/cherby/journal_note.rb +13 -0
- data/lib/cherby/task.rb +37 -0
- data/lib/cherby/templates/incident.mustache +226 -0
- data/lib/cherby/templates/journal_note.mustache +30 -0
- data/lib/cherby/templates/journal_note_relationship.mustache +3 -0
- data/lib/cherby/templates/task.mustache +67 -0
- data/lib/cherby/templates/task_relationship.mustache +3 -0
- data/lib/cherby/templates/test/simple.mustache +8 -0
- data/spec/business_object_spec.rb +250 -0
- data/spec/cherwell_spec.rb +300 -0
- data/spec/client_spec.rb +149 -0
- data/spec/data/cherwell.wsdl +1568 -0
- data/spec/data/incident.xml +1411 -0
- data/spec/data/login_false.xml +8 -0
- data/spec/data/login_true.xml +6 -0
- data/spec/data/task.xml +64 -0
- data/spec/incident_spec.rb +124 -0
- data/spec/journal_note_spec.rb +13 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/task_spec.rb +77 -0
- data/spec/xml/method_response_result.mustache +4 -0
- data/spec/xml/soap_envelope.mustache +6 -0
- data/tasks/pry.rake +28 -0
- data/tasks/spec.rake +8 -0
- metadata +261 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
Cherby
|
2
|
+
======
|
3
|
+
|
4
|
+
Cherby is a Ruby wrapper for the
|
5
|
+
[Cherwell Web Service](http://cherwellsupport.com/webhelp/cherwell/index.htm#1971.htm).
|
6
|
+
|
7
|
+
[Full documentation is on rdoc.info](http://rubydoc.info/github/a-e/cherby/master/frames).
|
8
|
+
|
9
|
+
[](http://travis-ci.org/a-e/cherby)
|
10
|
+
|
11
|
+
|
12
|
+
Usage
|
13
|
+
-----
|
14
|
+
|
15
|
+
Connect to a Cherwell server by providing the URL of the web service:
|
16
|
+
|
17
|
+
url = "http://my.server/CherwellService/api.asmx"
|
18
|
+
cherwell = Cherby::Cherwell.new(url)
|
19
|
+
|
20
|
+
Login by providing username and password, either during instantiation, or later
|
21
|
+
when calling the `#login` method:
|
22
|
+
|
23
|
+
cherwell = Cherby::Cherwell.new(url, 'sisko', 'baseball')
|
24
|
+
cherwell.login
|
25
|
+
# => true
|
26
|
+
|
27
|
+
# or
|
28
|
+
|
29
|
+
cherwell = Cherby::Cherwell.new(url)
|
30
|
+
cherwell.login('sisko', 'baseball')
|
31
|
+
# => true
|
32
|
+
|
33
|
+
Fetch an Incident:
|
34
|
+
|
35
|
+
incident = cherwell.incident('12345')
|
36
|
+
# => #<Cherby::Incident:0x...>
|
37
|
+
|
38
|
+
View as a Hash:
|
39
|
+
|
40
|
+
incident.to_hash
|
41
|
+
# => {
|
42
|
+
# 'IncidentID' => '12345',
|
43
|
+
# 'Status' => 'Open',
|
44
|
+
# 'Priority' => '7',
|
45
|
+
# ...
|
46
|
+
# }
|
47
|
+
|
48
|
+
Make changes:
|
49
|
+
|
50
|
+
incident['Status'] = 'Closed'
|
51
|
+
incident['CloseDescription'] = 'Issue resolved'
|
52
|
+
|
53
|
+
Save back to Cherwell:
|
54
|
+
|
55
|
+
cherwell.save_incident(incident)
|
56
|
+
|
57
|
+
|
58
|
+
Copyright
|
59
|
+
---------
|
60
|
+
|
61
|
+
The MIT License
|
62
|
+
|
63
|
+
Copyright (c) 2014 Eric Pierce
|
64
|
+
|
65
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
66
|
+
a copy of this software and associated documentation files (the
|
67
|
+
"Software"), to deal in the Software without restriction, including
|
68
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
69
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
70
|
+
permit persons to whom the Software is furnished to do so, subject to
|
71
|
+
the following conditions:
|
72
|
+
|
73
|
+
The above copyright notice and this permission notice shall be
|
74
|
+
included in all copies or substantial portions of the Software.
|
75
|
+
|
76
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
77
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
78
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
79
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
80
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
81
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
82
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
83
|
+
|
data/Rakefile
ADDED
data/cherby.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "cherby"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.summary = "Cherwell-Ruby bridge"
|
5
|
+
s.description = <<-EOS
|
6
|
+
Cherby is a Ruby wrapper for the Cherwell Web Service.
|
7
|
+
EOS
|
8
|
+
s.authors = ["Eric Pierce"]
|
9
|
+
s.email = "wapcaplet88@gmail.com"
|
10
|
+
s.homepage = "http://github.com/a-e/cherby"
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
|
13
|
+
s.add_dependency "httpclient"
|
14
|
+
s.add_dependency 'savon', '>= 2.3.0'
|
15
|
+
s.add_dependency 'yajl-ruby'
|
16
|
+
s.add_dependency 'nokogiri'
|
17
|
+
s.add_dependency 'mustache'
|
18
|
+
|
19
|
+
s.add_development_dependency "rake"
|
20
|
+
s.add_development_dependency "simplecov"
|
21
|
+
s.add_development_dependency "pry"
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency 'yard'
|
24
|
+
s.add_development_dependency 'redcarpet'
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.require_path = 'lib'
|
28
|
+
end
|
29
|
+
|
data/lib/cherby.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Cherby
|
5
|
+
# Cherwell BusinessObject wrapper, with data represented as an XML DOM
|
6
|
+
class BusinessObject
|
7
|
+
|
8
|
+
# Override this with the value of the BusinessObject's 'Name' attribute
|
9
|
+
@object_name = ''
|
10
|
+
# Override this with the name of the Mustache XML template used to render
|
11
|
+
# your BusinessObject
|
12
|
+
@template = ''
|
13
|
+
# Fill this with default values for new instances of your BusinessObject
|
14
|
+
@default_values = {}
|
15
|
+
|
16
|
+
class << self
|
17
|
+
attr_accessor :object_name, :template, :default_values, :template_path
|
18
|
+
end
|
19
|
+
|
20
|
+
# Create a new BusinessObject subclass instance from the given hash of
|
21
|
+
# options.
|
22
|
+
# FIXME: Make this method accept CamelCase string field names instead of
|
23
|
+
# just :snake_case symbols, as part of a larger strategy to treat field names
|
24
|
+
# consistently throughout (using Cherwell's CamelCase strings everywhere)
|
25
|
+
def self.create(options={})
|
26
|
+
if self.template.empty?
|
27
|
+
# TODO: Exception subclass
|
28
|
+
raise RuntimeError, "No template defined for BusinessObject"
|
29
|
+
end
|
30
|
+
Mustache.template_path = File.join(File.dirname(__FILE__), 'templates')
|
31
|
+
xml = Mustache.render_file(
|
32
|
+
self.template, self.default_values.merge(options))
|
33
|
+
return self.new(xml)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Instance methods
|
37
|
+
|
38
|
+
attr_reader :dom
|
39
|
+
|
40
|
+
# Create a new instance populated with the given XML string
|
41
|
+
def initialize(xml)
|
42
|
+
@dom = Nokogiri::XML(xml)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return the XML representation of this BusinessObject
|
46
|
+
def to_xml
|
47
|
+
return @dom.to_xml
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return the node of the field with the given name.
|
51
|
+
def get_field_node(field_name)
|
52
|
+
selector = "BusinessObject > FieldList > Field[@Name=#{field_name}]"
|
53
|
+
return @dom.css(selector).first
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return a hash of field names and values
|
57
|
+
def to_hash
|
58
|
+
result = {}
|
59
|
+
selector = "BusinessObject > FieldList > Field"
|
60
|
+
@dom.css(selector).each do |node|
|
61
|
+
result[node['Name']] = node.content
|
62
|
+
end
|
63
|
+
return result
|
64
|
+
end
|
65
|
+
alias :field_values :to_hash # For backwards compatibility
|
66
|
+
|
67
|
+
|
68
|
+
# Parse a Cherwell date/time string and return a DateTime object in UTC.
|
69
|
+
#
|
70
|
+
# This method mostly exists to work around the fact that Cherwell does
|
71
|
+
# not report a time zone offset in its datestamps. Since a BusinessObject
|
72
|
+
# may be initialized from a Jira entity (which *does* store time zone
|
73
|
+
# offset), any dt_string that includes a time zone offset at the end is
|
74
|
+
# correctly included in the result.
|
75
|
+
#
|
76
|
+
# @param [String] dt_string
|
77
|
+
# The date/time string to parse. May or may not include a trailing
|
78
|
+
# [+-]HH:MM or [+-]HHMM.
|
79
|
+
#
|
80
|
+
# @param [Integer] tz_offset
|
81
|
+
# Offset in hours (positive or negative) between UTC and the given
|
82
|
+
# `dt_string`. For example, Eastern Time is `-5`. This is ONLY used if
|
83
|
+
# `dt_string` does NOT include a trailing offset component.
|
84
|
+
#
|
85
|
+
def self.parse_datetime(dt_string, tz_offset=-5)
|
86
|
+
begin
|
87
|
+
result = DateTime.parse(dt_string)
|
88
|
+
rescue
|
89
|
+
raise ArgumentError, "Could not parse date/time '#{dt_string}'"
|
90
|
+
end
|
91
|
+
# If offset was part of the dt_string, use new_offset to get UTC
|
92
|
+
if dt_string =~ /[+-]\d\d:?\d\d$/
|
93
|
+
return result.new_offset(0)
|
94
|
+
# Otherwise, subtract the numeric offset to get UTC time
|
95
|
+
else
|
96
|
+
return result - Rational(tz_offset.to_i, 24)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return the last-modified date/time of this BusinessObject
|
101
|
+
# (LastModDateTime converted to DateTime)
|
102
|
+
def modified
|
103
|
+
last_mod = self['LastModDateTime']
|
104
|
+
if last_mod.nil?
|
105
|
+
raise RuntimeError, "BusinessObject is missing LastModDateTime field."
|
106
|
+
end
|
107
|
+
begin
|
108
|
+
return BusinessObject.parse_datetime(last_mod)
|
109
|
+
rescue(ArgumentError)
|
110
|
+
raise RuntimeError, "Cannot parse LastModDateTime: '#{last_mod}'"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Return the last-modified time as a human-readable string
|
115
|
+
def mod_s
|
116
|
+
return modified.strftime('%Y-%m-%d %H:%M:%S')
|
117
|
+
end
|
118
|
+
|
119
|
+
# Return True if this BusinessObject was modified more recently than
|
120
|
+
# another BusinessObject.
|
121
|
+
def newer_than?(business_object)
|
122
|
+
return modified > business_object.modified
|
123
|
+
end
|
124
|
+
|
125
|
+
# Return the content in the field with the given name.
|
126
|
+
# TODO: Exception for unknown field name
|
127
|
+
def [](field_name)
|
128
|
+
if field = get_field_node(field_name)
|
129
|
+
return field.content
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Modify the content in the field with the given name.
|
134
|
+
# TODO: Exception for unknown field name
|
135
|
+
def []=(field_name, value)
|
136
|
+
if field = get_field_node(field_name)
|
137
|
+
field.content = value.to_s
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Copy designated fields from one BusinessObject to another.
|
142
|
+
#
|
143
|
+
# @example
|
144
|
+
# object_a.copy_fields_from(object_b, 'Status', 'Description')
|
145
|
+
# # object_a['Status'] = object_b['Status']
|
146
|
+
# # object_a['Description'] = object_b['Description']
|
147
|
+
#
|
148
|
+
# @param [BusinessObject] other_object
|
149
|
+
# The object to copy field values from
|
150
|
+
# @param [Array<String>] field_names
|
151
|
+
# Names of fields whose values you want to copy
|
152
|
+
#
|
153
|
+
def copy_fields_from(other_object, *field_names)
|
154
|
+
field_names.each do |field|
|
155
|
+
self[field] = other_object[field]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'cherby/client'
|
4
|
+
require 'cherby/incident'
|
5
|
+
require 'cherby/task'
|
6
|
+
require 'cherby/exceptions'
|
7
|
+
|
8
|
+
module Cherby
|
9
|
+
# Top-level Cherwell interface
|
10
|
+
class Cherwell
|
11
|
+
attr_reader :url, :username, :client
|
12
|
+
|
13
|
+
# Connect to a Cherwell server.
|
14
|
+
#
|
15
|
+
# @param [String] web_service_url
|
16
|
+
# Full URL to the Cherwell web service API (typically ending in
|
17
|
+
# `api.asmx`)
|
18
|
+
# @param [String] username
|
19
|
+
# Default Cherwell user ID to use
|
20
|
+
# @param [String] password
|
21
|
+
# Default Cherwell password to use
|
22
|
+
#
|
23
|
+
def initialize(web_service_url, username=nil, password=nil)
|
24
|
+
@url = web_service_url
|
25
|
+
@url.chop! if @url =~ /\/$/ # Remove any trailing slash
|
26
|
+
@username = username
|
27
|
+
@password = password
|
28
|
+
@client = Cherby::Client.new(@url)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Login to Cherwell using the given credentials. Return true if
|
32
|
+
# login succeeded, or raise `LoginFailed` if login failed.
|
33
|
+
#
|
34
|
+
# @param [String] username
|
35
|
+
# User ID to login with. If omitted, the username that was passed to
|
36
|
+
# `Cherwell.new` is used.
|
37
|
+
# @param [String] password
|
38
|
+
# Password to login with. If omitted, the password that was passed to
|
39
|
+
# `Cherwell.new` is used.
|
40
|
+
#
|
41
|
+
# @return [Boolean]
|
42
|
+
# `true` if login was successful
|
43
|
+
#
|
44
|
+
# @raise [LoginFailed]
|
45
|
+
# If login failed for any reason
|
46
|
+
#
|
47
|
+
def login(username=nil, password=nil)
|
48
|
+
creds = {
|
49
|
+
:userId => username || @username,
|
50
|
+
:password => password || @password,
|
51
|
+
}
|
52
|
+
begin
|
53
|
+
response = @client.call(:login, :message => creds)
|
54
|
+
rescue => e
|
55
|
+
# This can happen if a bad URL is given
|
56
|
+
raise LoginFailed, e.message
|
57
|
+
else
|
58
|
+
if response.body[:login_response][:login_result] == true
|
59
|
+
# FIXME: Using the workaround described in this issue:
|
60
|
+
# https://github.com/savonrb/savon/issues/363
|
61
|
+
# because the version recommended in the documentation:
|
62
|
+
# auth_cookies = response.http.cookies
|
63
|
+
# does not work, giving:
|
64
|
+
# NoMethodError: undefined method `cookies' for #<HTTPI::Response:0x...>
|
65
|
+
@client.globals[:headers] = {"Cookie" => response.http.headers["Set-Cookie"]}
|
66
|
+
return true
|
67
|
+
# This can happen if invalid credentials are given
|
68
|
+
else
|
69
|
+
raise LoginFailed, "Cherwell returned false status"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Log out of Cherwell.
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
# Logout response as reported by Cherwell.
|
78
|
+
#
|
79
|
+
def logout
|
80
|
+
return @client.logout
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get the Cherwell incident with the given public ID, and return an
|
84
|
+
# Incident object.
|
85
|
+
#
|
86
|
+
# @return [Incident]
|
87
|
+
#
|
88
|
+
def incident(id)
|
89
|
+
incident_xml = get_object_xml('Incident', id)
|
90
|
+
return Incident.new(incident_xml.to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Get the Cherwell task with the given public ID, and return a Task
|
94
|
+
# object.
|
95
|
+
#
|
96
|
+
# @return [Task]
|
97
|
+
#
|
98
|
+
def task(id)
|
99
|
+
task_xml = get_object_xml('Task', id)
|
100
|
+
return Task.new(task_xml.to_s)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get a business object based on its public ID or RecID, and return the
|
104
|
+
# XML response.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# incident_xml = cherwell.get_object_xml(
|
108
|
+
# 'Incident', '12345')
|
109
|
+
#
|
110
|
+
# note_xml = cherwell.get_object_xml(
|
111
|
+
# 'JournalNote', '93bd7e3e067f1dafb454d14cb399dda1ef3f65d36d')
|
112
|
+
#
|
113
|
+
# @param [String] object_type
|
114
|
+
# What type of object to fetch, for example "Incident", "Customer",
|
115
|
+
# "Task", "JournalNote", "SLA" etc. May also be the `IDREF` of an
|
116
|
+
# object type. Cherwell's API knows this as `busObNameOrId`.
|
117
|
+
# @param [String] id
|
118
|
+
# The public ID or RecID of the object. If this is 32 characters or
|
119
|
+
# more, it's assumed to be a RecID. For incidents, the public ID is a
|
120
|
+
# numeric identifier like "50629", while the RecID is a long
|
121
|
+
# hexadecimal string like "93bd7e3e067f1dafb454d14cb399dda1ef3f65d36d".
|
122
|
+
#
|
123
|
+
# This invokes `GetBusinessObject` or `GetBusinessObjectByPublicId`,
|
124
|
+
# depending on the length of `id`. The returned XML is the content of the
|
125
|
+
# `GetBusinessObjectResult` or `GetBusinessObjectByPublicIdResult`.
|
126
|
+
#
|
127
|
+
# @return [String]
|
128
|
+
# Raw XML response string.
|
129
|
+
#
|
130
|
+
def get_object_xml(object_type, id)
|
131
|
+
# Assemble the SOAP body
|
132
|
+
body = {:busObNameOrId => object_type}
|
133
|
+
|
134
|
+
# If ID is really long, it's probably a RecID
|
135
|
+
if id.to_s.length >= 32
|
136
|
+
method = :get_business_object
|
137
|
+
body[:busObRecId] = id
|
138
|
+
# Otherwise, assume it's a public ID
|
139
|
+
else
|
140
|
+
method = :get_business_object_by_public_id
|
141
|
+
body[:busObPublicId] = id
|
142
|
+
end
|
143
|
+
|
144
|
+
begin
|
145
|
+
result = @client.call_wrap(method, body)
|
146
|
+
rescue Savon::Error => e
|
147
|
+
raise SoapError, e.message
|
148
|
+
else
|
149
|
+
return result
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Update a given Cherwell object by submitting its XML to the SOAP
|
155
|
+
# interface.
|
156
|
+
#
|
157
|
+
# @param [String] object_type
|
158
|
+
# The kind of object you're updating ('Incident', 'Task'), or the
|
159
|
+
# IDREF of the object type.
|
160
|
+
# @param [String] id
|
161
|
+
# The public ID of the object
|
162
|
+
# @param [String] xml
|
163
|
+
# The XML body containing all the updates you want to make
|
164
|
+
#
|
165
|
+
def update_object_xml(object_type, id, xml)
|
166
|
+
@client.update_business_object_by_public_id({
|
167
|
+
:busObNameOrId => object_type,
|
168
|
+
:busObPublicId => id,
|
169
|
+
:updateXml => xml
|
170
|
+
})
|
171
|
+
return last_error
|
172
|
+
end
|
173
|
+
|
174
|
+
# Save the given Cherwell incident
|
175
|
+
def save_incident(incident)
|
176
|
+
update_object_xml('Incident', incident.id, incident.to_xml)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Save the given Cherwell task
|
180
|
+
def save_task(task)
|
181
|
+
update_object_xml('Task', task.id, task.to_xml)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Create a new Cherwell incident with the given data. If creation
|
185
|
+
# succeeds, return the Incident instance; otherwise, return `nil`.
|
186
|
+
#
|
187
|
+
# @example
|
188
|
+
# create_incident(
|
189
|
+
# :service => 'Consulting Services',
|
190
|
+
# :sub_category => 'New/Modified Functionality',
|
191
|
+
# :priority => '4',
|
192
|
+
# )
|
193
|
+
#
|
194
|
+
# @param [Hash] data
|
195
|
+
# Incident fields to initialize. All required fields must be filled
|
196
|
+
# in, or creation will fail. At minimum this includes `:service`,
|
197
|
+
# `:sub_category`, and `:priority`.
|
198
|
+
#
|
199
|
+
# @return [Incident, nil]
|
200
|
+
# The created incident, or `nil` if creation failed.
|
201
|
+
#
|
202
|
+
def create_incident(data)
|
203
|
+
incident = Incident.create(data)
|
204
|
+
result = @client.create_business_object({
|
205
|
+
:busObNameOrId => 'Incident',
|
206
|
+
:creationXml => incident.to_xml
|
207
|
+
})
|
208
|
+
|
209
|
+
# Result contains the public ID of the new incident, or nil if the
|
210
|
+
# incident-creation failed.
|
211
|
+
if !result.nil?
|
212
|
+
incident['IncidentID'] = result
|
213
|
+
return incident
|
214
|
+
else
|
215
|
+
return nil
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Get the last error reported by Cherwell.
|
220
|
+
#
|
221
|
+
# @return [String, nil]
|
222
|
+
# Text of the last error that occurred, or `nil` if there was no error.
|
223
|
+
#
|
224
|
+
def last_error
|
225
|
+
return @client.get_last_error
|
226
|
+
end
|
227
|
+
|
228
|
+
end # class Cherwell
|
229
|
+
end # module Cherby
|
230
|
+
|