docusign_rest 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e077e5af78df26b9158e39d0a37b138693f9634
4
- data.tar.gz: 566af05a3a7a3c1fe7dc351f7e25a168f62a2b5a
3
+ metadata.gz: 67460cc1df129f721affa3f822e3019a0b648be3
4
+ data.tar.gz: 461927419841a056220b26a8ee9ff64c1ef20d54
5
5
  SHA512:
6
- metadata.gz: d2710846c68cc0cb9a9f09b5b77b9645e57d36dac7a679247f8792fe51f277a3af372bee303a72cb3e853cebd36348b8899483df1cdd6d8e7fbb782fa8cb1ce5
7
- data.tar.gz: 326e18ab520f022027393a9648953bc5046a7aae5d03fea5924e9d06294168b825825642c6a6a7ee7d1811e8cb24300ea77a03e8c574fb76d6343c442ff46ca8
6
+ metadata.gz: 6e7c0c96f3a815fb4048db7f8379e36df690c5dd1884f346a93863efc8f0937fd79aaf5b3fdd6c98ee9ae86f10e5769601262b7b99c455750d1f87475f7d849d
7
+ data.tar.gz: 3a3f5bcac8407d7be4b43f217f34d90114b718b06e0935dbd79bb5f171b475bc3fdafdbbe27bcebeefd51fca6407448cf088cbf03d10dee12219548b498ec250
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.3.0 May 11 2017
4
+
5
+ ### Features:
6
+ * Add brandId and allow_reassign options to DocusignRest::Client#create_envelope_from_template and DocusignRest::Client#create_envelope_from_composite_template (Jayan Jacob)
7
+ * Implement DocusignRest::Client#add_envelope_certified_deliveries (Moses Dwaram)
8
+ * Add envelopeIds option to DocusignRest::Client#get_envelope_statuses (Amit Chakradeo)
9
+ * Add recipientEvents option to event notification payload (Guillermo Wu)
10
+ * Added logging of each call to support Docusign API certification (Jon Witucki)
11
+ * Enable requireSignOnPaper option for a recipient in a composite template (Tom Copeland)
12
+ * Support routingOrder option when generating signers (Guillaume Dott)
13
+ * Support arbitrary parameters to DocusignRest::Client#get_combined_document_from_envelope (Coley Brown)
14
+ * Support event notifications in DocusignRest::Client#get_combined_document_from_envelope (Maxime Orefice)
15
+ * Support wet_sign option on DocusignRest::Client#create_envelope_from_document (Sergio Cambra)
16
+ * Support signHereTabs on DocusignRest::Client#get_inline_signers (Chris Sturm)
17
+ * Support additional tab options (Hoang Le)
18
+
19
+ ### Misc:
20
+ * Replace monkeypatch with argument usage (Jean-Philippe Moal)
21
+ * Bumped minimum Ruby version to 2.1.0. (Tom Copeland)
22
+ * DocusignRest::Client#void_envelope now returns a JSON object rather than a request object (Tom Copeland)
23
+
3
24
  ## v0.2.0 April 28 2017
4
25
 
5
26
  ### Features:
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Jon Kinney
1
+ Copyright (c) 2012-2017 Jon Kinney
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # DocusignRest
2
2
 
