figo 1.2.5 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/config.yml +4 -0
  4. data/console_demo.rb +1 -1
  5. data/figo.gemspec +3 -3
  6. data/lib/account/api_call.rb +55 -0
  7. data/lib/account/model.rb +122 -0
  8. data/lib/account_balance/api_call.rb +18 -0
  9. data/lib/account_balance/model.rb +31 -0
  10. data/lib/authentification/api_call.rb +88 -0
  11. data/lib/bank/api_call.rb +49 -0
  12. data/lib/bank/model.rb +23 -0
  13. data/lib/base.rb +56 -0
  14. data/lib/cacert.pem +0 -0
  15. data/lib/figo.rb +54 -380
  16. data/lib/helpers/error.rb +20 -0
  17. data/lib/helpers/https.rb +52 -0
  18. data/lib/notification/api_call.rb +40 -0
  19. data/lib/notification/model.rb +27 -0
  20. data/lib/payment/api_call.rb +71 -0
  21. data/lib/payment/model.rb +75 -0
  22. data/lib/process/api_call.rb +17 -0
  23. data/lib/process/model.rb +34 -0
  24. data/lib/security/api_call.rb +59 -0
  25. data/lib/security/model.rb +83 -0
  26. data/lib/standing_order/api_call.rb +24 -0
  27. data/lib/standing_order/model.rb +75 -0
  28. data/lib/synchronization_status/api_call.rb +27 -0
  29. data/lib/synchronization_status/model.rb +23 -0
  30. data/lib/task/api_call.rb +37 -0
  31. data/lib/task/model.rb +43 -0
  32. data/lib/transaction/api_call.rb +57 -0
  33. data/lib/transaction/model.rb +75 -0
  34. data/lib/user/api_call.rb +46 -0
  35. data/lib/user/model.rb +55 -0
  36. data/test/config.yml +7 -0
  37. data/test/test_account_sync_and_setup.rb +67 -0
  38. data/test/test_accounts.rb +106 -0
  39. data/test/test_authentififcation.rb +68 -0
  40. data/test/test_business_processes.rb +43 -0
  41. data/test/test_figo.rb +5 -86
  42. data/test/test_notifications.rb +83 -0
  43. data/test/test_payments.rb +106 -0
  44. data/test/test_securities.rb +70 -0
  45. data/test/test_standing_orders.rb +49 -0
  46. data/test/test_transactions.rb +87 -0
  47. data/test/test_user_management.rb +91 -0
  48. metadata +64 -14
  49. data/lib/models.rb +0 -466
File without changes
@@ -21,102 +21,35 @@
21
21
  #
22
22
 
23
23
  require "json"
24
- require "net/http/persistent"
25
- require "digest/sha1"
26
- require_relative "models.rb"
24
+ require "yaml"
27
25
 
26
+ require_relative "./helpers/https.rb"
27
+ require_relative "./helpers/error.rb"
28
+
29
+ require_relative "./authentification/api_call.rb"
28
30
 
29
31
  # Ruby bindings for the figo Connect API: http://developer.figo.me
30
32
  module Figo
