synapse_pay_rest 2.0.2 → 2.1.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/synapse_pay_rest.rb +3 -1
  4. data/lib/synapse_pay_rest/error.rb +1 -0
  5. data/lib/synapse_pay_rest/http_client.rb +2 -0
  6. data/lib/synapse_pay_rest/models/node/ach_us_node.rb +11 -19
  7. data/lib/synapse_pay_rest/models/node/base_node.rb +88 -17
  8. data/lib/synapse_pay_rest/models/node/eft_ind_node.rb +7 -6
  9. data/lib/synapse_pay_rest/models/node/eft_np_node.rb +3 -4
  10. data/lib/synapse_pay_rest/models/node/iou_node.rb +6 -15
  11. data/lib/synapse_pay_rest/models/node/node.rb +18 -17
  12. data/lib/synapse_pay_rest/models/node/reserve_us_node.rb +5 -11
  13. data/lib/synapse_pay_rest/models/node/synapse_ind_node.rb +4 -8
  14. data/lib/synapse_pay_rest/models/node/synapse_np_node.rb +2 -8
  15. data/lib/synapse_pay_rest/models/node/synapse_us_node.rb +2 -8
  16. data/lib/synapse_pay_rest/models/node/triumph_subaccount_us_node.rb +17 -0
  17. data/lib/synapse_pay_rest/models/node/unverified_node.rb +1 -1
  18. data/lib/synapse_pay_rest/models/node/wire_int_node.rb +3 -4
  19. data/lib/synapse_pay_rest/models/node/wire_us_node.rb +1 -2
  20. data/lib/synapse_pay_rest/models/transaction/transaction.rb +9 -9
  21. data/lib/synapse_pay_rest/models/user/base_document.rb +12 -16
  22. data/lib/synapse_pay_rest/models/user/document.rb +2 -2
  23. data/lib/synapse_pay_rest/models/user/physical_document.rb +58 -17
  24. data/lib/synapse_pay_rest/models/user/user.rb +27 -10
  25. data/lib/synapse_pay_rest/models/user/virtual_document.rb +7 -8
  26. data/lib/synapse_pay_rest/version.rb +1 -1
  27. data/samples.md +41 -60
  28. data/synapse_pay_rest.gemspec +8 -8
  29. metadata +4 -6
  30. data/lib/synapse_pay_rest/models/node/eft_node.rb +0 -27
  31. data/lib/synapse_pay_rest/models/node/synapse_node.rb +0 -25
  32. data/lib/synapse_pay_rest/models/node/wire_node.rb +0 -38
@@ -1,7 +1,7 @@
1
1
  module SynapsePayRest
2
2
  # Represents a Synapse node allowing any user to hold funds. You can use this
3
3
  # node as a wallet, an escrow account or something else along those lines.
4
- class SynapseUsNode < SynapseNode
4
+ class SynapseUsNode < BaseNode
5
5
  class << self
6
6
  private
7
7
 
@@ -10,13 +10,7 @@ module SynapsePayRest
10
10
  type: 'SYNAPSE-US',
11
11
  nickname: nickname
12
12
  }.merge(options)
13
- payload = super(args)
14
- # optional payload fields
15
- extra = {}
16
- extra['supp_id'] = options[:supp_id] if options[:supp_id]
17
- extra['gateway_restricted'] = options[:gateway_restricted] if options[:gateway_restricted]
18
- payload['extra'] = extra if extra.any?
19
- payload
13
+ super(args)
20
14
  end
21
15
  end
22
16
  end
@@ -0,0 +1,17 @@
1
+ module SynapsePayRest
2
+ # Represents a Synapse node allowing any user to hold funds. You can use this
3
+ # node as a wallet, an escrow account or something else along those lines.
4
+ class TriumphSubaccountUsNode < BaseNode
5
+ class << self
6
+ private
7
+
8
+ def payload_for_create(nickname:, **options)
9
+ args = {
10
+ type: 'TRIUMPH-SUBACCOUNT-US',
11
+ nickname: nickname
12
+ }.merge(options)
13
+ super(args)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -53,7 +53,7 @@ module SynapsePayRest
53
53
  if response['error_code'] == '0'
54
54
  # correct answer
55
55
  @mfa_verified = true
56
- AchUsNode.create_multiple_from_response(user, response['nodes'])
56
+ AchUsNode.multiple_from_response(user, response['nodes'])
57
57
  elsif response['error_code'] == '10' && response['mfa']['message'] == mfa_message
58
58
  # wrong answer (mfa message the same), retry if allowed