3
- This 'wrapper gem' hooks a Ruby app (currently only tested with Rails) up to the [DocuSign](http://www.docusign.com/) [REST API](http://www.docusign.com/developer-center) to allow for embedded signing.
3
+ This 'wrapper gem' hooks a Ruby app (currently only tested with Rails) up to the [DocuSign](http://www.docusign.com/) REST API ([docs](https://docs.docusign.com/esign/), [API explorer](https://apiexplorer.docusign.com/#/esign/restapi)) to allow for embedded signing.
4
4
 
5
5
  ## Installation
6
6
 
@@ -65,23 +65,38 @@ There are several other configuration options available but the two most likely
65
65
 
66
66
  ```ruby
67
67
  config.endpoint = 'https://docusign.net/restapi'
68
- config.api_version = 'v1'
68
+ config.api_version = 'v2'
69
69
  ```
70
70
 
71
- The above options allow you to change the endpoint (to be able to hit the production DocuSign API, for instance) and to modify the API version you wish to use. If there is a big change in the API it's likely that this gem will need to be updated to leverage changes on the DocuSign side. However, it doesn't hurt to provide the option in case there are several minor updates that do not break functionality but would otherwise require a new gem release. These config options have existed since the gem was created, but in v0.0.3 and above, the options are auto-generated in the config file as comments to make them easier to discover.
72
-
71
+ The above options allow you to change the endpoint (to be able to hit the production DocuSign API, for instance) and to modify the API version you wish to use.
73
72
 
74
73
  ## Usage
75
74
 
76
- The docusign\_rest gem makes creating multipart POST (aka file upload) requests to the DocuSign REST API dead simple. It's built on top of Net:HTTP and utilizes the [multipart-post](https://github.com/nicksieger/multipart-post) gem to assist with formatting the multipart requests. The DocuSign REST API requires that all files be embedded as JSON directly in the request body (not the body\_stream like multipart-post does by default) so the docusign\_rest gem takes care of [setting that up for you](https://github.com/j2fly/docusign_rest/blob/master/lib/docusign_rest/client.rb#L397).
77
-
78
- This gem also monkey patches one small part of multipart-post to inject some header values and formatting that DocuSign requires. If you would like to see the monkey patched code please take a look at [lib/multipart-post/parts.rb](https://github.com/j2fly/docusign_rest/blob/master/lib/multipart_post/parts.rb). It's only re-opening one method, but feel free to make sure you understand that code if it concerns you.
75
+ The docusign\_rest gem makes creating multipart POST (aka file upload) requests to the DocuSign REST API dead simple. It's built on top of `Net::HTTP` and utilizes the [multipart-post](https://github.com/nicksieger/multipart-post) gem to assist with formatting the multipart requests. The DocuSign REST API requires that all files be embedded as JSON directly in the request body (not the body\_stream like multipart-post does by default) so the docusign\_rest gem takes care of [setting that up for you](https://github.com/j2fly/docusign_rest/blob/master/lib/docusign_rest/client.rb#L397).
79
76
 
80
77
  ### Examples
81
78
 
82
- * These examples assume you have already run the `docusign_rest:generate_config` rake task and have the configure block properly setup in an initializer with your username, password, integrator\_key, and account\_id.
83
79
  * Unless noted otherwise, these requests return the JSON parsed body of the response so you can index the returned hash directly. For example: `template_response["templateId"]`.
84
80
 
81
+ #### Situations
82
+
83
+ ** In the context of a Rails app **
84
+
85
+ This is how most people are using this gem - they've got a Rails app that's doing things with the Docusign API. In that case, these examples assume you have already set up a docusign account, have run the `docusign_rest:generate_config` rake task, and have the configure block properly setup in an initializer with your username, password, integrator\_key, and account\_id.
86
+
87
+ ** In the context of this gem as a standalone project **
88
+
89
+ Ideally this gem will be independent of Rails. If that's your situation, there won't be a Rails initializer so your code will need to load the API authentication credentials. You will want to do something like:
90
+
91
+ ```ruby
92
+ load 'test/docusign_login_config.rb'
93
+ client = DocusignRest::Client.new
94
+ client.get_account_id
95
+ document_envelope_response = client.create_envelope_from_document( # etc etc
96
+ ```
97
+
98
+ #### Example code
99
+
85
100
  **Getting account_id:**
86
101
 
87
102
  ```ruby
@@ -89,10 +104,45 @@ client = DocusignRest::Client.new
89
104
  puts client.get_account_id
90
105
  ```
91
106
 
92
-
93
107
  **Creating an envelope from a document:**
94
108
 
95
- Note: In the example below there are two sign here tabs for the user with a role of 'Attorney'. There are also two documents attached to the envelope, however, this exact configuration would only allow for signature on the first document. If you need signature for a second document, you'll need to add further options, namely: `document_id: 2` in one of the sign_here_tabs so that DocuSign knows where to embed that signature tab.
109
+ Here's how to create an envelope from a local PDF file and open a browser to the URL for the recipient:
110
+
111
+ ```ruby
112
+ client = DocusignRest::Client.new
113
+ document_envelope_response = client.create_envelope_from_document(
114
+ email: {
115
+ subject: "test email subject",
116
+ body: "this is the email body and it's large!"
117
+ },
118
+ # If embedded is set to true in the signers array below, emails
119
+ # don't go out to the signers and you can embed the signature page in an
120
+ # iframe by using the client.get_recipient_view method
121
+ signers: [
122
+ {
123
+ embedded: true,
124
+ name: 'Joe Dimaggio',
125
+ email: 'joe.dimaggio@example.org',
126
+ role_name: 'Issuer',
127
+ sign_here_tabs: [
128
+ {
129
+ anchor_string: 'sign here',
130
+ anchor_x_offset: '-30',
131
+ anchor_y_offset: '35'
132
+ }
133
+ ]
134
+ },
135
+ ],
136
+ files: [
137
+ {path: '/Absolute/path/to/test.pdf', name: 'test.pdf'},
138
+ ],
139
+ status: 'sent'
140
+ )
141
+ url = client.get_recipient_view(envelope_id: document_envelope_response['envelopeId'], name: "Joe Dimaggio", email: "joe.dimaggio@example.org", return_url: 'http://google.com')['url']
142
+ `open #{url}`
143
+ ```
144
+
145
+ Note: In the example below there are two sign here tabs for the user with a role of 'Attorney'. There are also two documents attached to the envelope, however, this exact configuration would only allow for signature on the first document. If you need signature for a second document, you'll need to add further options, namely: `document_id: 2` in one of the `sign_here_tabs` so that DocuSign knows where to embed that signature tab.
96
146
 
97
147
  ```ruby
98
148
  client = DocusignRest::Client.new
@@ -103,7 +153,7 @@ document_envelope_response = client.create_envelope_from_document(
103
153
  },
104
154
  # If embedded is set to true in the signers array below, emails
105
155
  # don't go out to the signers and you can embed the signature page in an
106
- # iFrame by using the client.get_recipient_view method
156
+ # iframe by using the client.get_recipient_view method
107
157
  signers: [
108
158
  {
109
159
  embedded: true,
@@ -112,9 +162,9 @@ document_envelope_response = client.create_envelope_from_document(
112
162
  role_name: 'Issuer',
113
163
  sign_here_tabs: [
114
164
  {
115
- anchor_string: 'sign_here_1',
116
- anchor_x_offset: '140',
117
- anchor_y_offset: '8'
165
+ anchor_string: 'sign here',
166
+ anchor_x_offset: '-30',
167
+ anchor_y_offset: '35'
118
168
  }
119
169
  ]
120
170
  },
@@ -218,8 +268,6 @@ client = DocusignRest::Client.new
218
268
 
219
269
  **Creating an envelope from a template using custom tabs:**
220
270
 
221
- Note: This feature is not supported in 'v1' of the REST API
222
-
223
271
  ```ruby
224
272
  client = DocusignRest::Client.new
225
273
  @envelope_response = client.create_envelope_from_template(
@@ -296,14 +344,14 @@ client.get_document_from_envelope(
296
344
  )
297
345
  ```
298
346
 
299
- ## Breaking out of the iFrame after signing
347
+ ## Breaking out of the iframe after signing
300
348
 
301
- In order to return to your application after the signing process is complete it's important to have a way to evaluate whether or not the signing was successful and then do something about each case. The way I set this up was to render the embedded signing iframe for a controller action called 'embedded_signing' and specify the return_url of the `client.get_recipient_view` API call to be something like: http://myapp.com/docusign_response. Then in the same controller as the embedded_signing method, define the docusign_response method. This is where the signing process will redirect to after the user is done interacting with the DocuSign iframe. DocuSign passes a query string parameter in the return_url named 'event' and you can check like so: `if params[:event] == "signing_complete"` then you'll want to redirect to another spot in your app, not in the iframe. To do so, we need to use JavaScript to access the iframe's parent and set it's location to the path of our choosing. To do this, instanciate the DocusignRest::Utility class and call the breakout_path method like this:
349
+ In order to return to your application after the signing process is complete it's important to have a way to evaluate whether or not the signing was successful and then do something about each case. The way I set this up was to render the embedded signing iframe for a controller action called 'embedded_signing' and specify the return_url of the `client.get_recipient_view` API call to be something like: http://myapp.com/docusign_response. Then in the same controller as the embedded_signing method, define the docusign_response method. This is where the signing process will redirect to after the user is done interacting with the DocuSign iframe. DocuSign passes a query string parameter in the return_url named 'event' and you can check like so: `if params[:event] == "signing_complete"` then you'll want to redirect to another spot in your app, not in the iframe. To do so, we need to use JavaScript to access the iframe's parent and set it's location to the path of our choosing. To do this, instantiate the `DocusignRest::Utility` class and call the breakout_path method like this:
302
350
 
303
351
  ```ruby
304
352
  class SomeController < ApplicationController
305
353
 
306
- # the view corresponding to this action has the iFrame in it with the
354
+ # the view corresponding to this action has the iframe in it with the
307
355
  # @url as it's src. @envelope_response is populated from either:
308
356
  # @envelope_response = client.create_envelope_from_document
309
357
  # or
@@ -349,10 +397,6 @@ In order to run the tests you'll need to register for a (free) DocuSign develope
349
397
 
350
398
  This calls a rake task which adds a non-version controlled file in the test folder called `docusign_login_config.rb` which holds your account specific credentials and is required in order to hit the test API through the test suite.
351
399
 
352
- **Guard**
353
-
354
- Simply run 'guard' from the root directory of the repository to have the test suite executed automatically as you make changes.
355
-
356
400
  **VCR**
357
401
 
358
402
  The test suite uses VCR and is configured to record all requests by using the 'all' configuration option surrounding each API request. If you want to speed up the test suite locally for new feature development, you may want to change the VCR config record setting to 'once' temporarily which will not write a new YAML file for each request each time you hit the API and significantly speed up the tests. However, this can lead to false passing tests as the gem changes so it's recommended that you ensure all tests pass by actually hitting the API before submitting a pull request.
@@ -2,27 +2,25 @@
2
2
  require File.expand_path('../lib/docusign_rest/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.authors = ['Jon Kinney']
6
- gem.email = ['jonkinney@gmail.com']
5
+ gem.authors = ['Jon Kinney', 'Tom Copeland']
6
+ gem.email = ['jonkinney@gmail.com', 'tom@thomasleecopeland.com']
7
7
  gem.description = %q{Hooks a Rails app up to the DocuSign service through the DocuSign REST API}
8
8
  gem.summary = %q{Use this gem to embed signing of documents in a Rails app through the DocuSign REST API}
9
9
  gem.homepage = "https://github.com/jondkinney/docusign_rest"
10
10
 
11
- gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11
+ gem.files = `git ls-files -z`.split("\x0").reject {|p| p.match(%r{^(test/|test.*pdf|cacert.pem|.gitignore)}) }
14
12
  gem.name = 'docusign_rest'
15
13
  gem.require_paths = ['lib']
16
14
  gem.version = DocusignRest::VERSION
17
15
  gem.licenses = ['MIT']
18
16
 
19
- gem.required_ruby_version = '>= 1.9.2'
17
+ gem.required_ruby_version = '>= 2.1.0'
20
18
 
21
19
  gem.add_dependency('multipart-post', '>= 1.2')
22
20
  gem.add_dependency('json')
23
21
  gem.add_development_dependency('rake')
22
+ gem.add_development_dependency('byebug')
24
23
  gem.add_development_dependency('minitest', '~> 4.0')
25
- gem.add_development_dependency('guard-minitest')
26
24
  gem.add_development_dependency('rb-fsevent', '~> 0.9')
27
25
  gem.add_development_dependency('turn')
28
26
  gem.add_development_dependency('pry')
@@ -4,7 +4,6 @@ require_relative 'docusign_rest/client'
4
4
  require_relative 'docusign_rest/utility'
5
5
  require 'multipart_post' #require the multipart-post gem itself
6
6
  require 'net/http/post/multipart' #require the multipart-post net/http/post/multipart monkey patch
7
- require_relative 'multipart_post/parts' #require my monkey patched parts.rb which adjusts the build_part method
8
7
  require 'net/http'
9
8
  require 'json'
10
9
 
@@ -7,6 +7,7 @@ module DocusignRest
7
7
  # Define the same set of accessors as the DocusignRest module
8
8
  attr_accessor *Configuration::VALID_CONFIG_KEYS
9
9
  attr_accessor :docusign_authentication_headers, :acct_id
10
+ attr_accessor :previous_call_log
10
11
 
11
12
  def initialize(options={})
12
13
  # Merge the config values from the module and those passed to the client.
@@ -38,6 +39,9 @@ module DocusignRest
38
39
  # the instance var @account_id because that'll override the attr_accessor
39
40
  # that is automatically configured for the configure block
40
41
  @acct_id = account_id
42
+
43
+ #initialize the log cache
44
+ @previous_call_log = []
41
45
  end
42
46
 
43
47
 
@@ -143,6 +147,7 @@ module DocusignRest
143
147
 
144
148
  http = initialize_net_http_ssl(uri)
145
149
  response = http.request(request)
150
+ generate_log(request, response, uri)
146
151
  JSON.parse(response.body)
147
152
  end
148
153
 
@@ -169,7 +174,9 @@ module DocusignRest
169
174
  uri = build_uri('/login_information')
170
175
  request = Net::HTTP::Get.new(uri.request_uri, headers(options[:headers]))
171
176
  http = initialize_net_http_ssl(uri)
172
- http.request(request)
177
+ response = http.request(request)
178
+ generate_log(request, response, uri)
179
+ response
173
180
  end
174
181
 
175
182
 
@@ -200,7 +207,7 @@ module DocusignRest
200
207
  # hashes with commas
201
208
  #
202
209
  # embedded - Tells DocuSign if this is an embedded signer which determines
203
- # weather or not to deliver emails. Also lets us authenticate
210
+ # whether or not to deliver emails. Also lets us authenticate
204
211
  # them when they go to do embedded signing. Behind the scenes
205
212
  # this is setting the clientUserId value to the signer's email.
206
213
  # name - The name of the signer
@@ -209,8 +216,6 @@ module DocusignRest
209
216
  # tabs - Array of tab pairs grouped by type (Example type: 'textTabs')
210
217
  # { textTabs: [ { tabLabel: "label", name: "name", value: "value" } ] }
211
218
  #
212
- # NOTE: The 'tabs' option is NOT supported in 'v1' of the REST API
213
- #
214
219
  # Returns a hash of users that need to be embedded in the template to
215
220
  # create an envelope
216
221
  def get_template_roles(signers)
@@ -239,6 +244,17 @@ module DocusignRest
239
244
  template_roles
240
245
  end
241
246
 
247
+ def get_sign_here_tabs(tabs)
248
+ Array(tabs).map do |tab|
249
+ {
250
+ documentId: tab[:document_id],
251
+ recipientId: tab[:recipient_id],
252
+ anchorString: tab[:anchor_string],
253
+ anchorXOffset: tab[:anchorXOffset],
254
+ anchorYOffset: tab[:anchorYOffset]
255
+ }
256
+ end
257
+ end
242
258
 
243
259
  # TODO (2014-02-03) jonk => document
244
260
  def get_signer_tabs(tabs)
@@ -260,14 +276,20 @@ module DocusignRest
260
276
  return {} unless event_notification
261
277
  {
262
278
  useSoapInterface: event_notification[:use_soap_interface] || false,
263
- includeCertificatWithSoap: event_notification[:include_certificate_with_soap] || false,
279
+ includeCertificateWithSoap: event_notification[:include_certificate_with_soap] || false,
264
280
  url: event_notification[:url],
265
281
  loggingEnabled: event_notification[:logging],
266
- 'EnvelopeEvents' => Array(event_notification[:envelope_events]).map do |envelope_event|
282
+ 'envelopeEvents' => Array(event_notification[:envelope_events]).map do |envelope_event|
267
283
  {
268
284
  includeDocuments: envelope_event[:include_documents] || false,
269
285
  envelopeEventStatusCode: envelope_event[:envelope_event_status_code]
270
286
  }
287
+ end,
288
+ 'recipientEvents' => Array(event_notification[:recipient_events]).map do |recipient_event|
289
+ {
290
+ includeDocuments: recipient_event[:include_documents] || false,
291
+ recipientEventStatusCode: recipient_event[:recipient_event_status_code]
292
+ }
271
293
  end
272
294
  }
273
295
  end
@@ -283,7 +305,7 @@ module DocusignRest
283
305
  # email - The signer's email
284
306
  # name - The signer's name
285
307
  # embedded - Tells DocuSign if this is an embedded signer which
286
- # determines weather or not to deliver emails. Also
308
+ # determines whether or not to deliver emails. Also
287
309
  # lets us authenticate them when they go to do
288
310
  # embedded signing. Behind the scenes this is setting
289
311
  # the clientUserId value to the signer's email.
@@ -312,7 +334,7 @@ module DocusignRest
312
334
  name: signer[:name],
313
335
  accessCode: '',
314
336
  addAccessCodeToEmail: false,
315
- customFields: nil,
337
+ customFields: signer[:custom_fields],
316
338
  iDCheckConfigurationName: nil,
317
339
  iDCheckInformationInput: nil,
318
340
  inheritEmailNotificationConfiguration: false,
@@ -322,7 +344,7 @@ module DocusignRest
322
344
  recipientId: "#{index + 1}",
323
345
  requireIdLookup: false,
324
346
  roleName: signer[:role_name],
325
- routingOrder: index + 1,
347
+ routingOrder: signer[:routing_order] || index + 1,
326
348
  socialAuthentications: nil
327
349
  }
328
350
 
@@ -355,7 +377,7 @@ module DocusignRest
355
377
  fullNameTabs: get_tabs(signer[:full_name_tabs], options, index),
356
378
  listTabs: get_tabs(signer[:list_tabs], options, index),
357
379
  noteTabs: nil,
358
- numberTabs: nil,
380
+ numberTabs: get_tabs(signer[:number_tabs], options, index),
359
381
  radioGroupTabs: get_tabs(signer[:radio_group_tabs], options, index),
360
382
  initialHereTabs: get_tabs(signer[:initial_here_tabs], options.merge!(initial_here_tab: true), index),
361
383
  signHereTabs: get_tabs(signer[:sign_here_tabs], options.merge!(sign_here_tab: true), index),
@@ -373,6 +395,72 @@ module DocusignRest
373
395
  end
374
396
 
375
397
 
398
+ # Internal: people to be Carbon Copied on the document that is created
399
+ # https://docs.docusign.com/esign/restapi/Envelopes/Envelopes/create/
400
+ #
401
+ # Expecting options to be an array of hashes, with each hash representing a person to carbon copy
402
+ #
403
+ # email - The email of the recipient to be copied on the document
404
+ # name - The name of the recipient
405
+ # signer_count - Used to generate required attributes recipientId and routingOrder which must be unique in the document
406
+ #
407
+ def get_carbon_copies(options, signer_count)
408
+ copies = []
409
+ (options || []).each do |cc|
410
+ signer_count += 1
411
+ raise "Missing required data [:email, :name]" unless (cc[:email] && cc[:name])
412
+ cc.merge!(recipient_id: signer_count, routing_order: signer_count)
413
+ copies << camelize_keys(cc)
414
+ end
415
+ copies
416
+ end
417
+
418
+ # Public: Translate ruby oriented keys to camel cased keys recursively through the hash received
419
+ #
420
+ # The method expects symbol parameters in ruby form ":access_code" and translates them to camel cased "accessCode"
421
+ #
422
+ # example [{access_code: '12345', email_notification: {email_body: 'abcdef'}}] -> [{'accessCode': '12345', 'emailNotification': {'emailBody': 'abcdef'}}]
423
+ #
424
+ def camelize_keys(hash)
425
+ new_hash={}
426
+ hash.each do |k,v|
427
+ new_hash[camelize(k.to_s)] = (v.is_a?(Hash) ? camelize_keys(v) : v)
428
+ end
429
+ new_hash
430
+ end
431
+
432
+ # Generic implementation to avoid having to pull in Rails dependencies
433
+ #
434
+ def camelize(str)
435
+ str.gsub(/_([a-z])/) { $1.upcase }
436
+ end
437
+
438
+ # Internal: takes an array of hashes of certified deliveries
439
+ #
440
+ # email - The recipient email
441
+ # name - The recipient name
442
+ # recipient_id - The recipient's id
443
+ # embedded - Tells DocuSign if this is an embedded recipient which
444
+ # determines whether or not to deliver emails.
445
+ def get_certified_deliveries(certified_deliveries)
446
+ doc_certified_deliveries = []
447
+
448
+ certified_deliveries.each do |certified_delivery|
449
+ doc_certified_delivery = {
450
+ email: certified_delivery[:email],
451
+ name: certified_delivery[:name],
452
+ recipientId: certified_delivery[:recipient_id]
453
+ }
454
+
455
+ if certified_delivery[:embedded]
456
+ doc_certified_delivery[:clientUserId] = certified_delivery[:client_id] || certified_delivery[:email]
457
+ end
458
+
459
+ doc_certified_deliveries << doc_certified_delivery
460
+ end
461
+ doc_certified_deliveries
462
+ end
463
+
376
464
  # TODO (2014-02-03) jonk => document
377
465
  def get_tabs(tabs, options, index)
378
466
  tab_array = []
@@ -412,6 +500,11 @@ module DocusignRest
412
500
  tab_hash[:width] = tab[:width] if tab[:width]
413
501
  tab_hash[:height] = tab[:height] if tab[:height]
414
502
  tab_hash[:value] = tab[:value] if tab[:value]
503
+ tab_hash[:fontSize] = tab[:font_size] if tab[:font_size]
504
+ tab_hash[:fontColor] = tab[:font_color] if tab[:font_color]
505
+ tab_hash[:bold] = tab[:bold] if tab[:bold]
506
+ tab_hash[:italic] = tab[:italic] if tab[:italic]
507
+ tab_hash[:underline] = tab[:underline] if tab[:underline]
415
508
  tab_hash[:selected] = tab[:selected] if tab[:selected]
416
509
 
417
510
  tab_hash[:locked] = tab[:locked] || false
@@ -421,6 +514,9 @@ module DocusignRest
421
514
  tab_hash[:groupName] = tab[:group_name] if tab.key?(:group_name)
422
515
  tab_hash[:radios] = get_tabs(tab[:radios], options, index) if tab.key?(:radios)
423
516
 
517
+ tab_hash[:validationMessage] = tab[:validation_message] if tab[:validation_message]
518
+ tab_hash[:validationPattern] = tab[:validation_pattern] if tab[:validation_pattern]
519
+
424
520
  tab_array << tab_hash
425
521
  end
426
522
  tab_array
@@ -508,7 +604,6 @@ module DocusignRest
508
604
  # Returns an array of server template hashes
509
605
  def get_composite_template(server_template_ids, signers, files)
510
606
  composite_array = []
511
- index = 0
512
607
  server_template_ids.each_with_index do |template_id, idx|
513
608
  server_template_hash = {
514
609
  sequence: (idx+1).to_s,
@@ -545,12 +640,14 @@ module DocusignRest
545
640
  recipientId: signer[:recipient_id],
546
641
  roleName: signer[:role_name],
547
642
  clientUserId: signer[:client_id] || signer[:email],
643
+ requireSignOnPaper: signer[:require_sign_on_paper] || false,
548
644
  tabs: {
549
645
  textTabs: get_signer_tabs(signer[:text_tabs]),
550
646
  checkboxTabs: get_signer_tabs(signer[:checkbox_tabs]),
551
647
  numberTabs: get_signer_tabs(signer[:number_tabs]),
552
648
  fullNameTabs: get_signer_tabs(signer[:fullname_tabs]),
553
- dateTabs: get_signer_tabs(signer[:date_tabs])
649
+ dateTabs: get_signer_tabs(signer[:date_tabs]),
650
+ signHereTabs: get_sign_here_tabs(signer[:sign_here_tabs])
554
651
  }
555
652
  }
556
653
  signers_array << signers_hash
@@ -577,6 +674,9 @@ module DocusignRest
577
674
  # headers={} - The fully merged, final request headers
578
675
  # boundary - Optional: you can give the request a custom boundary
579
676
  #
677
+
678
+ headers = headers.dup.merge(parts: {post_body: {'Content-Type' => 'application/json'}})
679
+
580
680
  request = Net::HTTP::Post::Multipart.new(
581
681
  uri.request_uri,
582
682
  { post_body: post_body }.merge(file_params),
@@ -603,19 +703,23 @@ module DocusignRest
603
703
  # file_name - The name you want to give to the file you are uploading
604
704
  # content_type - (for the request body) application/json is what DocuSign
605
705
  # is expecting
606
- # email_subject - (Optional) short subject line for the email
607
- # email_body - (Optional) custom text that will be injected into the
706
+ # email[subject] - (Optional) short subject line for the email
707
+ # email[body] - (Optional) custom text that will be injected into the
608
708
  # DocuSign generated email
609
709
  # signers - A hash of users who should receive the document and need
610
710
  # to sign it. More info about the options available for
611
711
  # this method are documented above it's method definition.
712
+ # carbon_copies - An array of hashes that includes users names and email who
713
+ # should receive a copy of the document once it is complete.
612
714
  # status - Options include: 'sent', 'created', 'voided' and determine
613
715
  # if the envelope is sent out immediately or stored for
614
716
  # sending at a later time
615
717
  # customFields - (Optional) A hash of listCustomFields and textCustomFields.
616
718
  # Each contains an array of corresponding customField hashes.
617
719
  # For details, please see: http://bit.ly/1FnmRJx
618
- # headers - Allows a client to pass in some
720
+ # headers - Allows a client to pass in some headers
721
+ # web_sign - (Optional) If true, the signer is allowed to print the
722
+ # document and sign it on paper. False if not defined.
619
723
  #
620
724
  # Returns a JSON parsed response object containing:
621
725
  # envelopeId - The envelope's ID
@@ -626,16 +730,20 @@ module DocusignRest
626
730
  ios = create_file_ios(options[:files])
627
731
  file_params = create_file_params(ios)
628
732
 
629
- post_body = {
733
+ post_hash = {
630
734
  emailBlurb: "#{options[:email][:body] if options[:email]}",
631
735
  emailSubject: "#{options[:email][:subject] if options[:email]}",
632
736
  documents: get_documents(ios),
633
737
  recipients: {
634
- signers: get_signers(options[:signers])
738
+ signers: get_signers(options[:signers]),
739
+ carbonCopies: get_carbon_copies(options[:carbon_copies],options[:signers].size)
635
740
  },
741
+ eventNotification: get_event_notification(options[:event_notification]),
636
742
  status: "#{options[:status]}",
637
743
  customFields: options[:custom_fields]
638
- }.to_json
744
+ }
745
+ post_hash[:enableWetSign] = options[:wet_sign] if options.has_key? :web_sign
746
+ post_body = post_hash.to_json
639
747
 
640
748
  uri = build_uri("/accounts/#{acct_id}/envelopes")
641
749
 
@@ -646,10 +754,10 @@ module DocusignRest
646
754
  )
647
755
 
648
756
  response = http.request(request)
757
+ generate_log(request, response, uri)
649
758
  JSON.parse(response.body)
650
759
  end
651
760
 
652
-
653
761
  # Public: allows a template to be dynamically created with several options.
654
762
  #
655
763
  # files - An array of hashes of file parameters which will be used
@@ -706,6 +814,7 @@ module DocusignRest
706
814
  )
707
815
 
708
816
  response = http.request(request)
817
+ generate_log(request, response, uri)
709
818
  JSON.parse(response.body)
710
819
  end
711
820
 
@@ -720,6 +829,7 @@ module DocusignRest
720
829
  http = initialize_net_http_ssl(uri)
721
830
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
722
831
  response = http.request(request)
832
+ generate_log(request, response, uri)
723
833
  JSON.parse(response.body)
724
834
  end
725
835
 
@@ -755,9 +865,12 @@ module DocusignRest
755
865
  emailBlurb: options[:email][:body],
756
866
  emailSubject: options[:email][:subject],
757
867
  templateId: options[:template_id],
868
+ enableWetSign: options[:wet_sign],
869
+ brandId: options[:brand_id],
758
870
  eventNotification: get_event_notification(options[:event_notification]),
759
871
  templateRoles: get_template_roles(options[:signers]),
760
- customFields: options[:custom_fields]
872
+ customFields: options[:custom_fields],
873
+ allowReassign: options[:allow_reassign]
761
874
  }.to_json
762
875
 
763
876
  uri = build_uri("/accounts/#{acct_id}/envelopes")
@@ -768,6 +881,7 @@ module DocusignRest
768
881
  request.body = post_body
769
882
 
770
883
  response = http.request(request)
884
+ generate_log(request, response, uri)
771
885
  JSON.parse(response.body)
772
886
  end
773
887
 
@@ -782,10 +896,8 @@ module DocusignRest
782
896
  # email/body - Sets the text in the email body
783
897
  # email/subject - Sets the text in the email subject line
784
898
  # files - Sets documents to be used instead of inline or server templates
785
- # template_roles - See the get_template_roles method definition for a list
786
- # of options to pass. Note: for consistency sake we call
787
- # this 'signers' and not 'templateRoles' when we build up
788
- # the request in client code.
899
+ # signers - See get_template_roles/get_inline_signers for a list
900
+ # of options to pass.
789
901
  # headers - Optional hash of headers to merge into the existing
790
902
  # required headers for a multipart request.
791
903
  # server_template_ids - Array of ids for templates uploaded to DocuSign. Templates
@@ -808,6 +920,8 @@ module DocusignRest
808
920
  emailBlurb: "#{options[:email][:body] if options[:email]}",
809
921
  emailSubject: "#{options[:email][:subject] if options[:email]}",
810
922
  status: options[:status],
923
+ brandId: options[:brand_id],
924
+ allowReassign: options[:allow_reassign],
811
925
  compositeTemplates: get_composite_template(options[:server_template_ids], options[:signers], options[:files])
812
926
  }.to_json
813
927
 
@@ -820,6 +934,7 @@ module DocusignRest
820
934
  )
821
935
 
822
936
  response = http.request(request)
937
+ generate_log(request, response, uri)
823
938
  JSON.parse(response.body)
824
939
  end
825
940
 
@@ -842,9 +957,40 @@ module DocusignRest
842
957
  request = Net::HTTP::Post.new(uri.request_uri, headers(content_type))
843
958
 
844
959
  response = http.request(request)
960
+ generate_log(request, response, uri)
845
961
  JSON.parse(response.body)
846
962
  end
847
963
 
964
+ # Public adds the certified delivery recipients (Need to View) for a given envelope
965
+ #
966
+ # envelope_id - ID of the envelope for which you want to retrieve the
967
+ # signer info
968
+ # headers - optional hash of headers to merge into the existing
969
+ # required headers for a multipart request.
970
+ # certified_deliveries - A required hash of all the certified delivery recipients
971
+ # that need to be added to the envelope
972
+ #
973
+ # # The response returns the success or failure of each recipient being added
974
+ # to the envelope and the envelope ID
975
+ def add_envelope_certified_deliveries(options={})
976
+ content_type = { 'Content-Type' => 'application/json' }
977
+ content_type.merge(options[:headers]) if options[:headers]
978
+
979
+ post_body = {
980
+ certifiedDeliveries: get_certified_deliveries(options[:certified_deliveries]),
981
+ }.to_json
982
+
983
+ uri = build_uri("/accounts/#{acct_id}/envelopes/#{options[:envelope_id]}/recipients")
984
+
985
+ http = initialize_net_http_ssl(uri)
986
+
987
+ request = Net::HTTP::Post.new(uri.request_uri, headers(content_type))
988
+ request.body = post_body
989
+
990
+ response = http.request(request)
991
+ generate(request, response, uri)
992
+ JSON.parse(response.body)
993
+ end
848
994
 
849
995
  # Public returns the URL for embedded signing
850
996
  #
@@ -877,6 +1023,7 @@ module DocusignRest
877
1023
  request.body = post_body
878
1024
 
879
1025
  response = http.request(request)
1026
+ generate_log(request, response, uri)
880
1027
  JSON.parse(response.body)
881
1028
  end
882
1029
 
@@ -901,6 +1048,7 @@ module DocusignRest
901
1048
  request.body = { returnUrl: options[:return_url] }.to_json
902
1049
 
903
1050
  response = http.request(request)
1051
+ generate_log(request, response, uri)
904
1052
  JSON.parse(response.body)
905
1053
  end
906
1054
 
@@ -927,7 +1075,7 @@ module DocusignRest
927
1075
  request.body = post_body
928
1076
 
929
1077
  response = http.request(request)
930
-
1078
+ generate_log(request, response, uri)
931
1079
  parsed_response = JSON.parse(response.body)
932
1080
  parsed_response['url']
933
1081
  end
@@ -955,6 +1103,7 @@ module DocusignRest
955
1103
  http = initialize_net_http_ssl(uri)
956
1104
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
957
1105
  response = http.request(request)
1106
+ generate_log(request, response, uri)
958
1107
  JSON.parse(response.body)
959
1108
  end
960
1109
 
@@ -971,6 +1120,7 @@ module DocusignRest
971
1120
  http = initialize_net_http_ssl(uri)
972
1121
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
973
1122
  response = http.request(request)
1123
+ generate_log(request, response, uri)
974
1124
  JSON.parse(response.body)
975
1125
  end
976
1126
 
@@ -985,6 +1135,8 @@ module DocusignRest
985
1135
  # from_to_status - The status of the envelope checked for in the from_date - to_date period.
986
1136
  # Defaults to 'changed'
987
1137
  #
1138
+ # envelope_ids - Comma joined list of envelope_ids which you want to query.
1139
+ #
988
1140
  # status - The current status of the envelope. Defaults to any status.
989
1141
  #
990
1142
  # Returns an array of hashes containing envelope statuses, ids, and similar information.
@@ -992,13 +1144,14 @@ module DocusignRest
992
1144
  content_type = { 'Content-Type' => 'application/json' }
993
1145
  content_type.merge(options[:headers]) if options[:headers]
994
1146
 
995
- query_params = options.slice(:from_date, :to_date, :from_to_status, :status)
1147
+ query_params = options.slice(:from_date, :to_date, :from_to_status, :envelope_ids, :status)
1148
+ # Note that Hash#to_query is an ActiveSupport monkeypatch
996
1149
  uri = build_uri("/accounts/#{acct_id}/envelopes?#{query_params.to_query}")
997
1150
 
998
1151
  http = initialize_net_http_ssl(uri)
999
1152
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1000
1153
  response = http.request(request)
1001
-
1154
+ generate_log(request, response, uri)
1002
1155
  JSON.parse(response.body)
1003
1156
  end
1004
1157
 
@@ -1031,6 +1184,7 @@ module DocusignRest
1031
1184
  http = initialize_net_http_ssl(uri)
1032
1185
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1033
1186
  response = http.request(request)
1187
+ generate_log(request, response, uri)
1034
1188
  return response.body if options[:return_stream]
1035
1189
 
1036
1190
  split_path = options[:local_save_path].split('/')
@@ -1058,7 +1212,7 @@ module DocusignRest
1058
1212
  http = initialize_net_http_ssl(uri)
1059
1213
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1060
1214
  response = http.request(request)
1061
-
1215
+ generate_log(request, response, uri)
1062
1216
  JSON.parse(response.body)
1063
1217
  end
1064
1218
 
@@ -1071,6 +1225,7 @@ module DocusignRest
1071
1225
  # filename itself
1072
1226
  # headers - Optional hash of headers to merge into the existing
1073
1227
  # required headers for a multipart request.
1228
+ # params - Optional params; for example, certificate: true
1074
1229
  #
1075
1230
  # Example
1076
1231
  #
@@ -1086,10 +1241,12 @@ module DocusignRest
1086
1241
  content_type.merge(options[:headers]) if options[:headers]
1087
1242
 
1088
1243
  uri = build_uri("/accounts/#{acct_id}/envelopes/#{options[:envelope_id]}/documents/combined")
1244
+ uri.query = URI.encode_www_form(options[:params]) if options[:params]
1089
1245
 
1090
1246
  http = initialize_net_http_ssl(uri)
1091
1247
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1092
1248
  response = http.request(request)
1249
+ generate_log(request, response, uri)
1093
1250
  return response.body if options[:return_stream]
1094
1251
 
1095
1252
  split_path = options[:local_save_path].split('/')
@@ -1132,7 +1289,7 @@ module DocusignRest
1132
1289
  request = Net::HTTP::Put.new(uri.request_uri, headers(content_type))
1133
1290
  request.body = post_body
1134
1291
  response = http.request(request)
1135
-
1292
+ generate_log(request, response, uri)
1136
1293
  response
1137
1294
  end
1138
1295
 
@@ -1156,7 +1313,7 @@ module DocusignRest
1156
1313
  http = initialize_net_http_ssl(uri)
1157
1314
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1158
1315
  response = http.request(request)
1159
-
1316
+ generate_log(request, response, uri)
1160
1317
  JSON.parse(response.body)
1161
1318
  end
1162
1319
 
@@ -1170,6 +1327,7 @@ module DocusignRest
1170
1327
  http = initialize_net_http_ssl(uri)
1171
1328
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1172
1329
  response = http.request(request)
1330
+ generate_log(request, response, uri)
1173
1331
  JSON.parse(response.body)
1174
1332
  end
1175
1333
 
@@ -1211,6 +1369,7 @@ module DocusignRest
1211
1369
  http = initialize_net_http_ssl(uri)
1212
1370
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1213
1371
  response = http.request(request)
1372
+ generate_log(request, response, uri)
1214
1373
  JSON.parse(response.body)
1215
1374
  end
1216
1375
 
@@ -1228,6 +1387,7 @@ module DocusignRest
1228
1387
  request = Net::HTTP::Post.new(uri.request_uri, headers(content_type))
1229
1388
  request.body = post_body
1230
1389
  response = http.request(request)
1390
+ generate_log(request, response, uri)
1231
1391
  JSON.parse(response.body)
1232
1392
  end
1233
1393
 
@@ -1255,6 +1415,7 @@ module DocusignRest
1255
1415
  http = initialize_net_http_ssl(uri)
1256
1416
  request = Net::HTTP::Delete.new(uri.request_uri, headers(content_type))
1257
1417
  response = http.request(request)
1418
+ generate_log(request, response, uri)
1258
1419
  json = response.body
1259
1420
  json = '{}' if json.nil? || json == ''
1260
1421
  JSON.parse(json)
@@ -1273,7 +1434,9 @@ module DocusignRest
1273
1434
 
1274
1435
  http = initialize_net_http_ssl(uri)
1275
1436
  request = Net::HTTP::Get.new(uri.request_uri, headers({ 'Content-Type' => 'application/json' }))
1276
- JSON.parse(http.request(request).body)
1437
+ response = http.request(request)
1438
+ generate_log(request, response, uri)
1439
+ JSON.parse(response.body)
1277
1440
  end
1278
1441
 
1279
1442
 
@@ -1287,7 +1450,9 @@ module DocusignRest
1287
1450
 
1288
1451
  http = initialize_net_http_ssl(uri)
1289
1452
  request = Net::HTTP::Get.new(uri.request_uri, headers({ 'Content-Type' => 'application/json' }))
1290
- JSON.parse(http.request(request).body)
1453
+ response = http.request(request)
1454
+ generate_log(request, response, uri)
1455
+ JSON.parse(response.body)
1291
1456
  end
1292
1457
 
1293
1458
 
@@ -1303,6 +1468,7 @@ module DocusignRest
1303
1468
  http = initialize_net_http_ssl(uri)
1304
1469
  request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
1305
1470
  response = http.request(request)
1471
+ generate_log(request, response, uri)
1306
1472
  JSON.parse(response.body)
1307
1473
  end
1308
1474
 
@@ -1329,6 +1495,7 @@ module DocusignRest
1329
1495
  request.body = post_body
1330
1496
 
1331
1497
  response = http.request(request)
1498
+ generate_log(request, response, uri)
1332
1499
  JSON.parse(response.body)
1333
1500
  end
1334
1501
 
@@ -1353,11 +1520,13 @@ module DocusignRest
1353
1520
  http = initialize_net_http_ssl(uri)
1354
1521
  request = Net::HTTP::Put.new(uri.request_uri, headers(content_type))
1355
1522
  request.body = post_body
1356
- http.request(request)
1523
+ response = http.request(request)
1524
+ generate_log(request, response, uri)
1525
+ response
1357
1526
  end
1358
1527
 
1359
1528
  # Public deletes a document for a given envelope
1360
- # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST API References/Remove Documents from a Draft Envelope.htm%3FTocPath%3DREST%2520API%2520References%7C_____54
1529
+ # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeDocuments/delete/
1361
1530
  #
1362
1531
  # envelope_id - ID of the envelope from which the doc will be retrieved
1363
1532
  # document_id - ID of the document to delete
@@ -1382,11 +1551,12 @@ module DocusignRest
1382
1551
  request.body = post_body
1383
1552
 
1384
1553
  response = http.request(request)
1554
+ generate_log(request, response, uri)
1385
1555
  JSON.parse(response.body)
1386
1556
  end
1387
1557
 
1388
1558
  # Public adds a document to a given envelope
1389
- # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST API References/Add Document.htm%3FTocPath%3DREST%2520API%2520References%7C_____56
1559
+ # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeDocuments/update/
1390
1560
  #
1391
1561
  # envelope_id - ID of the envelope from which the doc will be added
1392
1562
  # document_id - ID of the document to add
@@ -1412,20 +1582,21 @@ module DocusignRest
1412
1582
  http = initialize_net_http_ssl(uri)
1413
1583
  request = Net::HTTP::Put.new(uri.request_uri, headers(headers))
1414
1584
  request.body = post_body
1415
-
1416
- http.request(request)
1585
+ response = http.request(request)
1586
+ generate_log(request, response, uri)
1587
+ response
1417
1588
  end
1418
1589
 
1419
1590
  # Public adds signers to a given envelope
1420
- # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Add%20Recipients%20to%20an%20Envelope.htm%3FTocPath%3DREST%2520API%2520References|_____77
1591
+ # Seehttps://docs.docusign.com/esign/restapi/Envelopes/EnvelopeRecipients/update/
1421
1592
  #
1422
1593
  # envelope_id - ID of the envelope to which the recipient will be added
1423
1594
  # signers - Array of hashes
1424
- # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Recipients/Signers%20Recipient.htm%3FTocPath%3DREST%2520API%2520References|Send%2520an%2520Envelope%2520or%2520Create%2520a%2520Draft%2520Envelope|Recipient%2520Parameters|_____7
1595
+ # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeRecipients/update/#definitions
1425
1596
  #
1426
1597
  # TODO: This could be made more general as an add_envelope_recipient method
1427
1598
  # to handle recipient types other than Signer
1428
- # See: https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Recipient%20Parameter.htm%3FTocPath%3DREST%2520API%2520References|Send%2520an%2520Envelope%2520or%2520Create%2520a%2520Draft%2520Envelope|Recipient%2520Parameters|_____0
1599
+ # See: https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeRecipients/update/#examples
1429
1600
  def add_envelope_signers(options = {})
1430
1601
  content_type = { "Content-Type" => "application/json" }
1431
1602
  content_type.merge(options[:headers]) if options[:headers]
@@ -1438,11 +1609,12 @@ module DocusignRest
1438
1609
  request.body = post_body
1439
1610
 
1440
1611
  response = http.request(request)
1612
+ generate_log(request, response, uri)
1441
1613
  JSON.parse(response.body)
1442
1614
  end
1443
1615
 
1444
1616
  # Public adds recipient tabs to a given envelope
1445
- # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST API References/Add Tabs for a Recipient.htm%3FTocPath%3DREST%2520API%2520References%7C_____86
1617
+ # See https://docs.docusign.com/esign/restapi/Envelopes/EnvelopeRecipients/update/
1446
1618
  #
1447
1619
  # envelope_id - ID of the envelope from which the doc will be added
1448
1620
  # recipient - ID of the recipient to add tabs to
@@ -1488,7 +1660,32 @@ module DocusignRest
1488
1660
  request.body = post_body
1489
1661
 
1490
1662
  response = http.request(request)
1663
+ generate_log(request, response, uri)
1491
1664
  JSON.parse(response.body)
1492
1665
  end
1666
+
1667
+ private
1668
+
1669
+ # Private: Generates a standardized log of the request and response pair
1670
+ # to and from DocuSign for logging and API Certification.
1671
+ # and resulting list is set to the publicly accessible: @previous_call_log
1672
+ # For example:
1673
+ # envelope = connection.create_envelope_from_document(doc)
1674
+ # connection.previous_call_log.each {|line| logger.debug line }
1675
+ def generate_log(request, response, uri)
1676
+ log = ['--DocuSign REQUEST--']
1677
+ log << "#{request.method} #{uri.to_s}"
1678
+ request.each_capitalized{ |k,v| log << "#{k}: #{v.gsub(/(?<="Password":")(.+?)(?=")/, '[FILTERED]')}" }
1679
+ # Trims out the actual binary file to reduce log size
1680
+ if request.body
1681
+ request_body = request.body.gsub(/(?<=Content-Transfer-Encoding: binary).+?(?=-------------RubyMultipartPost)/m, "\n[BINARY BLOB]\n")
1682
+ log << "Body: #{request_body}"
1683
+ end
1684
+ log << '--DocuSign RESPONSE--'
1685
+ log << "HTTP/#{response.http_version} #{response.code} #{response.msg}"
1686
+ response.each_capitalized{ |k,v| log << "#{k}: #{v}" }
1687
+ log << "Body: #{response.body}"
1688
+ @previous_call_log = log
1689
+ end
1493
1690
  end
1494
1691
  end