31
- $api_endpoint = "api.figo.me"
32
-
33
- $valid_fingerprints = ["38:AE:4A:32:6F:16:EA:15:81:33:8B:B0:D8:E4:A6:35:E7:27:F1:07",
34
- "CF:C1:BC:7F:6A:16:09:2B:10:83:8A:B0:22:4F:3A:65:D2:70:D7:3E"]
35
-
36
- # Base class for all errors transported via the figo Connect API.
37
- class Error < RuntimeError
38
- # Initialize error object.
39
- #
40
- # @param error [String] the error code
41
- # @param error_description [String] the error description
42
- def initialize(error, error_description)
43
- @error = error
44
- @error_description = error_description
45
- end
46
-
47
- # Convert error object to string.
48
- #
49
- # @return [String] the error description
50
- def to_s
51
- return @error_description
52
- end
53
- end
54
-
55
- # HTTPS class with certificate authentication and enhanced error handling.
56
- class HTTPS < Net::HTTP::Persistent
57
- # Overwrite `initialize` method from `Net::HTTP::Persistent`.
58
- #
59
- # Verify fingerprints of server SSL/TLS certificates.
60
- def initialize(name = nil, proxy = nil)
61
- super(name, proxy)
62
-
63
- # Attribute ca_file must be set, otherwise verify_callback would never be called.
64
- @ca_file = "lib/cacert.pem"
65
- @verify_callback = proc do |preverify_ok, store_context|
66
- if preverify_ok and store_context.error == 0
67
- certificate = OpenSSL::X509::Certificate.new(store_context.chain[0])
68
- fingerprint = Digest::SHA1.hexdigest(certificate.to_der).upcase.scan(/../).join(":")
69
- $valid_fingerprints.include?(fingerprint)
70
- else
71
- false
72
- end
73
- end
74
- end
75
-
76
- # Overwrite `request` method from `Net::HTTP::Persistent`.
77
- #
78
- # Raise error when a REST API error is returned.
79
- def request(uri, req = nil, &block)
80
- response = super(uri, req, &block)
81
-
82
- # Evaluate HTTP response.
83
- case response
84
- when Net::HTTPSuccess
85
- return response
86
- when Net::HTTPBadRequest
87
- hash = JSON.parse(response.body)
88
- raise Error.new(hash["error"], hash["error_description"])
89
- when Net::HTTPUnauthorized
90
- raise Error.new("unauthorized", "Missing, invalid or expired access token.")
91
- when Net::HTTPForbidden
92
- raise Error.new("forbidden", "Insufficient permission.")
93
- when Net::HTTPNotFound
94
- return nil
95
- when Net::HTTPMethodNotAllowed
96
- raise Error.new("method_not_allowed", "Unexpected request method.")
97
- when Net::HTTPServiceUnavailable
98
- raise Error.new("service_unavailable", "Exceeded rate limit.")
99
- else
100
- raise Error.new("internal_server_error", "We are very sorry, but something went wrong.")
101
- end
102
- end
103
-
104
- end
33
+ $config = YAML.load_file(File.join(__dir__, '../config.yml'))
34
+ $api_endpoint = $config["API_ENDPOINT"]
35
+ $valid_fingerprints = $config["FINGER_PRINTS"]
105
36
 
106
37
  # Represents a non user-bound connection to the figo Connect API.
107
38
  #
108
39
  # It's main purpose is to let user login via OAuth 2.0.
109
40
  class Connection
41
+ include Figo
110
42
  # Create connection object with client credentials.
111
43
  #
112
44
  # @param client_id [String] the client ID
113
45
  # @param client_secret [String] the client secret
114
46
  # @param redirect_uri [String] optional redirect URI
115
- def initialize(client_id, client_secret, redirect_uri = nil)
47
+ def initialize(client_id, client_secret, redirect_uri = nil, fingerprints = $valid_fingerprints, api_endpoint = $api_endpoint)
116
48
  @client_id = client_id
117
49
  @client_secret = client_secret
118
50
  @redirect_uri = redirect_uri
119
- @https = HTTPS.new("figo-#{client_id}")
51
+ @https = HTTPS.new("figo-#{client_id}", nil, fingerprints)
52
+ @api_endpoint = api_endpoint
120
53
  end
121
54
 
122
55
  # Helper method for making a OAuth 2.0 request.
@@ -125,14 +58,14 @@ module Figo
125
58
  # @param data [Hash] this optional object will be used as url-encoded POST content.
126
59
  # @return [Hash] JSON response
127
60
  def query_api(path, data = nil)
128
- uri = URI("https://#{$api_endpoint}#{path}")
61
+ uri = URI("https://#{@api_endpoint}#{path}")
129
62
 
130
63
  # Setup HTTP request.
131
64
  request = Net::HTTP::Post.new(path)
132
65
  request.basic_auth(@client_id, @client_secret)
133
66
  request["Accept"] = "application/json"
134
67
  request["Content-Type"] = "application/x-www-form-urlencoded"
135
- request["User-Agent"] = "ruby-figo"
68
+ request["User-Agent"] = "figo-ruby/1.3.1"
136
69
  request.body = URI.encode_www_form(data) unless data.nil?
137
70
 
138
71
  # Send HTTP request.
@@ -141,84 +74,55 @@ module Figo
141
74
  # Evaluate HTTP response.
142
75
  return response.body == "" ? {} : JSON.parse(response.body)
143
76
  end
77
+ end
144
78
 