59
59
  args = {
@@ -1,6 +1,6 @@
1
1
  module SynapsePayRest
2
2
  # Represents a non-US account for wire payments.
3
- class WireIntNode < WireNode
3
+ class WireIntNode < BaseNode
4
4
  class << self
5
5
  private
6
6
 
@@ -11,12 +11,11 @@ module SynapsePayRest
11
11
  nickname: nickname,
12
12
  bank_name: bank_name,
13
13
  account_number: account_number,
14
+ swift: swift,
14
15
  name_on_account: name_on_account,
15
16
  address: address
16
17
  }.merge(options)
17
- payload = super(args)
18
- payload['info']['swift'] = swift
19
- payload
18
+ super(args)
20
19
  end
21
20
  end
22
21
  end
@@ -1,6 +1,6 @@
1
1
  module SynapsePayRest
2
2
  # Represents a US bank account for processing wire payments.
3
- class WireUsNode < WireNode
3
+ class WireUsNode < BaseNode
4
4
  class << self
5
5
  private
6
6
 
@@ -15,7 +15,6 @@ module SynapsePayRest
15
15
  name_on_account: name_on_account,
16
16
  address: address
17
17
  }.merge(options)
18
-
19
18
  super(args)
20
19
  end
21
20
  end
@@ -54,7 +54,7 @@ module SynapsePayRest
54
54
  amount: amount, currency: currency, ip: ip, **options)
55
55
  node.user.authenticate
56
56
  response = node.user.client.trans.create(node_id: node.id, payload: payload)
57
- create_from_response(node, response)
57
+ from_response(node, response)
58
58
  end
59
59
 
60
60
  # Queries the API for a transaction belonging to the supplied node by transaction id
@@ -72,7 +72,7 @@ module SynapsePayRest
72
72
 
73
73
  node.user.authenticate
74
74
  response = node.user.client.trans.get(node_id: node.id, trans_id: id)
75
- create_from_response(node, response)
75
+ from_response(node, response)
76
76
  end
77
77
 
78
78
  # Queries the API for all transactions belonging to the supplied node and returns
@@ -95,7 +95,7 @@ module SynapsePayRest
95
95
 
96
96
  node.user.authenticate
97
97
  response = node.user.client.trans.get(node_id: node.id, page: page, per_page: per_page)
98
- create_multiple_from_response(node, response['trans'])
98
+ multiple_from_response(node, response['trans'])
99
99
  end
100
100
 
101
101
  # Creates a Transaction from a response hash.
@@ -104,7 +104,7 @@ module SynapsePayRest
104
104
  #
105
105
  # @todo convert the nodes and users in response into User/Node objects
106
106
  # @todo rework to handle multiple fees
