gocardless_pro 2.17.1 → 2.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/gocardless_pro.rb +3 -0
- data/lib/gocardless_pro/client.rb +6 -1
- data/lib/gocardless_pro/resources/creditor_bank_account.rb +1 -2
- data/lib/gocardless_pro/resources/currency_exchange_rate.rb +44 -0
- data/lib/gocardless_pro/resources/customer_notification.rb +3 -5
- data/lib/gocardless_pro/resources/event.rb +2 -1
- data/lib/gocardless_pro/resources/mandate_import.rb +5 -8
- data/lib/gocardless_pro/resources/mandate_import_entry.rb +3 -5
- data/lib/gocardless_pro/resources/payout.rb +2 -0
- data/lib/gocardless_pro/resources/redirect_flow.rb +2 -0
- data/lib/gocardless_pro/resources/subscription.rb +38 -29
- data/lib/gocardless_pro/services/currency_exchange_rates_service.rb +67 -0
- data/lib/gocardless_pro/services/customers_service.rb +1 -2
- data/lib/gocardless_pro/services/instalment_schedules_service.rb +81 -5
- data/lib/gocardless_pro/services/mandates_service.rb +1 -1
- data/lib/gocardless_pro/services/payouts_service.rb +21 -0
- data/lib/gocardless_pro/services/subscriptions_service.rb +129 -0
- data/lib/gocardless_pro/version.rb +1 -1
- data/spec/resources/currency_exchange_rate_spec.rb +103 -0
- data/spec/resources/instalment_schedule_spec.rb +193 -1
- data/spec/resources/payout_spec.rb +45 -0
- data/spec/resources/redirect_flow_spec.rb +9 -0
- data/spec/resources/subscription_spec.rb +210 -0
- data/spec/services/currency_exchange_rates_service_spec.rb +223 -0
- data/spec/services/instalment_schedules_service_spec.rb +270 -1
- data/spec/services/payouts_service_spec.rb +74 -0
- data/spec/services/redirect_flows_service_spec.rb +9 -0
- data/spec/services/subscriptions_service_spec.rb +240 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c285e5a1284e099a2840ea4dfb7a8282a73a38aa0def7e81f522654b4be5922
|
4
|
+
data.tar.gz: 0443f073f12c0c6d69029a4a79d28634978274e73b6d1bc0a1517066c44b66e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf2401b3823b41bd1d562a80f0e7a8b0847a86f04e1ec29ad2e55b3caf814e39ea379f0686c6108b91de81701b8cebc697e0bd1f7cd4741c44176785c01bcc27
|
7
|
+
data.tar.gz: f8aa9bd7ff1c8f969d54ae654b324395572459ec065e603601dbe5eb9a38ec61852724820dc8423bc7407e47004434dcee4b880b3a4d2678086b0f0729dece07
|
data/lib/gocardless_pro.rb
CHANGED
@@ -47,6 +47,9 @@ require_relative 'gocardless_pro/services/creditors_service'
|
|
47
47
|
require_relative 'gocardless_pro/resources/creditor_bank_account'
|
48
48
|
require_relative 'gocardless_pro/services/creditor_bank_accounts_service'
|
49
49
|
|
50
|
+
require_relative 'gocardless_pro/resources/currency_exchange_rate'
|
51
|
+
require_relative 'gocardless_pro/services/currency_exchange_rates_service'
|
52
|
+
|
50
53
|
require_relative 'gocardless_pro/resources/customer'
|
51
54
|
require_relative 'gocardless_pro/services/customers_service'
|
52
55
|
|
@@ -18,6 +18,11 @@ module GoCardlessPro
|
|
18
18
|
@creditor_bank_accounts ||= Services::CreditorBankAccountsService.new(@api_service)
|
19
19
|
end
|
20
20
|
|
21
|
+
# Access to the service for currency_exchange_rate to make API calls
|
22
|
+
def currency_exchange_rates
|
23
|
+
@currency_exchange_rates ||= Services::CurrencyExchangeRatesService.new(@api_service)
|
24
|
+
end
|
25
|
+
|
21
26
|
# Access to the service for customer to make API calls
|
22
27
|
def customers
|
23
28
|
@customers ||= Services::CustomersService.new(@api_service)
|
@@ -143,7 +148,7 @@ module GoCardlessPro
|
|
143
148
|
'User-Agent' => user_agent.to_s,
|
144
149
|
'Content-Type' => 'application/json',
|
145
150
|
'GoCardless-Client-Library' => 'gocardless-pro-ruby',
|
146
|
-
'GoCardless-Client-Version' => '2.
|
151
|
+
'GoCardless-Client-Version' => '2.21.0',
|
147
152
|
},
|
148
153
|
}
|
149
154
|
end
|
@@ -23,8 +23,7 @@ module GoCardlessPro
|
|
23
23
|
# `links[creditor_bank_account]` in the error response.
|
24
24
|
#
|
25
25
|
# <p class="restricted-notice"><strong>Restricted</strong>: This API is not
|
26
|
-
# available for
|
27
|
-
# partner integrations.</p>
|
26
|
+
# available for partner integrations.</p>
|
28
27
|
class CreditorBankAccount
|
29
28
|
attr_reader :account_holder_name
|
30
29
|
attr_reader :account_number_ending
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#
|
4
|
+
# This client is automatically generated from a template and JSON schema definition.
|
5
|
+
# See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module GoCardlessPro
|
11
|
+
# A module containing classes for each of the resources in the GC Api
|
12
|
+
module Resources
|
13
|
+
# Represents an instance of a currency_exchange_rate resource returned from the API
|
14
|
+
|
15
|
+
# Currency exchange rates from our foreign exchange provider.
|
16
|
+
class CurrencyExchangeRate
|
17
|
+
attr_reader :rate
|
18
|
+
attr_reader :source
|
19
|
+
attr_reader :target
|
20
|
+
attr_reader :time
|
21
|
+
|
22
|
+
# Initialize a currency_exchange_rate resource instance
|
23
|
+
# @param object [Hash] an object returned from the API
|
24
|
+
def initialize(object, response = nil)
|
25
|
+
@object = object
|
26
|
+
|
27
|
+
@rate = object['rate']
|
28
|
+
@source = object['source']
|
29
|
+
@target = object['target']
|
30
|
+
@time = object['time']
|
31
|
+
@response = response
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_response
|
35
|
+
ApiResponse.new(@response)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Provides the currency_exchange_rate resource as a hash of all its readable attributes
|
39
|
+
def to_h
|
40
|
+
@object
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -23,11 +23,9 @@ module GoCardlessPro
|
|
23
23
|
# way, it is no longer visible using this API.
|
24
24
|
#
|
25
25
|
# <p class="restricted-notice"><strong>Restricted</strong>: This API is
|
26
|
-
# currently
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# in touch</a> if you would like to use this API.</p>
|
30
|
-
#
|
26
|
+
# currently only available for approved integrators - please <a
|
27
|
+
# href="mailto:help@gocardless.com">get in touch</a> if you would like to
|
28
|
+
# use this API.</p>
|
31
29
|
class CustomerNotification
|
32
30
|
attr_reader :action_taken
|
33
31
|
attr_reader :action_taken_at
|
@@ -14,7 +14,8 @@ module GoCardlessPro
|
|
14
14
|
|
15
15
|
# Events are stored for all webhooks. An event refers to a resource which
|
16
16
|
# has been updated, for example a payment which has been collected, or a
|
17
|
-
# mandate which has been transferred.
|
17
|
+
# mandate which has been transferred. See [here](#event-actions) for a
|
18
|
+
# complete list of event types.
|
18
19
|
class Event
|
19
20
|
attr_reader :action
|
20
21
|
attr_reader :created_at
|
@@ -47,16 +47,13 @@ module GoCardlessPro
|
|
47
47
|
# system](#mandate-import-entries-list-all-mandate-import-entries).
|
48
48
|
#
|
49
49
|
# <p class="notice">Note that all Mandate Imports have an upper limit of
|
50
|
-
# 30,000 entries, so
|
51
|
-
#
|
52
|
-
# planning to
|
53
|
-
# exceed this threshold.</p>
|
50
|
+
# 30,000 entries, so we recommend you split your import into several smaller
|
51
|
+
# imports if you're planning to exceed this threshold.</p>
|
54
52
|
#
|
55
53
|
# <p class="restricted-notice"><strong>Restricted</strong>: This API is
|
56
|
-
# currently
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# in touch</a> if you would like to use this API.</p>
|
54
|
+
# currently only available for approved integrators - please <a
|
55
|
+
# href="mailto:help@gocardless.com">get in touch</a> if you would like to
|
56
|
+
# use this API.</p>
|
60
57
|
class MandateImport
|
61
58
|
attr_reader :created_at
|
62
59
|
attr_reader :id
|
@@ -39,11 +39,9 @@ module GoCardlessPro
|
|
39
39
|
# been imported.
|
40
40
|
#
|
41
41
|
# <p class="restricted-notice"><strong>Restricted</strong>: This API is
|
42
|
-
# currently
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# in touch</a> if you would like to use this API.</p>
|
46
|
-
#
|
42
|
+
# currently only available for approved integrators - please <a
|
43
|
+
# href="mailto:help@gocardless.com">get in touch</a> if you would like to
|
44
|
+
# use this API.</p>
|
47
45
|
class MandateImportEntry
|
48
46
|
attr_reader :created_at
|
49
47
|
attr_reader :record_identifier
|
@@ -26,6 +26,7 @@ module GoCardlessPro
|
|
26
26
|
attr_reader :deducted_fees
|
27
27
|
attr_reader :fx
|
28
28
|
attr_reader :id
|
29
|
+
attr_reader :metadata
|
29
30
|
attr_reader :payout_type
|
30
31
|
attr_reader :reference
|
31
32
|
attr_reader :status
|
@@ -43,6 +44,7 @@ module GoCardlessPro
|
|
43
44
|
@fx = object['fx']
|
44
45
|
@id = object['id']
|
45
46
|
@links = object['links']
|
47
|
+
@metadata = object['metadata']
|
46
48
|
@payout_type = object['payout_type']
|
47
49
|
@reference = object['reference']
|
48
50
|
@status = object['status']
|
@@ -49,6 +49,7 @@ module GoCardlessPro
|
|
49
49
|
attr_reader :created_at
|
50
50
|
attr_reader :description
|
51
51
|
attr_reader :id
|
52
|
+
attr_reader :metadata
|
52
53
|
attr_reader :redirect_url
|
53
54
|
attr_reader :scheme
|
54
55
|
attr_reader :session_token
|
@@ -64,6 +65,7 @@ module GoCardlessPro
|
|
64
65
|
@description = object['description']
|
65
66
|
@id = object['id']
|
66
67
|
@links = object['links']
|
68
|
+
@metadata = object['metadata']
|
67
69
|
@redirect_url = object['redirect_url']
|
68
70
|
@scheme = object['scheme']
|
69
71
|
@session_token = object['session_token']
|
@@ -20,40 +20,45 @@ module GoCardlessPro
|
|
20
20
|
# The following rules apply when specifying recurrence:
|
21
21
|
#
|
22
22
|
# - The first payment must be charged within 1 year.
|
23
|
-
# -
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
23
|
+
# - If `day_of_month` and `start_date` are not provided `start_date` will be
|
24
|
+
# the [mandate](#core-endpoints-mandates)'s `next_possible_charge_date` and
|
25
|
+
# the subscription will then recur based on the `interval` & `interval_unit`
|
26
|
+
# - If `month` or `day_of_month` are present the following validations
|
27
|
+
# apply:
|
27
28
|
#
|
28
|
-
# |
|
29
|
-
#
|
30
|
-
# |
|
31
|
-
#
|
32
|
-
# | yearly
|
33
|
-
# optional (
|
34
|
-
# | monthly
|
35
|
-
#
|
36
|
-
# | weekly
|
37
|
-
# invalid
|
29
|
+
# | __interval_unit__ | __month__ |
|
30
|
+
# __day_of_month__ |
|
31
|
+
# | :---------------- | :--------------------------------------------- |
|
32
|
+
# :----------------------------------------- |
|
33
|
+
# | yearly | optional (required if `day_of_month` provided) |
|
34
|
+
# optional (invalid if `month` not provided) |
|
35
|
+
# | monthly | invalid |
|
36
|
+
# optional |
|
37
|
+
# | weekly | invalid |
|
38
|
+
# invalid |
|
38
39
|
#
|
39
40
|
# Examples:
|
40
41
|
#
|
41
|
-
# |
|
42
|
-
#
|
43
|
-
# |
|
42
|
+
# | __interval_unit__ | __interval__ | __month__ | __day_of_month__ | valid?
|
43
|
+
# |
|
44
|
+
# | :---------------- | :----------- | :-------- | :--------------- |
|
44
45
|
# :------------------------------------------------- |
|
45
|
-
# | yearly
|
46
|
-
#
|
47
|
-
# |
|
48
|
-
#
|
49
|
-
# | monthly
|
50
|
-
#
|
51
|
-
# |
|
52
|
-
#
|
53
|
-
# |
|
54
|
-
#
|
55
|
-
# |
|
56
|
-
#
|
46
|
+
# | yearly | 1 | january | -1 | valid
|
47
|
+
# |
|
48
|
+
# | monthly | 6 | | | valid
|
49
|
+
# |
|
50
|
+
# | monthly | 6 | | 12 | valid
|
51
|
+
# |
|
52
|
+
# | weekly | 2 | | | valid
|
53
|
+
# |
|
54
|
+
# | yearly | 1 | march | |
|
55
|
+
# invalid - missing `day_of_month` |
|
56
|
+
# | yearly | 1 | | 2 |
|
57
|
+
# invalid - missing `month` |
|
58
|
+
# | monthly | 6 | august | 12 |
|
59
|
+
# invalid - `month` must be blank |
|
60
|
+
# | weekly | 2 | october | 10 |
|
61
|
+
# invalid - `month` and `day_of_month` must be blank |
|
57
62
|
#
|
58
63
|
# ### Rolling dates
|
59
64
|
#
|
@@ -69,9 +74,11 @@ module GoCardlessPro
|
|
69
74
|
class Subscription
|
70
75
|
attr_reader :amount
|
71
76
|
attr_reader :app_fee
|
77
|
+
attr_reader :count
|
72
78
|
attr_reader :created_at
|
73
79
|
attr_reader :currency
|
74
80
|
attr_reader :day_of_month
|
81
|
+
attr_reader :earliest_charge_date_after_resume
|
75
82
|
attr_reader :end_date
|
76
83
|
attr_reader :id
|
77
84
|
attr_reader :interval
|
@@ -92,9 +99,11 @@ module GoCardlessPro
|
|
92
99
|
|
93
100
|
@amount = object['amount']
|
94
101
|
@app_fee = object['app_fee']
|
102
|
+
@count = object['count']
|
95
103
|
@created_at = object['created_at']
|
96
104
|
@currency = object['currency']
|
97
105
|
@day_of_month = object['day_of_month']
|
106
|
+
@earliest_charge_date_after_resume = object['earliest_charge_date_after_resume']
|
98
107
|
@end_date = object['end_date']
|
99
108
|
@id = object['id']
|
100
109
|
@interval = object['interval']
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative './base_service'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
# encoding: utf-8
|
5
|
+
#
|
6
|
+
# This client is automatically generated from a template and JSON schema definition.
|
7
|
+
# See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
|
8
|
+
#
|
9
|
+
|
10
|
+
module GoCardlessPro
|
11
|
+
module Services
|
12
|
+
# Service for making requests to the CurrencyExchangeRate endpoints
|
13
|
+
class CurrencyExchangeRatesService < BaseService
|
14
|
+
# Returns a [cursor-paginated](#api-usage-cursor-pagination) list of all
|
15
|
+
# exchange rates.
|
16
|
+
# Example URL: /currency_exchange_rates
|
17
|
+
# @param options [Hash] parameters as a hash, under a params key.
|
18
|
+
def list(options = {})
|
19
|
+
path = '/currency_exchange_rates'
|
20
|
+
|
21
|
+
options[:retry_failures] = true
|
22
|
+
|
23
|
+
response = make_request(:get, path, options)
|
24
|
+
|
25
|
+
ListResponse.new(
|
26
|
+
response: response,
|
27
|
+
unenveloped_body: unenvelope_body(response.body),
|
28
|
+
resource_class: Resources::CurrencyExchangeRate
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
|
33
|
+
#
|
34
|
+
# @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
|
35
|
+
# Otherwise they will be the body of the request.
|
36
|
+
def all(options = {})
|
37
|
+
Paginator.new(
|
38
|
+
service: self,
|
39
|
+
options: options
|
40
|
+
).enumerator
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Unenvelope the response of the body using the service's `envelope_key`
|
46
|
+
#
|
47
|
+
# @param body [Hash]
|
48
|
+
def unenvelope_body(body)
|
49
|
+
body[envelope_key] || body['data']
|
50
|
+
end
|
51
|
+
|
52
|
+
# return the key which API responses will envelope data under
|
53
|
+
def envelope_key
|
54
|
+
'currency_exchange_rates'
|
55
|
+
end
|
56
|
+
|
57
|
+
# take a URL with placeholder params and substitute them out for the actual value
|
58
|
+
# @param url [String] the URL with placeholders in
|
59
|
+
# @param param_map [Hash] a hash of placeholders and their actual values (which will be escaped)
|
60
|
+
def sub_url(url, param_map)
|
61
|
+
param_map.reduce(url) do |new_url, (param, value)|
|
62
|
+
new_url.gsub(":#{param}", URI.escape(value))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -123,8 +123,7 @@ module GoCardlessPro
|
|
123
123
|
# ID.
|
124
124
|
#
|
125
125
|
# <p class="restricted-notice"><strong>The action of removing a customer cannot
|
126
|
-
# be
|
127
|
-
# reversed, so please use with care.</strong></p>
|
126
|
+
# be reversed, so please use with care.</strong></p>
|
128
127
|
# Example URL: /customers/:identity
|
129
128
|
#
|
130
129
|
# @param identity # Unique identifier, beginning with "CU".
|
@@ -12,11 +12,66 @@ module GoCardlessPro
|
|
12
12
|
# Service for making requests to the InstalmentSchedule endpoints
|
13
13
|
class InstalmentSchedulesService < BaseService
|
14
14
|
# Creates a new instalment schedule object, along with the associated payments.
|
15
|
+
# This
|
16
|
+
# API is recommended if you know the specific dates you wish to charge.
|
17
|
+
# Otherwise,
|
18
|
+
# please check out the [scheduling
|
19
|
+
# version](#instalment-schedules-create-with-schedule).
|
15
20
|
#
|
16
|
-
# The `instalments` property
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
21
|
+
# The `instalments` property is an array of payment properties (`amount` and
|
22
|
+
# `charge_date`).
|
23
|
+
#
|
24
|
+
# It can take quite a while to create the associated payments, so the API will
|
25
|
+
# return
|
26
|
+
# the status as `pending` initially. When processing has completed, a subsequent
|
27
|
+
# GET
|
28
|
+
# request for the instalment schedule will either have the status `success` and
|
29
|
+
# link
|
30
|
+
# to the created payments, or the status `error` and detailed information about
|
31
|
+
# the
|
32
|
+
# failures.
|
33
|
+
# Example URL: /instalment_schedules
|
34
|
+
# @param options [Hash] parameters as a hash, under a params key.
|
35
|
+
def create_with_dates(options = {})
|
36
|
+
path = '/instalment_schedules'
|
37
|
+
|
38
|
+
params = options.delete(:params) || {}
|
39
|
+
options[:params] = {}
|
40
|
+
options[:params][envelope_key] = params
|
41
|
+
|
42
|
+
options[:retry_failures] = true
|
43
|
+
|
44
|
+
begin
|
45
|
+
response = make_request(:post, path, options)
|
46
|
+
|
47
|
+
# Response doesn't raise any errors until #body is called
|
48
|
+
response.tap(&:body)
|
49
|
+
rescue InvalidStateError => e
|
50
|
+
if e.idempotent_creation_conflict?
|
51
|
+
case @api_service.on_idempotency_conflict
|
52
|
+
when :raise
|
53
|
+
raise IdempotencyConflict, e.error
|
54
|
+
when :fetch
|
55
|
+
return get(e.conflicting_resource_id)
|
56
|
+
else
|
57
|
+
raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
raise e
|
62
|
+
end
|
63
|
+
|
64
|
+
return if response.body.nil?
|
65
|
+
|
66
|
+
Resources::InstalmentSchedule.new(unenvelope_body(response.body), response)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a new instalment schedule object, along with the associated payments.
|
70
|
+
# This
|
71
|
+
# API is recommended if you wish to use the GoCardless scheduling logic. For
|
72
|
+
# finer
|
73
|
+
# control over the individual dates, please check out the [alternative
|
74
|
+
# version](#instalment-schedules-create-with-dates).
|
20
75
|
#
|
21
76
|
# It can take quite a while to create the associated payments, so the API will
|
22
77
|
# return
|
@@ -27,7 +82,7 @@ module GoCardlessPro
|
|
27
82
|
# failures.
|
28
83
|
# Example URL: /instalment_schedules
|
29
84
|
# @param options [Hash] parameters as a hash, under a params key.
|
30
|
-
def
|
85
|
+
def create_with_schedule(options = {})
|
31
86
|
path = '/instalment_schedules'
|
32
87
|
|
33
88
|
params = options.delete(:params) || {}
|
@@ -107,6 +162,27 @@ module GoCardlessPro
|
|
107
162
|
Resources::InstalmentSchedule.new(unenvelope_body(response.body), response)
|
108
163
|
end
|
109
164
|
|
165
|
+
# Updates an instalment schedule. This accepts only the metadata parameter.
|
166
|
+
# Example URL: /instalment_schedules/:identity
|
167
|
+
#
|
168
|
+
# @param identity # Unique identifier, beginning with "IS".
|
169
|
+
# @param options [Hash] parameters as a hash, under a params key.
|
170
|
+
def update(identity, options = {})
|
171
|
+
path = sub_url('/instalment_schedules/:identity', 'identity' => identity)
|
172
|
+
|
173
|
+
params = options.delete(:params) || {}
|
174
|
+
options[:params] = {}
|
175
|
+
options[:params][envelope_key] = params
|
176
|
+
|
177
|
+
options[:retry_failures] = true
|
178
|
+
|
179
|
+
response = make_request(:put, path, options)
|
180
|
+
|
181
|
+
return if response.body.nil?
|
182
|
+
|
183
|
+
Resources::InstalmentSchedule.new(unenvelope_body(response.body), response)
|
184
|
+
end
|
185
|
+
|
110
186
|
# Immediately cancels an instalment schedule; no further payments will be
|
111
187
|
# collected for it.
|
112
188
|
#
|