79
+ # Represents a user-bound connection to the figo Connect API and allows access to the user's data.
80
+ class Session
81
+ require_relative "./account_balance/model.rb"
82
+ require_relative "./account_balance/api_call.rb"
145
83
 
146
- # Get the URL a user should open in the web browser to start the login process.
147
- #
148
- # When the process is completed, the user is redirected to the URL provided to
149
- # the constructor and passes on an authentication code. This code can be converted
150
- # into an access token for data access.
151
- #
152
- # @param state [String] this string will be passed on through the complete login
153
- # process and to the redirect target at the end. It should be used to
154
- # validated the authenticity of the call to the redirect URL
155
- # @param scope [String] optional scope of data access to ask the user for,
156
- # e.g. `accounts=ro`
157
- # @return [String] the URL to be opened by the user.
158
- def login_url(state, scope = nil)
159
- data = { "response_type" => "code", "client_id" => @client_id, "state" => state }
160
- data["redirect_uri"] = @redirect_uri unless @redirect_uri.nil?
161
- data["scope"] = scope unless scope.nil?
162
- return "https://#{$api_endpoint}/auth/code?" + URI.encode_www_form(data)
163
- end
84
+ require_relative "./account/model.rb"
85
+ require_relative "./account/api_call.rb"
164
86
 
87
+ require_relative "./bank/model.rb"
88
+ require_relative "./bank/api_call.rb"
165
89
 
166
- # Exchange authorization code or refresh token for access token.
167
- #
168
- # @param authorization_code_or_refresh_token [String] either the authorization
169
- # code received as part of the call to the redirect URL at the end of the
170
- # logon process, or a refresh token
171
- # @param scope [String] optional scope of data access to ask the user for,
172
- # e.g. `accounts=ro`
173
- # @return [Hash] object with the keys `access_token`, `refresh_token` and
174
- # `expires`, as documented in the figo Connect API specification.
175
- def obtain_access_token(authorization_code_or_refresh_token, scope = nil)
176
- # Authorization codes always start with "O" and refresh tokens always start with "R".
177
- if authorization_code_or_refresh_token[0] == "O"
178
- data = { "grant_type" => "authorization_code", "code" => authorization_code_or_refresh_token }
179
- data["redirect_uri"] = @redirect_uri unless @redirect_uri.nil?
180
- elsif authorization_code_or_refresh_token[0] == "R"
181
- data = { "grant_type" => "refresh_token", "refresh_token" => authorization_code_or_refresh_token }
182
- data["scope"] = scope unless scope.nil?
183
- end
184
- return query_api("/auth/token", data)
185
- end
90
+ require_relative "./notification/model.rb"
91
+ require_relative "./notification/api_call.rb"
186
92
 
187
- # Revoke refresh token or access token.
188
- #
189
- # @note this action has immediate effect, i.e. you will not be able use that token anymore after this call.
190
- #
191
- # @param refresh_token_or_access_token [String] access or refresh token to be revoked
192
- # @return [nil]
193
- def revoke_token(refresh_token_or_access_token)
194
- data = { "token" => refresh_token_or_access_token }
195
- query_api("/auth/revoke?" + URI.encode_www_form(data))
196
- return nil
197
- end
93
+ require_relative "./payment/model.rb"
94
+ require_relative "./payment/api_call.rb"
198
95
 
199
- # Create a new figo Account
200
- #
201
- # @param name [String] First and last name
202
- # @param email [String] Email address; It must obey the figo username & password policy
203
- # @param password [String] New figo Account password; It must obey the figo username & password policy
204
- # @param language [String] Two-letter code of preferred language
205
- # @param send_newsletter [Boolean] This flag indicates whether the user has agreed to be contacted by email -- Not accepted by backend at the moment
206
- # @return [Hash] object with the key `recovery_password` as documented in the figo Connect API specification
207
- def create_user(name, email, password, language='de', send_newsletter=true)
208
- data = { 'name' => name, 'email' => email, 'password' => password, 'language' => language, 'affiliate_client_id' => @client_id} #'send_newsletter' => send_newsletter,
209
- return query_api("/auth/user", data)
210
- end
211
- end
96
+ require_relative "./synchronization_status/model.rb"
97
+ require_relative "./synchronization_status/api_call.rb"
212
98
 