107
- def create_from_response(node, response)
107
+ def from_response(node, response)
108
108
  args = {
109
109
  node: node,
110
110
  id: response['_id'],
@@ -156,7 +156,7 @@ module SynapsePayRest
156
156
  payload['extra']['process_on'] = options[:process_in] if options[:process_in]
157
157
  other = {}
158
158
  other['attachments'] = options[:attachments] if options[:attachments]
159
- payload['other'] = other if other.any?
159
+ payload['extra']['other'] = other if other.any?
160
160
  fees = []
161
161
  fee = {}
162
162
  fee['fee'] = options[:fee_amount] if options[:fee_amount]
@@ -169,9 +169,9 @@ module SynapsePayRest
169
169
  payload
170
170
  end
171
171
 
172
- def create_multiple_from_response(node, response)
172
+ def multiple_from_response(node, response)
173
173
  return [] if response.empty?
174
- response.map { |trans_data| create_from_response(node, trans_data) }
174
+ response.map { |trans_data| from_response(node, trans_data) }
175
175
  end
176
176
  end
177
177
 
@@ -191,7 +191,7 @@ module SynapsePayRest
191
191
  def add_comment(comment)
192
192
  payload = {'comment': comment}
193
193
  response = node.user.client.trans.update(node_id: node.id, trans_id: id, payload: payload)
194
- self.class.create_from_response(node, response['trans'])
194
+ self.class.from_response(node, response['trans'])
195
195
  end
196
196
 
197
197
  # Cancels this transaction if it has not already settled.
@@ -201,7 +201,7 @@ module SynapsePayRest
201
201
  # @return [Array<SynapsePayRest::Transaction>] (self)
202
202
  def cancel
203
203
  response = node.user.client.trans.delete(node_id: node.id, trans_id: id)
204
- self.class.create_from_response(node, response)
204
+ self.class.from_response(node, response)
205
205
  end
206
206
 
207
207
  # Checks if two Transaction instances have same id (different instances of same record).
@@ -93,21 +93,21 @@ module SynapsePayRest
93
93
 
94
94
  # Parses multiple base_documents from response
95
95
  # @note Do not call directly (it's automatic).
96
- def create_from_response(user, response)
96
+ def from_response(user, response)
97
97
  base_documents_data = response['documents']
98
98
  base_documents_data.map do |base_document_data|
99
99
  physical_docs = base_document_data['physical_docs'].map do |data|
100
- doc = PhysicalDocument.create_from_response(data)
100
+ doc = PhysicalDocument.from_response(data)
101
101
  doc.base_document = self
102
102
  doc
103
103
  end
104
104
  social_docs = base_document_data['social_docs'].map do |data|
105
- doc = SocialDocument.create_from_response(data)
105
+ doc = SocialDocument.from_response(data)
106
106
  doc.base_document = self
107
107
  doc
108
108
  end
109
109
  virtual_docs = base_document_data['virtual_docs'].map do |data|
110
- doc = VirtualDocument.create_from_response(data)
110
+ doc = VirtualDocument.from_response(data)
111
111
  doc.base_document = self
112
112
  doc
113
113
  end
@@ -166,14 +166,13 @@ module SynapsePayRest
166
166
  def submit
167
167
  user.authenticate
168
168
  response = user.client.users.update(payload: payload_for_submit)
169
- @user = User.create_from_response(user.client, response)
169
+ @user = User.from_response(user.client, response)
170
170
 
171
171
  if id
172
172
  # return updated version of self
173
173
  user.base_documents.find { |doc| doc.id == id }
174
174
  else
175
175
  # first time submission, assume last doc is updated version of self
176
- require 'pry';
177
176
  user.base_documents.last
178
177
  end
179
178
  end
@@ -214,7 +213,7 @@ module SynapsePayRest
214
213
  user.authenticate
215
214
  payload = payload_for_update(changes)
216
215
  response = user.client.users.update(payload: payload)
217
- @user = User.create_from_response(user.client, response)
216
+ @user = User.from_response(user.client, response)
218
217
 
219
218
  if id
220
219
  # return updated version of self
@@ -228,13 +227,12 @@ module SynapsePayRest
228
227
  # Adds one or more physical documents to the base document and submits
229
228
  # them to the API using KYC 2.0 endpoints.
230
229
  #
231
- # @param documents [Array<SynapsePayRest::PhysicalDocument>]
230
+ # @param documents [Array<SynapsePayRest::PhysicalDocument>] (one or more documents)
232
231
  #
233
232
  # @raise [SynapsePayRest::Error]
234
233
  #
235
234
  # @return [SynapsePayRest::BaseDocument] new instance with updated info
236
- def add_physical_documents(documents)
237
- raise ArgumentError, 'must be an Array' unless documents.is_a?(Array)
235
+ def add_physical_documents(*documents)
238
236
  unless documents.first.is_a?(PhysicalDocument)
239
237
  raise ArgumentError, 'must contain a PhysicalDocument'
240
238
  end
@@ -245,13 +243,12 @@ module SynapsePayRest
245
243
  # Adds one or more social documents to the base document and submits
246
244
  # them to the API using KYC 2.0 endpoints.
247
245
  #
248
- # @param documents [Array<SynapsePayRest::SocialDocument>]
246
+ # @param documents [Array<SynapsePayRest::SocialDocument>] (one or more documents)
249
247
  #
250
248
  # @raise [SynapsePayRest::Error]
251
249
  #
252
250
  # @return [SynapsePayRest::BaseDocument] new instance with updated info
253
- def add_social_documents(documents)
254
- raise ArgumentError, 'must be an Array' unless documents.is_a?(Array)
251
+ def add_social_documents(*documents)
255
252
  unless documents.first.is_a?(SocialDocument)
256
253
  raise ArgumentError, 'must contain a SocialDocument'
257
254
  end
@@ -262,13 +259,12 @@ module SynapsePayRest
262
259
  # Adds one or more virtual documents to the base document and submits
263
260
  # them to the API using KYC 2.0 endpoints.
264
261
  #
265
- # @param documents [Array<SynapsePayRest::VirtualDocument>]
262
+ # @param documents [Array<SynapsePayRest::VirtualDocument>] (one or more documents)
266
263
  #
267
264
  # @raise [SynapsePayRest::Error]
268
265
  #
269
266
  # @return [SynapsePayRest::BaseDocument] new instance with updated info
270
- def add_virtual_documents(documents)
271
- raise ArgumentError, 'must be an Array' unless documents.is_a?(Array)
267
+ def add_virtual_documents(*documents)
272
268
  unless documents.first.is_a?(VirtualDocument)
273
269
  raise ArgumentError, 'must contain a VirtualDocument'
274
270
  end
@@ -11,7 +11,7 @@ module SynapsePayRest
11
11
  attr_accessor :base_document, :status, :id, :type, :value, :last_updated
12
12
 
13
13
  class << self
14
- # Creates a document instances but does not submit it to the API. Use
14
+ # Creates a document instance but does not submit it to the API. Use
15
15
  # BaseDocument#create/#update/#add_physical_documents or related methods
16
16
  # to submit the document to the API.
17
17
  #
@@ -34,7 +34,7 @@ module SynapsePayRest
34
34
  end
35
35
 
36
36
  # @note Do not call this method. It is used by child classes only.
37
- def create_from_response(data)
37
+ def from_response(data)
38
38
  self.new(
39
39
  type: data['document_type'],
40
40
  id: data['id'],
@@ -1,29 +1,70 @@
1
+ require 'open-uri'
2
+
1
3
  module SynapsePayRest
2
4
  # Represents physical documents that can be added to a base document.
3
5
  #
4
6
  # @see https://docs.synapsepay.com/docs/user-resources#section-physical-document-types
5
7
  # physical document types
6
8
  class PhysicalDocument < Document
7
- # Converts the document into hash format for use in request JSON.
8
- # @note You shouldn't need to call this directly.
9
- #
10
- # @return [Hash]
11
- def to_hash
12
- {'document_value' => to_base64(value), 'document_type' => type}
13
- end
14
9
 
15
- private
10
+ class << self
11
+ # Creates a document instance but does not submit it to the API. Use
12
+ # BaseDocument#create/#update/#add_physical_documents or related methods
13
+ # to submit the document to the API.
14
+ #
15
+ # @note This should only be called on subclasses of Document, not on
16
+ # Document itself.
17
+ #
18
+ # @param type [String]
19
+ # @param value [String] (optional) padded base64-encoded image ("data:#{mime_type};base64,#{base64}")
20
+ # @param file_path [String] (optional) path to image file
21
+ # @param url [String] (optional) image file url
22
+ # @param byte_stream [String] (optional) byte representation of image
23
+ # @param mime_type [String] (optional) mime type of byte_stream (e.g. 'image/png')
24
+ #
25
+ # @return [SynapsePayRest::Document]
26
+ #
27
+ # @see https://docs.synapsepay.com/docs/user-resources#section-physical-document-types physical document types
28
+ # @see https://docs.synapsepay.com/docs/user-resources#section-social-document-types social document types
29
+ # @see https://docs.synapsepay.com/docs/user-resources#section-virtual-document-types virtual document types
30
+ def create(type:, **options)
31
+ if options[:file_path]
32
+ value = self.file_to_base64(options[:file_path])
33
+ elsif options[:url]
34
+ value = self.url_to_base64(options[:url])
35
+ elsif options[:byte_stream]
36
+ value = self.byte_stream_to_base64(options[:byte_stream], options[:mime_type])
37
+ elsif options[:value]
38
+ value = options[:value]
39
+ end
40
+
41
+ super(type: type, value: value)
42
+ end
43
+
44
+ # Converts the supplied image url to padded base64
45
+ def url_to_base64(url)
46
+ raise ArgumentError, 'url must be a String' unless url.is_a?(String)
47
+ byte_stream = open(url).read
48
+ begin
49
+ mime_type = MIME::Types.type_for(url).first.content_type
50
+ rescue
51
+ mime_type = nil
52
+ end
53
+ byte_stream_to_base64(byte_stream, mime_type)
54
+ end
16
55
 
17
- # Converts the supplied file to base64 encoding so it can be uploaded to API.
18
- def to_base64(file_path)
19
- raise ArgumentError, 'file_path must be a String' unless file_path.is_a?(String)
56
+ # Converts the supplied image file to padded base64
57
+ def file_to_base64(file_path)
58
+ raise ArgumentError, 'file_path must be a String' unless file_path.is_a?(String)
59
+ url_to_base64(file_path)
60
+ end
20
61
 
21
- content_types = MIME::Types.type_for(file_path)
22
- file_type = content_types.first.content_type if content_types.any?
23
- file_contents = open(file_path) { |f| f.read }
24
- encoded = Base64.encode64(file_contents)
25
- mime_padding = "data:#{file_type};base64,"
26
- mime_padding + encoded
62
+ # Converts the supplied image byte stream to padded base64
63
+ def byte_stream_to_base64(byte_stream, mime_type)
64
+ base64 = Base64.encode64(byte_stream)
65
+ padding = "data:#{mime_type};base64,#{base64}"
66
+ padding + base64
67
+ end
27
68
  end
28
69
  end
29
70
  end
@@ -58,7 +58,7 @@ module SynapsePayRest
58
58
 
59
59
  payload = payload_for_create(logins: logins, phone_numbers: phone_numbers, legal_names: legal_names, **options)
60
60
  response = client.users.create(payload: payload)
61
- create_from_response(client, response)
61
+ from_response(client, response)
62
62
  end
63
63
 
64
64
  # Queries the API for a user by id and returns a User instances if found.
@@ -74,7 +74,7 @@ module SynapsePayRest
74
74
  raise ArgumentError, 'id must be a String' unless id.is_a?(String)
75
75
 
76
76
  response = client.users.get(user_id: id)
77
- create_from_response(client, response)
77
+ from_response(client, response)
78
78
  end
79
79
 
80
80
  # Queries the API for all users (with optional filters) and returns them
@@ -101,7 +101,7 @@ module SynapsePayRest
101
101
  end
102
102
 
103
103
  response = client.users.get(page: page, per_page: per_page, query: query)
104
- create_multiple_from_response(client, response['users'])
104
+ multiple_from_response(client, response['users'])
105
105
  end
106
106
 
107
107
  # Queries the API for all users with name/email matching the given query
@@ -141,7 +141,7 @@ module SynapsePayRest
141
141
 
142
142
  # Constructs a user instance from a user response.
143
143
  # @note Do not call directly.
144
- def create_from_response(client, response)
144
+ def from_response(client, response)
145
145
  user = self.new(
146
146
  client: client,
147
147
  id: response['_id'],
@@ -157,16 +157,16 @@ module SynapsePayRest
157
157
  )
158
158
 
159
159
  unless response['documents'].empty?
160
- base_documents = BaseDocument.create_from_response(user, response)
160
+ base_documents = BaseDocument.from_response(user, response)
161
161
  user.base_documents = base_documents
162
162
  end
163
163
  user
164
164
  end
165
165
 
166
- # Calls create_from_response on each member of a response collection.
167
- def create_multiple_from_response(client, response)
166
+ # Calls from_response on each member of a response collection.
167
+ def multiple_from_response(client, response)
168
168
  return [] if response.empty?
169
- response.map { |user_data| create_from_response(client, user_data)}
169
+ response.map { |user_data| from_response(client, user_data)}
170
170
  end
171
171
  end
172
172
 
@@ -202,10 +202,10 @@ module SynapsePayRest
202
202
  raise ArgumentError, 'must provide a key-value pair to update. keys: login,
203
203
  read_only, phone_number, legal_name, remove_phone_number, remove_login'
204
204
  end
205
-
205
+ authenticate
206
206
  response = client.users.update(payload: payload_for_update(options))
207
207
  # return an updated user instance
208
- self.class.create_from_response(client, response)
208
+ self.class.from_response(client, response)
209
209
  end
210
210
 
211
211
  # Creates a new base document for the user. To update an existing base
@@ -435,6 +435,8 @@ module SynapsePayRest
435
435
  # @raise [SynapsePayRest::Error]
436
436
  #
437
437
  # @return [SynapsePayRest::EftIndNode]
438
+ #
439
+ # @deprecated
438
440
  def create_eft_ind_node(**options)
439
441
  EftIndNode.create(user: self, **options)
440
442
  end
@@ -490,6 +492,8 @@ module SynapsePayRest
490
492
  # @raise [SynapsePayRest::Error]
491
493
  #
492
494
  # @return [SynapsePayRest::SynapseIndNode]
495
+ #
496
+ # @deprecated
493
497
  def create_synapse_ind_node(**options)
494
498
  SynapseIndNode.create(user: self, **options)
495
499
  end
@@ -520,6 +524,19 @@ module SynapsePayRest
520
524
  SynapseUsNode.create(user: self, **options)
521
525
  end
522
526
 
527
+ # Creates a TRIUMPH-SUBACCOUNT-US node.
528
+ #
529
+ # @param nickname [String] nickname for the node
530
+ # @param supp_id [String] (optional)
531
+ # @param gateway_restricted [Boolean] (optional)
532
+ #
533
+ # @raise [SynapsePayRest::Error]
534
+ #
535
+ # @return [SynapsePayRest::TriumphSubaccountUsNode]
536
+ def create_triumph_subaccount_us_node(**options)
537
+ TriumphSubaccountUsNode.create(user: self, **options)
538
+ end
539
+
523
540
  # Creates a WIRE-INT node.
524
541
  #
525
542
  # @param nickname [String] nickname for the node