213
- # Represents a user-bound connection to the figo Connect API and allows access to the user's data.
214
- class Session
99
+ require_relative "./transaction/model.rb"
100
+ require_relative "./transaction/api_call.rb"
101
+
102
+ require_relative "./user/model.rb"
103
+ require_relative "./user/api_call.rb"
104
+
105
+ require_relative "./standing_order/model.rb"
106
+ require_relative "./standing_order/api_call.rb"
107
+
108
+ require_relative "./process/model.rb"
109
+ require_relative "./process/api_call.rb"
110
+
111
+ require_relative "./security/model.rb"
112
+ require_relative "./security/api_call.rb"
113
+
114
+ require_relative "./task/model.rb"
115
+ require_relative "./task/api_call.rb"
116
+
117
+ include Figo
215
118
 
216
119
  # Create session object with access token.
217
120
  #
218
121
  # @param access_token [String] the access token
219
- def initialize(access_token)
122
+ def initialize(access_token, fingerprints = $valid_fingerprints, api_endpoint = $api_endpoint)
220
123
  @access_token = access_token
221
- @https = HTTPS.new("figo-#{access_token}")
124
+ @https = HTTPS.new("figo-#{access_token}", nil, fingerprints)
125
+ @api_endpoint = api_endpoint
222
126
  end
223
127
 
224
128
  # Helper method for making a REST request.
@@ -228,7 +132,7 @@ module Figo
228
132
  # @param method [String] the HTTP method
229
133
  # @return [Hash] JSON response
230
134
  def query_api(path, data=nil, method="GET") # :nodoc:
231
- uri = URI("https://#{$api_endpoint}#{path}")
135
+ uri = URI("https://#{@api_endpoint}#{path}")
232
136
 
233
137
  # Setup HTTP request.
234
138
  request = case method
@@ -245,7 +149,8 @@ module Figo
245
149
  request["Authorization"] = "Bearer #{@access_token}"
246
150
  request["Accept"] = "application/json"
247
151
  request["Content-Type"] = "application/json"
248
- request["User-Agent"] = "ruby-figo"
152
+ request["User-Agent"] = "figo-ruby/1.3.1"
153
+
249
154
  request.body = JSON.generate(data) unless data.nil?
250
155
 
251
156
  # Send HTTP request.
@@ -263,236 +168,5 @@ module Figo
263
168
  return type.new(self, response) if array_name.nil?
264
169
  return response[array_name].map {|entry| type.new(self, entry)}
265
170
  end
266
-
267
- # Retrieve current User
268
- #
269
- # @return [User] the current user
270
- def user
271
- query_api_object User, "/rest/user"
272
- end
273
-
274
- # Modify the current user
275
- #
276
- # @param user [User] the modified user object to be saved
277
- # @return [User] the modified user returned
278
- def modify_user(user)
279
- query_api_object User, "/rest/user", user.dump(), "PUT"
280
- end
281
-
282
- # Remove the current user
283
- # Note: this has immidiate effect and you wont be able to interact with the user after this call
284
- def remove_user
285
- query_api "/rest/user", nil, "DELETE"
286
- end
287
-
288
- # Retrieve all accounts
289
- #
290
- # @return [Array] an array of `Account` objects, one for each account the user has granted the app access
291
- def accounts
292
- query_api_object Account, "/rest/accounts", nil, "GET", "accounts"
293
- end
294
-
295
- # Retrieve specific account.
296
- #
297
- # @param account_id [String] ID of the account to be retrieved.
298
- # @return [Account] account object
299
- def get_account(account_id)
300
- query_api_object Account, "/rest/accounts/#{account_id}"
301
- end
302
-
303
- # Modify specific account
304
- #
305
- # @param account [Account] modified account to be saved
306
- # @return [Account] modified account returned by the server
307
- def modify_account(account)
308
- query_api_object Account, "/rest/accounts/#{account.account_id}", account.dump(), "PUT"
309
- end
310
-
311
- # Remove specific account
312
- #
313
- # @param account [Account, String] the account to be removed or its ID
314
- def remove_account(account)
315
- query_api account.is_a?(String) ? "/rest/accounts/#{account}" : "/rest/accounts/#{account.account_id}", nil, "DELETE"
316
- end
317
-
318
- # Retrieve balance of an account.
319
- #
320
- # @return [AccountBalance] account balance object
321
- def get_account_balance(account_id)
322
- query_api_object AccountBalance, "/rest/accounts/#{account_id}/balance"
323
- end
324
-
325
- # Modify balance or account limits
326
- #
327
- # @param account_id [String] ID of the account which balance should be modified
328
- # @param account_balance [AccountBalance] modified AccountBalance to be saved
329
- # @return [AccountBalance] modified AccountBalance returned by server
330
- def modify_account_balance(account_id, account_balance)
331
- query_api_object AccountBalance, "/rest/accounts/#{account_id}/balance", account_balance.dump(), "PUT"
332
- end
333
-
334
- # Retrieve specific bank
335
- #
336
- # @return [Bank] bank object
337
- def get_bank(bank_id)
338
- query_api_object Bank, "/rest/banks/#{bank_id}"
339
- end
340
-
341
- # Modify bank
342
- #
343
- # @param bank [Bank] modified bank object
344
- # @return [Bank] modified bank object returned by server
345
- def modify_bank(bank)
346
- query_api_object Bank, "/rest/banks/#{bank.bank_id}", bank.dump(), "PUT"
347
- end
348
-
349
- # Remove stored PIN from bank
350
- #
351
- # @param bank [Bank, String] the bank whose stored PIN should be removed or its ID
352
- # @return [nil]
353
- def remove_bank_pin(bank)
354
- query_api bank.is_a?(String) ? "/rest/banks/#{bank}/submit": "/rest/banks/#{bank.bank_id}/submit", nil, "POST"
355
- end
356
-
357
- # Get bank information from standard bank code
358
- #
359
- # @param country_code [String]
360
- # @param bank_code [String] bank sort code (Bankleitzahl)
361
- # @return [Hash] JSON response
362
- def find_bank(bank_code, country_code)
363
- query_api "/rest/catalog/banks/#{country_code}/#{bank_code}"
364
- end
365
-
366
- # Retrieve list of transactions (on all or a specific account)
367
- #
368
- # @param account_id [String] ID of the account for which to list the transactions
369
- # @param since [String, Date] this parameter can either be a transaction ID or a date
370
- # @param count [Integer] limit the number of returned transactions
371
- # @param offset [Integer] which offset into the result set should be used to determin the first transaction to return (useful in combination with count)
372
- # @param include_pending [Boolean] this flag indicates whether pending transactions should be included
373
- # in the response; pending transactions are always included as a complete set, regardless of
374
- # the `since` parameter
375
- # @return [Array] an array of `Transaction` objects, one for each transaction of the user
376
- def transactions(account_id = nil, since = nil, count = 1000, offset = 0, include_pending = false)
377
- data = {"count" => count.to_s, "offset" => offset.to_s, "include_pending" => include_pending ? "1" : "0"}
378
- data["since"] = ((since.is_a?(Date) ? since.to_s : since) unless since.nil?)
379
-
380
- query_api_object Transaction, (account_id.nil? ? "/rest/transactions?" : "/rest/accounts/#{account_id}/transactions?") + URI.encode_www_form(data), nil, "GET", "transactions"
381
- end
382
-
383
- # Retrieve a specific transaction
384
- #
385
- # @param account_id [String] ID of the account on which the transaction occured
386
- # @param transaction_id [String] ID of the transaction to be retrieved
387
- # @return [Transaction] transaction object
388
- def get_transaction(account_id, transaction_id)
389
- query_api_object Transaction, "/rest/accounts/#{account_id}/transactions/#{transaction_id}"
390
- end
391
-
392
- # Retrieve the URL a user should open in the web browser to start the synchronization process.
393
- #
394
- # @param redirect_uri [String] the user will be redirected to this URL after the process completes
395
- # @param state [String] this string will be passed on through the complete synchronization process
396
- # and to the redirect target at the end. It should be used to validated the authenticity of
397
- # the call to the redirect URL
398
- # @param if_not_synced_since [Integer] if this parameter is set, only those accounts will be
399
- # synchronized, which have not been synchronized within the specified number of minutes.
400
- # @return [String] the URL to be opened by the user.
401
- def sync_url(redirect_uri, state, if_not_synced_since = 0)
402
- response = query_api "/rest/sync", {"redirect_uri" => redirect_uri, "state" => state, "if_not_synced_since" => if_not_synced_since}, "POST"
403
- return "https://#{$api_endpoint}/task/start?id=#{response["task_token"]}"
404
- end
405
-
406
- # Retrieve list of registered notifications.
407
- #
408
- # @return [Notification] an array of `Notification` objects, one for each registered notification
409
- def notifications
410
- query_api_object Notification, "/rest/notifications", nil, "GET", "notifications"
411
- end
412
-
413
- # Retrieve specific notification.
414
- #
415
- # @param notification_id [String] ID of the notification to be retrieved
416
- # @return [Notification] `Notification` object for the respective notification
417
- def get_notification(notification_id)
418
- query_api_object Notification, "/rest/notifications/#{notification_id}"
419
- end
420
-
421
- # Register a new notification.
422
- #
423
- # @param notification [Notification] notification to be crated. It should not have a notification_id set.
424
- # @return [Notification] newly created `Notification` object
425
- def add_notification(notification)
426
- query_api_object Notification, "/rest/notifications", notification.dump(), "POST"
427
- end
428
-
429
- # Modify notification.
430
- #
431
- # @param notification [Notification] modified notification object
432
- # @return [Notification] modified notification returned by server
433
- def modify_notification(notification)
434
- query_api_object Notification, "/rest/notifications/#{notification.notification_id}", notification.dump(), "PUT"
435
- end
436
-
437
- # Unregister notification.
438
- #
439
- # @param notification [Notification, String] notification object which should be deleted or its ID
440
- def remove_notification(notification)
441
- query_api notification.is_a?(String) ? "/rest/notifications/#{notification}" : "/rest/notifications/#{notification.notification_id}", nil, "DELETE"
442
- end
443
-
444
- # Retrieve list of all payments (on all accounts or one)
445
- #
446
- # @param account_id [String] ID of the account for whicht to list the payments
447
- # @return [Payment] an array of `Payment` objects, one for each payment
448
- def payments(account_id = nil)
449
- query_api_object Payment, account_id.nil? ? "/rest/payments" : "/rest/accounts/#{account_id}/payments", nil, "GET", "payments"
450
- end
451
-
452
- # Retrieve specific payment.
453
- #
454
- # @param account_id [String] ID for the account on which the payment to be retrieved was created
455
- # @param payment_id [String] ID of the notification to be retrieved
456
- # @return [Payment] `Payment` object for the respective payment
457
- def get_payment(account_id, payment_id)
458
- query_api_object Payment, "/rest/accounts/#{account_id}/payments/#{payment_id}"
459
- end
460
-
461
- # Create new payment
462
- #
463
- # @param payment [Payment] payment object to be created. It should not have a payment_id set.
464
- # @return [Payment] newly created `Payment` object
465
- def add_payment(payment)
466
- query_api_object Payment, "/rest/accounts/#{payment.account_id}/payments", payment.dump(), "POST"
467
- end
468
-
469
- # Modify payment
470
- #
471
- # @param payment [Payment] modified payment object
472
- # @return [Payment] modified payment object
473
- def modify_payment(payment)
474
- query_api_object Payment, "/rest/accounts/#{payment.account_id}/payments/#{payment.payment_id}", payment.dump(), "PUT"
475
- end
476
-
477
- # Submit payment
478
- #
479
- # @param tan_scheme_id [String] TAN scheme ID of user-selected TAN scheme
480
- # @param state [String] Any kind of string that will be forwarded in the callback response message
481
- # @param redirect_uri [String] At the end of the submission process a response will be sent to this callback URL
482
- # @return [String] the URL to be opened by the user for the TAN process
483
- def submit_payment(payment, tan_scheme_id, state, redirect_uri = nil)
484
- params = {"tan_scheme_id" => tan_scheme_id, "state" => state}
485
- params['redirect_uri'] = redirect_uri unless redirect_uri.nil?
486
-
487
- response = query_api "/rest/accounts/#{payment.account_id}/payments/#{payment.payment_id}/submit", params, "POST"
488
- return "https://#{$api_endpoint}/task/start?id=#{response["task_token"]}"
489
- end
490
-
491
- # Remove payment
492
- #
493
- # @param payment [Payment, String] payment object which should be removed
494
- def remove_payment(payment)
495
- query_api "/rest/accounts/#{payment.account_id}/payments/#{payment.payment_id}", nil, "DELETE"
496
- end
497
171
  end
498
172
  end