genesis_ruby 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/.kiro/specs/f2025112509-add_managed_recurring_api/.config.kiro +1 -0
- data/.kiro/specs/f2025112509-add_managed_recurring_api/design.md +332 -0
- data/.kiro/specs/f2025112509-add_managed_recurring_api/requirements.md +91 -0
- data/.kiro/specs/f2025112509-add_managed_recurring_api/tasks.md +139 -0
- data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/.config.kiro +1 -0
- data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/design.md +148 -0
- data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/requirements.md +81 -0
- data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/tasks.md +48 -0
- data/.kiro/specs/f2025112606-add_list_payees_trx_request/.config.kiro +1 -0
- data/.kiro/specs/f2025112606-add_list_payees_trx_request/design.md +112 -0
- data/.kiro/specs/f2025112606-add_list_payees_trx_request/requirements.md +74 -0
- data/.kiro/specs/f2025112606-add_list_payees_trx_request/tasks.md +38 -0
- data/.kiro/specs/f2025112609_update_payee_request_params/design.md +86 -0
- data/.kiro/specs/f2025112609_update_payee_request_params/requirements.md +86 -0
- data/.kiro/specs/f2025112609_update_payee_request_params/tasks.md +40 -0
- data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/.config.kiro +1 -0
- data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/design.md +246 -0
- data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/requirements.md +287 -0
- data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/tasks.md +76 -0
- data/.kiro/specs/f2025112614-add_money_transfer_payout_attributes_to_payout_rq/design.md +84 -0
- data/.kiro/specs/f2025112614-add_money_transfer_payout_attributes_to_payout_rq/requirements.md +88 -0
- data/.kiro/specs/f2025112614-add_money_transfer_payout_attributes_to_payout_rq/tasks.md +38 -0
- data/.kiro/steering/product.md +15 -0
- data/.kiro/steering/spec-folder-naming.md +16 -0
- data/.kiro/steering/structure.md +96 -0
- data/.kiro/steering/tech.md +66 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +4 -4
- data/README.md +33 -0
- data/VERSION +1 -1
- data/lib/genesis_ruby/api/constants/non_financial/kyc/address_document_supported_types.rb +81 -0
- data/lib/genesis_ruby/api/constants/non_financial/payee/document_types.rb +57 -0
- data/lib/genesis_ruby/api/constants/non_financial/payee/owner_types.rb +30 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/purpose_of_payments.rb +50 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/sender_account_number_types.rb +50 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/source_of_funds.rb +44 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/types.rb +26 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/non_financial/billing_api/statement_response_fields.rb +37 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/cards/mpi_attributes.rb +0 -10
- data/lib/genesis_ruby/api/mixins/requests/financial/money_transfer_payout_attributes.rb +131 -0
- data/lib/genesis_ruby/api/mixins/requests/non_financial/date_attributes.rb +87 -5
- data/lib/genesis_ruby/api/mixins/requests/non_financial/kyc/business_attributes.rb +42 -0
- data/lib/genesis_ruby/api/mixins/requests/non_financial/kyc/document_attributes.rb +8 -7
- data/lib/genesis_ruby/api/request.rb +15 -9
- data/lib/genesis_ruby/api/requests/base/non_financial/billing_api/base.rb +108 -0
- data/lib/genesis_ruby/api/requests/base/non_financial/payee/base.rb +54 -0
- data/lib/genesis_ruby/api/requests/financial/cards/authorize3d.rb +1 -3
- data/lib/genesis_ruby/api/requests/financial/cards/payout.rb +3 -1
- data/lib/genesis_ruby/api/requests/financial/cards/sale3d.rb +1 -3
- data/lib/genesis_ruby/api/requests/non_financial/billing_api/statement.rb +170 -0
- data/lib/genesis_ruby/api/requests/non_financial/billing_api/transactions.rb +20 -60
- data/lib/genesis_ruby/api/requests/non_financial/kyc/business/create.rb +45 -0
- data/lib/genesis_ruby/api/requests/non_financial/kyc/business/document.rb +60 -0
- data/lib/genesis_ruby/api/requests/non_financial/kyc/business/document_list.rb +59 -0
- data/lib/genesis_ruby/api/requests/non_financial/kyc/business/verification.rb +52 -0
- data/lib/genesis_ruby/api/requests/non_financial/kyc/verifications/address_by_document_proof.rb +92 -0
- data/lib/genesis_ruby/api/requests/non_financial/kyc/verifications/create.rb +4 -1
- data/lib/genesis_ruby/api/requests/non_financial/managed_recurring/cancel.rb +63 -0
- data/lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch.rb +63 -0
- data/lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_all.rb +37 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/account/reverify.rb +61 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/associate_payee_with_owners.rb +105 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/create.rb +37 -7
- data/lib/genesis_ruby/api/requests/non_financial/payee/create_payee_document.rb +61 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/dissociate_payee_with_owners.rb +94 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/list.rb +38 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/list_payee_documents.rb +57 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/list_payee_owners.rb +70 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/associate_owner_with_owners.rb +109 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/create.rb +71 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/create_owner_document.rb +63 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/delete.rb +54 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/dissociate_owners.rb +96 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/list_owner_documents.rb +59 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/list_owners.rb +46 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/retrieve.rb +59 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/retrieve_owner_document.rb +62 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/owners/update.rb +66 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/retrieve_payee_document.rb +60 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/update.rb +34 -4
- data/lib/genesis_ruby/api/requests/non_financial/payee/verifications/create_payee_verification.rb +58 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/verifications/list_payee_verifications.rb +59 -0
- data/lib/genesis_ruby/api/requests/non_financial/payee/verifications/retrieve_payee_verification.rb +62 -0
- data/lib/genesis_ruby/api/requests/non_financial/tokenization/retokenize.rb +45 -0
- data/lib/genesis_ruby/api/requests/wpf/create.rb +19 -0
- data/lib/genesis_ruby/api/response.rb +15 -0
- data/lib/genesis_ruby/dependencies.rb +2 -0
- data/lib/genesis_ruby/network/adapter/net_http_adapter.rb +31 -5
- data/lib/genesis_ruby/network/base_network.rb +5 -0
- data/lib/genesis_ruby/network/net_http.rb +16 -4
- data/lib/genesis_ruby/utils/options/api_config.rb +43 -32
- data/lib/genesis_ruby/utils/options/network_adapter_config.rb +1 -1
- data/lib/genesis_ruby/version.rb +1 -1
- metadata +72 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25761ad9b4ff17bdcd71f0b5e084c4fce9cbfc5754ade3addf54debd8fcac1df
|
|
4
|
+
data.tar.gz: 181e7917e70576f2cca9d38e7b59eef4799030ba21fcd52231e78206913827cc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 556163d312e4e1e5abd5a70174f15fb6c179425499fd49cbf80c02c88d311479391a8afade1428983bbda34f1451b58a76b98ee7fac470dbeb10903b3ff798d8
|
|
7
|
+
data.tar.gz: 201a4291c694d167212aecb08ab00f449961c0ad66ae6d6040205f583dc34162caba6931916114586cfdacc033df1985977c94b075bedd0eb96a6ca30f5ba627
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"specId": "24c1b655-56dc-44db-9abb-29e73ec1507e", "workflowType": "requirements-first", "specType": "feature"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# Design Document: Managed Recurring API
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This feature adds three new request classes to the genesis_ruby SDK for the Managed Recurring JSON API. These classes allow merchants to programmatically list, retrieve, and cancel managed recurring payment items. The implementation follows the established `Base::Versioned` pattern for versioned JSON API requests and introduces HTTP DELETE method support as a new capability in the SDK's network layer.
|
|
6
|
+
|
|
7
|
+
**Key design decisions:**
|
|
8
|
+
- Inherit from `Base::Versioned` to leverage versioned JSON endpoint configuration
|
|
9
|
+
- Use the same `:placeholder` path interpolation pattern as `Installments::Show` and `Payee::Retrieve`
|
|
10
|
+
- Add `METHOD_DELETE` and `load_delete_config` following the existing `METHOD_PATCH`/`load_patch_config` precedent
|
|
11
|
+
- Define endpoint path constant in the existing `ManagedRecurring` constants module
|
|
12
|
+
|
|
13
|
+
## Architecture
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
classDiagram
|
|
17
|
+
class Request {
|
|
18
|
+
+METHOD_DELETE : String
|
|
19
|
+
+init_delete_configuration()
|
|
20
|
+
}
|
|
21
|
+
class Versioned {
|
|
22
|
+
+version : String
|
|
23
|
+
+request_path : String
|
|
24
|
+
#init_configuration()
|
|
25
|
+
#process_request_parameters()
|
|
26
|
+
}
|
|
27
|
+
class FetchAll {
|
|
28
|
+
#init_configuration()
|
|
29
|
+
#request_structure() Hash
|
|
30
|
+
}
|
|
31
|
+
class Fetch {
|
|
32
|
+
+unique_id : String
|
|
33
|
+
#init_configuration()
|
|
34
|
+
#init_field_validations()
|
|
35
|
+
#request_structure() Hash
|
|
36
|
+
#process_request_parameters()
|
|
37
|
+
}
|
|
38
|
+
class Cancel {
|
|
39
|
+
+unique_id : String
|
|
40
|
+
#init_configuration()
|
|
41
|
+
#init_field_validations()
|
|
42
|
+
#request_structure() Hash
|
|
43
|
+
#process_request_parameters()
|
|
44
|
+
}
|
|
45
|
+
class ApiConfig {
|
|
46
|
+
+load_delete_config()
|
|
47
|
+
}
|
|
48
|
+
class NetHttpAdapter {
|
|
49
|
+
+execute()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Request <|-- Versioned
|
|
53
|
+
Versioned <|-- FetchAll
|
|
54
|
+
Versioned <|-- Fetch
|
|
55
|
+
Versioned <|-- Cancel
|
|
56
|
+
Request --> ApiConfig
|
|
57
|
+
Request ..> NetHttpAdapter
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Request flow:**
|
|
61
|
+
1. Merchant instantiates a request class (e.g., `Fetch.new(config)`)
|
|
62
|
+
2. Sets attributes (e.g., `request.unique_id = '...'`)
|
|
63
|
+
3. Calls `build_document` which triggers `process_request_parameters`
|
|
64
|
+
4. For Fetch/Cancel: path placeholder `:unique_id` is replaced with the actual value
|
|
65
|
+
5. Gateway URL is reconfigured with the resolved path
|
|
66
|
+
6. The SDK network layer dispatches the request using the configured HTTP method (GET or DELETE)
|
|
67
|
+
|
|
68
|
+
## Components and Interfaces
|
|
69
|
+
|
|
70
|
+
### 1. Service Endpoint Constant
|
|
71
|
+
|
|
72
|
+
**Module:** `GenesisRuby::Api::Constants::Transactions::Parameters::ManagedRecurring`
|
|
73
|
+
|
|
74
|
+
A new constant `ITEM_PATH` is added to the existing `ManagedRecurring` module (which already contains `Intervals`, `Frequencies`, etc.).
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
# In a new file: managed_recurring/service_endpoints.rb
|
|
78
|
+
# or directly in the existing module structure
|
|
79
|
+
ITEM_PATH = 'managed_recurring/items'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Rationale:** The path omits the `/v1/` prefix because `Base::Versioned` automatically prepends the version. The constant value `managed_recurring/items` is what goes into `request_path`.
|
|
83
|
+
|
|
84
|
+
### 2. FetchAll Request Class
|
|
85
|
+
|
|
86
|
+
**Path:** `lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_all.rb`
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
module GenesisRuby::Api::Requests::NonFinancial::ManagedRecurring
|
|
90
|
+
class FetchAll < Base::Versioned
|
|
91
|
+
def initialize(configuration, _builder_interface = nil)
|
|
92
|
+
super configuration
|
|
93
|
+
self.request_path = ITEM_PATH
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
protected
|
|
97
|
+
|
|
98
|
+
def init_configuration
|
|
99
|
+
super
|
|
100
|
+
init_get_configuration
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def request_structure
|
|
104
|
+
{}
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Behavior:** Sends an HTTP GET to `/v1/managed_recurring/items` with no body. Returns a JSON array of managed recurring items.
|
|
111
|
+
|
|
112
|
+
### 3. Fetch Request Class
|
|
113
|
+
|
|
114
|
+
**Path:** `lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch.rb`
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
module GenesisRuby::Api::Requests::NonFinancial::ManagedRecurring
|
|
118
|
+
class Fetch < Base::Versioned
|
|
119
|
+
attr_writer :unique_id
|
|
120
|
+
|
|
121
|
+
def initialize(configuration, _builder_interface = nil)
|
|
122
|
+
super configuration
|
|
123
|
+
self.request_path = "#{ITEM_PATH}/:unique_id"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def unique_id
|
|
127
|
+
@unique_id.to_s
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
protected
|
|
131
|
+
|
|
132
|
+
def init_configuration
|
|
133
|
+
super
|
|
134
|
+
init_get_configuration
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def init_field_validations
|
|
138
|
+
super
|
|
139
|
+
required_fields.push *%i[unique_id]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def request_structure
|
|
143
|
+
{}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def process_request_parameters
|
|
147
|
+
super
|
|
148
|
+
processed_path = request_path.gsub(':unique_id', unique_id)
|
|
149
|
+
init_api_gateway_configuration(request_path: "#{version}/#{processed_path}", include_token: false)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Behavior:** Sends an HTTP GET to `/v1/managed_recurring/items/{unique_id}`. Requires `unique_id` to be set before building.
|
|
156
|
+
|
|
157
|
+
### 4. Cancel Request Class
|
|
158
|
+
|
|
159
|
+
**Path:** `lib/genesis_ruby/api/requests/non_financial/managed_recurring/cancel.rb`
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
module GenesisRuby::Api::Requests::NonFinancial::ManagedRecurring
|
|
163
|
+
class Cancel < Base::Versioned
|
|
164
|
+
attr_writer :unique_id
|
|
165
|
+
|
|
166
|
+
def initialize(configuration, _builder_interface = nil)
|
|
167
|
+
super configuration
|
|
168
|
+
self.request_path = "#{ITEM_PATH}/:unique_id"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def unique_id
|
|
172
|
+
@unique_id.to_s
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
protected
|
|
176
|
+
|
|
177
|
+
def init_configuration
|
|
178
|
+
super
|
|
179
|
+
init_delete_configuration
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def init_field_validations
|
|
183
|
+
super
|
|
184
|
+
required_fields.push *%i[unique_id]
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def request_structure
|
|
188
|
+
{}
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def process_request_parameters
|
|
192
|
+
super
|
|
193
|
+
processed_path = request_path.gsub(':unique_id', unique_id)
|
|
194
|
+
init_api_gateway_configuration(request_path: "#{version}/#{processed_path}", include_token: false)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Behavior:** Sends an HTTP DELETE to `/v1/managed_recurring/items/{unique_id}`. Requires `unique_id`. Gateway returns 204 No Content on success.
|
|
201
|
+
|
|
202
|
+
### 5. HTTP DELETE Support
|
|
203
|
+
|
|
204
|
+
**Changes to existing files:**
|
|
205
|
+
|
|
206
|
+
- **`Api::Request`** — Add `METHOD_DELETE = 'DELETE'` constant and `init_delete_configuration` helper method
|
|
207
|
+
- **`Utils::Options::ApiConfig`** — Add `load_delete_config` method following the `load_patch_config` pattern
|
|
208
|
+
- **`Network::Adapter::NetHttpAdapter`** — Add `METHOD_DELETE` case to the `execute` method's case statement
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
# In ApiConfig
|
|
212
|
+
def load_delete_config
|
|
213
|
+
self.protocol = GenesisRuby::Api::Request::PROTOCOL_HTTPS
|
|
214
|
+
self.port = GenesisRuby::Api::Request::PORT_HTTPS
|
|
215
|
+
self.type = GenesisRuby::Api::Request::METHOD_DELETE
|
|
216
|
+
self.format = Builder::JSON
|
|
217
|
+
self.parser_skip_root_node = false
|
|
218
|
+
self.authorization = GenesisRuby::Api::Request::AUTH_TYPE_BASIC
|
|
219
|
+
self.bearer_token = nil
|
|
220
|
+
end
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
# In NetHttpAdapter#execute case statement
|
|
225
|
+
when Api::Request::METHOD_DELETE then @response = @request.delete path, headers
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
# In Api::Request
|
|
230
|
+
def init_delete_configuration
|
|
231
|
+
@api_config.load_delete_config
|
|
232
|
+
end
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Data Models
|
|
236
|
+
|
|
237
|
+
### Managed Recurring Item (response payload — read-only)
|
|
238
|
+
|
|
239
|
+
The SDK receives but does not construct these objects. They are parsed from JSON responses:
|
|
240
|
+
|
|
241
|
+
| Field | Type | Description |
|
|
242
|
+
|----------------|---------|------------------------------------------|
|
|
243
|
+
| unique_id | String | Unique identifier for the recurring item |
|
|
244
|
+
| interval | Integer | Number of periods between recurrences |
|
|
245
|
+
| period | String | Period unit (days, months, etc.) |
|
|
246
|
+
| amount | Integer | Amount in minor currency units |
|
|
247
|
+
| max_count | Integer | Maximum number of recurring charges |
|
|
248
|
+
| current_count | Integer | Current number of executed charges |
|
|
249
|
+
| first_date | String | Date of the first recurring charge |
|
|
250
|
+
| next_date | String | Date of the next scheduled charge |
|
|
251
|
+
| time_of_day | Integer | Time of day for execution (minutes) |
|
|
252
|
+
|
|
253
|
+
### Request Parameters
|
|
254
|
+
|
|
255
|
+
| Request | Parameters | Notes |
|
|
256
|
+
|----------|-----------|--------------------------------|
|
|
257
|
+
| FetchAll | (none) | No request body or path params |
|
|
258
|
+
| Fetch | unique_id | Path parameter, required |
|
|
259
|
+
| Cancel | unique_id | Path parameter, required |
|
|
260
|
+
|
|
261
|
+
## Correctness Properties
|
|
262
|
+
|
|
263
|
+
*A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
|
264
|
+
|
|
265
|
+
### Property 1: Unique ID path interpolation
|
|
266
|
+
|
|
267
|
+
*For any* non-empty string `unique_id`, when set on a Fetch or Cancel request and the request is built, the resulting endpoint URL SHALL end with `/managed_recurring/items/{unique_id}` where `{unique_id}` is the exact string that was set.
|
|
268
|
+
|
|
269
|
+
**Validates: Requirements 3.3, 3.8, 4.3, 4.7**
|
|
270
|
+
|
|
271
|
+
### Property 2: Empty unique_id rejection
|
|
272
|
+
|
|
273
|
+
*For any* nil or empty-string value assigned as `unique_id`, building the Fetch or Cancel request SHALL raise a validation error, and the request SHALL NOT be dispatched.
|
|
274
|
+
|
|
275
|
+
**Validates: Requirements 3.7, 4.6**
|
|
276
|
+
|
|
277
|
+
## Error Handling
|
|
278
|
+
|
|
279
|
+
| Scenario | Error Type | Behavior |
|
|
280
|
+
|-----------------------------------|------------------|-------------------------------------------------------|
|
|
281
|
+
| `unique_id` not set on Fetch | ParameterError | Raised during `check_requirements` in `build_document`|
|
|
282
|
+
| `unique_id` not set on Cancel | ParameterError | Raised during `check_requirements` in `build_document`|
|
|
283
|
+
| Invalid HTTP method in adapter | RuntimeError | Raised by NetHttpAdapter `else` branch |
|
|
284
|
+
| Network failure during request | NetworkError | Raised by NetHttpAdapter `safe_execute` |
|
|
285
|
+
| Gateway returns non-2xx | Handled by Response | `error?` method returns true |
|
|
286
|
+
| Gateway returns 204 (Cancel) | No error | Empty response body, `error?` returns false |
|
|
287
|
+
|
|
288
|
+
**Design note:** The `Net::HTTPSuccess` class in Ruby covers 2xx status codes (200-299), so a 204 response will correctly be treated as success by `error?`.
|
|
289
|
+
|
|
290
|
+
## Testing Strategy
|
|
291
|
+
|
|
292
|
+
### Unit Tests (RSpec)
|
|
293
|
+
|
|
294
|
+
Each request class gets a dedicated spec file following the existing pattern:
|
|
295
|
+
|
|
296
|
+
- `spec/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_all_spec.rb`
|
|
297
|
+
- `spec/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_spec.rb`
|
|
298
|
+
- `spec/genesis_ruby/api/requests/non_financial/managed_recurring/cancel_spec.rb`
|
|
299
|
+
|
|
300
|
+
Each spec verifies:
|
|
301
|
+
- Endpoint URL structure
|
|
302
|
+
- HTTP method (GET or DELETE)
|
|
303
|
+
- JSON format configuration
|
|
304
|
+
- Empty request body (`'{}'`)
|
|
305
|
+
- Required field validation (for Fetch and Cancel)
|
|
306
|
+
- Includes shared examples: `'base request examples'`, `'versioned request examples'`
|
|
307
|
+
|
|
308
|
+
Additional specs:
|
|
309
|
+
- `METHOD_DELETE` constant in `Api::Request` spec
|
|
310
|
+
- `load_delete_config` in `Utils::Options::ApiConfig` spec
|
|
311
|
+
- DELETE dispatch in `Network::Adapter::NetHttpAdapter` spec
|
|
312
|
+
|
|
313
|
+
### Property-Based Tests
|
|
314
|
+
|
|
315
|
+
**Library:** A property-based testing library for Ruby (e.g., `rantly` or custom generators with RSpec)
|
|
316
|
+
|
|
317
|
+
**Configuration:** Minimum 100 iterations per property test.
|
|
318
|
+
|
|
319
|
+
| Property | Test Description | Tag |
|
|
320
|
+
|----------|-----------------|-----|
|
|
321
|
+
| 1 | Generate random non-empty strings as unique_id, verify URL interpolation | Feature: f2025112509-add_managed_recurring_api, Property 1: Unique ID path interpolation |
|
|
322
|
+
| 2 | Generate nil/empty/whitespace-only strings, verify validation error raised | Feature: f2025112509-add_managed_recurring_api, Property 2: Empty unique_id rejection |
|
|
323
|
+
|
|
324
|
+
### Test Execution
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Run all managed recurring tests
|
|
328
|
+
bundle exec rspec spec/genesis_ruby/api/requests/non_financial/managed_recurring/
|
|
329
|
+
|
|
330
|
+
# Run full suite
|
|
331
|
+
bundle exec rspec
|
|
332
|
+
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Requirements Document
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Add Managed Recurring API request classes to the genesis_ruby SDK. The Managed Recurring JSON API enables merchants to programmatically manage recurring payment items through three operations: listing all active items, retrieving a single item by unique ID, and cancelling an item. The implementation follows existing SDK patterns for versioned JSON API requests and includes full RSpec test coverage.
|
|
6
|
+
|
|
7
|
+
## Glossary
|
|
8
|
+
|
|
9
|
+
- **SDK**: The genesis_ruby RubyGem client library for the Genesis Payment Gateway
|
|
10
|
+
- **Managed_Recurring_Item**: An active recurring payment schedule configured for a merchant, identified by a unique_id
|
|
11
|
+
- **Gateway**: The Genesis Payment Processing Gateway API by emerchantpay
|
|
12
|
+
- **Versioned_Request**: A request class inheriting from `Base::Versioned` that uses versioned JSON API endpoints
|
|
13
|
+
- **Item_Path**: The API endpoint constant `/v1/managed_recurring/items` used for all managed recurring requests
|
|
14
|
+
- **Unique_ID**: A string identifier that uniquely identifies a managed recurring item
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
### Requirement 1: Service Endpoint Constant
|
|
19
|
+
|
|
20
|
+
**User Story:** As a developer, I want a constant defining the managed recurring items endpoint path, so that request classes reference a single authoritative path value.
|
|
21
|
+
|
|
22
|
+
#### Acceptance Criteria
|
|
23
|
+
|
|
24
|
+
1. THE SDK SHALL define the constant `ITEM_PATH` with value `managed_recurring/items` under the `Api::Constants::Transactions::Parameters::ManagedRecurring` module (the `/v1/` prefix is omitted because `Base::Versioned` automatically prepends the version)
|
|
25
|
+
2. THE SDK SHALL make the ITEM_PATH constant accessible to all managed recurring request classes
|
|
26
|
+
|
|
27
|
+
### Requirement 2: Fetch All Managed Recurring Items
|
|
28
|
+
|
|
29
|
+
**User Story:** As a merchant integrator, I want to retrieve all active managed recurring items, so that I can display and manage recurring payment schedules.
|
|
30
|
+
|
|
31
|
+
#### Acceptance Criteria
|
|
32
|
+
|
|
33
|
+
1. THE SDK SHALL provide a request class `NonFinancial::ManagedRecurring::FetchAll` that inherits from `Base::Versioned`
|
|
34
|
+
2. WHEN the FetchAll request is built, THE SDK SHALL configure an HTTP GET request to the managed recurring items endpoint
|
|
35
|
+
3. THE SDK SHALL use the JSON builder interface for the FetchAll request
|
|
36
|
+
4. WHEN the FetchAll request is executed, THE Gateway SHALL return a JSON response containing a list of managed recurring items
|
|
37
|
+
5. THE SDK SHALL send the FetchAll request without a request body
|
|
38
|
+
6. THE SDK SHALL configure the FetchAll request endpoint as `https://{environment}.gate.{endpoint}:443/v1/managed_recurring/items`
|
|
39
|
+
|
|
40
|
+
### Requirement 3: Fetch Single Managed Recurring Item
|
|
41
|
+
|
|
42
|
+
**User Story:** As a merchant integrator, I want to retrieve a single managed recurring item by unique ID, so that I can inspect its details.
|
|
43
|
+
|
|
44
|
+
#### Acceptance Criteria
|
|
45
|
+
|
|
46
|
+
1. THE SDK SHALL provide a request class `NonFinancial::ManagedRecurring::Fetch` that inherits from `Base::Versioned`
|
|
47
|
+
2. THE SDK SHALL expose a `unique_id` attribute on the Fetch request class
|
|
48
|
+
3. WHEN the unique_id attribute is set, THE Fetch request SHALL include the unique_id value in the endpoint URL path
|
|
49
|
+
4. WHEN the Fetch request is built, THE SDK SHALL configure an HTTP GET request to the managed recurring items endpoint with the unique_id appended
|
|
50
|
+
5. THE SDK SHALL use the JSON builder interface for the Fetch request
|
|
51
|
+
6. THE SDK SHALL send the Fetch request without a request body
|
|
52
|
+
7. THE SDK SHALL require the unique_id field before executing the Fetch request
|
|
53
|
+
8. THE SDK SHALL configure the Fetch request endpoint as `https://{environment}.gate.{endpoint}:443/v1/managed_recurring/items/{unique_id}`
|
|
54
|
+
|
|
55
|
+
### Requirement 4: Cancel Managed Recurring Item
|
|
56
|
+
|
|
57
|
+
**User Story:** As a merchant integrator, I want to cancel a managed recurring item by unique ID, so that future recurring payments are stopped.
|
|
58
|
+
|
|
59
|
+
#### Acceptance Criteria
|
|
60
|
+
|
|
61
|
+
1. THE SDK SHALL provide a request class `NonFinancial::ManagedRecurring::Cancel` that inherits from `Base::Versioned`
|
|
62
|
+
2. THE SDK SHALL expose a `unique_id` attribute on the Cancel request class
|
|
63
|
+
3. WHEN the Cancel request is built, THE SDK SHALL configure an HTTP DELETE request to the managed recurring items endpoint with the unique_id appended
|
|
64
|
+
4. THE SDK SHALL use the JSON builder interface for the Cancel request
|
|
65
|
+
5. THE SDK SHALL send the Cancel request without a request body
|
|
66
|
+
6. THE SDK SHALL require the unique_id field before executing the Cancel request
|
|
67
|
+
7. THE SDK SHALL configure the Cancel request endpoint as `https://{environment}.gate.{endpoint}:443/v1/managed_recurring/items/{unique_id}`
|
|
68
|
+
8. WHEN the Gateway processes a successful cancellation, THE Gateway SHALL return HTTP status 204 with no response body
|
|
69
|
+
|
|
70
|
+
### Requirement 5: HTTP DELETE Method Support
|
|
71
|
+
|
|
72
|
+
**User Story:** As a developer, I want the SDK to support HTTP DELETE requests, so that the Cancel managed recurring request can use the correct HTTP method.
|
|
73
|
+
|
|
74
|
+
#### Acceptance Criteria
|
|
75
|
+
|
|
76
|
+
1. THE SDK SHALL define a `METHOD_DELETE` constant with value `DELETE` in the `Api::Request` class
|
|
77
|
+
2. THE SDK SHALL provide a `load_delete_config` method in the `Utils::Options::ApiConfig` class that configures HTTPS protocol, port 443, DELETE method type, JSON format, no root node skipping, and basic authorization
|
|
78
|
+
3. THE SDK SHALL provide an `init_delete_configuration` helper method in the `Api::Request` base class
|
|
79
|
+
4. THE Network_Adapter SHALL handle DELETE method requests by invoking the HTTP delete method on the connection
|
|
80
|
+
|
|
81
|
+
### Requirement 6: RSpec Test Coverage
|
|
82
|
+
|
|
83
|
+
**User Story:** As a developer, I want comprehensive RSpec tests for all managed recurring request classes, so that correctness is verified and regressions are prevented.
|
|
84
|
+
|
|
85
|
+
#### Acceptance Criteria
|
|
86
|
+
|
|
87
|
+
1. THE SDK SHALL include an RSpec test file for the FetchAll request class that verifies the endpoint URL, HTTP GET method, JSON format, and empty request body
|
|
88
|
+
2. THE SDK SHALL include an RSpec test file for the Fetch request class that verifies the endpoint URL with unique_id, HTTP GET method, JSON format, empty request body, and required field validation
|
|
89
|
+
3. THE SDK SHALL include an RSpec test file for the Cancel request class that verifies the endpoint URL with unique_id, HTTP DELETE method, JSON format, empty request body, and required field validation
|
|
90
|
+
4. THE SDK SHALL include an RSpec test for the METHOD_DELETE constant and the delete configuration in the network adapter
|
|
91
|
+
5. WHEN all managed recurring RSpec tests are executed, THE test suite SHALL pass without failures
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Implementation Plan: Managed Recurring API
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Add three new request classes (FetchAll, Fetch, Cancel) for the Managed Recurring JSON API to the genesis_ruby SDK, along with HTTP DELETE method support in the network layer. Implementation follows existing `Base::Versioned` patterns and includes full RSpec coverage.
|
|
6
|
+
|
|
7
|
+
## Tasks
|
|
8
|
+
|
|
9
|
+
- [x] 1. Add HTTP DELETE method support
|
|
10
|
+
- [x] 1.1 Add `METHOD_DELETE` constant and `init_delete_configuration` helper to `Api::Request`
|
|
11
|
+
- Add `METHOD_DELETE = 'DELETE'` constant alongside existing METHOD_PATCH in `lib/genesis_ruby/api/request.rb`
|
|
12
|
+
- Add `init_delete_configuration` protected method that calls `@api_config.load_delete_config`
|
|
13
|
+
- _Requirements: 5.1, 5.3_
|
|
14
|
+
|
|
15
|
+
- [x] 1.2 Add `load_delete_config` method to `Utils::Options::ApiConfig`
|
|
16
|
+
- Add `load_delete_config` method in `lib/genesis_ruby/utils/options/api_config.rb` following `load_patch_config` pattern
|
|
17
|
+
- Configure: HTTPS protocol, port 443, METHOD_DELETE type, JSON format, no root node skipping, basic authorization
|
|
18
|
+
- _Requirements: 5.2_
|
|
19
|
+
|
|
20
|
+
- [x] 1.3 Add DELETE case to `NetHttpAdapter#execute`
|
|
21
|
+
- Add `when Api::Request::METHOD_DELETE then @response = @request.delete path, headers` to the case statement in `lib/genesis_ruby/network/adapter/net_http_adapter.rb`
|
|
22
|
+
- _Requirements: 5.4_
|
|
23
|
+
|
|
24
|
+
- [x]* 1.4 Write RSpec tests for HTTP DELETE support
|
|
25
|
+
- Add test for `METHOD_DELETE` constant in `spec/genesis_ruby/api/request_spec.rb`
|
|
26
|
+
- Add test for `load_delete_config` in `spec/genesis_ruby/utils/options/api_config_spec.rb`
|
|
27
|
+
- Add test for DELETE dispatch in `spec/genesis_ruby/network/adapter/net_http_adapter_spec.rb`
|
|
28
|
+
- _Requirements: 6.4_
|
|
29
|
+
|
|
30
|
+
- [x] 2. Add ITEM_PATH constant for managed recurring endpoint
|
|
31
|
+
- [x] 2.1 Create `service_endpoints.rb` constant file in the ManagedRecurring module
|
|
32
|
+
- Create `lib/genesis_ruby/api/constants/transactions/parameters/managed_recurring/service_endpoints.rb`
|
|
33
|
+
- Define `ITEM_PATH = 'managed_recurring/items'` under `GenesisRuby::Api::Constants::Transactions::Parameters::ManagedRecurring` module
|
|
34
|
+
- Path omits `/v1/` prefix because `Base::Versioned` automatically prepends the version
|
|
35
|
+
- _Requirements: 1.1, 1.2_
|
|
36
|
+
|
|
37
|
+
- [x] 3. Implement FetchAll request class
|
|
38
|
+
- [x] 3.1 Create `NonFinancial::ManagedRecurring::FetchAll` request class
|
|
39
|
+
- Create `lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_all.rb`
|
|
40
|
+
- Inherit from `Base::Versioned`, set `request_path = ITEM_PATH`
|
|
41
|
+
- Override `init_configuration` to call `init_get_configuration`
|
|
42
|
+
- Return empty hash `{}` from `request_structure`
|
|
43
|
+
- Include the `ITEM_PATH` constant via the ManagedRecurring constants module
|
|
44
|
+
- _Requirements: 2.1, 2.2, 2.3, 2.5, 2.6_
|
|
45
|
+
|
|
46
|
+
- [x]* 3.2 Write RSpec tests for FetchAll request
|
|
47
|
+
- Create `spec/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_all_spec.rb`
|
|
48
|
+
- Verify endpoint URL `https://staging.gate.emerchantpay.net:443/v1/managed_recurring/items`
|
|
49
|
+
- Verify HTTP GET method, JSON format, empty request body (`'{}'`)
|
|
50
|
+
- Include shared examples: `'base request examples'`, `'versioned request examples'`
|
|
51
|
+
- _Requirements: 6.1_
|
|
52
|
+
|
|
53
|
+
- [x] 4. Implement Fetch request class
|
|
54
|
+
- [x] 4.1 Create `NonFinancial::ManagedRecurring::Fetch` request class
|
|
55
|
+
- Create `lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch.rb`
|
|
56
|
+
- Inherit from `Base::Versioned`, expose `unique_id` attribute (reader returns `.to_s`)
|
|
57
|
+
- Set `request_path = "#{ITEM_PATH}/:unique_id"`
|
|
58
|
+
- Override `init_configuration` to call `init_get_configuration`
|
|
59
|
+
- Override `init_field_validations` to push `unique_id` to `required_fields`
|
|
60
|
+
- Override `process_request_parameters` to gsub `:unique_id` placeholder and reconfigure gateway URL
|
|
61
|
+
- Return empty hash `{}` from `request_structure`
|
|
62
|
+
- Follow `Installments::Show` pattern for path interpolation
|
|
63
|
+
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8_
|
|
64
|
+
|
|
65
|
+
- [x]* 4.2 Write RSpec tests for Fetch request
|
|
66
|
+
- Create `spec/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_spec.rb`
|
|
67
|
+
- Verify endpoint URL with unique_id interpolation: `https://staging.gate.emerchantpay.net:443/v1/managed_recurring/items/{unique_id}`
|
|
68
|
+
- Verify HTTP GET method, JSON format, empty request body
|
|
69
|
+
- Verify required field validation raises error when unique_id is not set
|
|
70
|
+
- Verify unique_id attribute returns string
|
|
71
|
+
- Include shared examples: `'base request examples'`, `'versioned request examples'`
|
|
72
|
+
- _Requirements: 6.2_
|
|
73
|
+
|
|
74
|
+
- [x]* 4.3 Write property test for unique_id path interpolation (Fetch)
|
|
75
|
+
- **Property 1: Unique ID path interpolation**
|
|
76
|
+
- Generate random non-empty strings as unique_id, verify the built URL ends with `/managed_recurring/items/{unique_id}`
|
|
77
|
+
- **Validates: Requirements 3.3, 3.8**
|
|
78
|
+
|
|
79
|
+
- [x] 5. Implement Cancel request class
|
|
80
|
+
- [x] 5.1 Create `NonFinancial::ManagedRecurring::Cancel` request class
|
|
81
|
+
- Create `lib/genesis_ruby/api/requests/non_financial/managed_recurring/cancel.rb`
|
|
82
|
+
- Inherit from `Base::Versioned`, expose `unique_id` attribute (reader returns `.to_s`)
|
|
83
|
+
- Set `request_path = "#{ITEM_PATH}/:unique_id"`
|
|
84
|
+
- Override `init_configuration` to call `init_delete_configuration`
|
|
85
|
+
- Override `init_field_validations` to push `unique_id` to `required_fields`
|
|
86
|
+
- Override `process_request_parameters` to gsub `:unique_id` placeholder and reconfigure gateway URL
|
|
87
|
+
- Return empty hash `{}` from `request_structure`
|
|
88
|
+
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7_
|
|
89
|
+
|
|
90
|
+
- [x]* 5.2 Write RSpec tests for Cancel request
|
|
91
|
+
- Create `spec/genesis_ruby/api/requests/non_financial/managed_recurring/cancel_spec.rb`
|
|
92
|
+
- Verify endpoint URL with unique_id interpolation: `https://staging.gate.emerchantpay.net:443/v1/managed_recurring/items/{unique_id}`
|
|
93
|
+
- Verify HTTP DELETE method, JSON format, empty request body
|
|
94
|
+
- Verify required field validation raises error when unique_id is not set
|
|
95
|
+
- Verify unique_id attribute returns string
|
|
96
|
+
- Include shared examples: `'base request examples'`, `'versioned request examples'`
|
|
97
|
+
- _Requirements: 6.3_
|
|
98
|
+
|
|
99
|
+
- [x]* 5.3 Write property test for unique_id path interpolation (Cancel)
|
|
100
|
+
- **Property 1: Unique ID path interpolation**
|
|
101
|
+
- Generate random non-empty strings as unique_id, verify the built URL ends with `/managed_recurring/items/{unique_id}`
|
|
102
|
+
- **Validates: Requirements 4.3, 4.7**
|
|
103
|
+
|
|
104
|
+
- [x] 6. Checkpoint - Ensure all tests pass
|
|
105
|
+
- Ensure all tests pass, ask the user if questions arise.
|
|
106
|
+
|
|
107
|
+
- [x]* 6.1 Write property test for empty unique_id rejection
|
|
108
|
+
- **Property 2: Empty unique_id rejection**
|
|
109
|
+
- Generate nil/empty/whitespace-only strings, verify validation error is raised for both Fetch and Cancel
|
|
110
|
+
- **Validates: Requirements 3.7, 4.6**
|
|
111
|
+
|
|
112
|
+
- [x] 7. Final checkpoint - Ensure full test suite passes
|
|
113
|
+
- Run `bundle exec rspec` and `bundle exec rake styles` to confirm no failures or style violations.
|
|
114
|
+
- Ensure all tests pass, ask the user if questions arise.
|
|
115
|
+
|
|
116
|
+
## Notes
|
|
117
|
+
|
|
118
|
+
- Tasks marked with `*` are optional and can be skipped for faster MVP
|
|
119
|
+
- Each task references specific requirements for traceability
|
|
120
|
+
- Checkpoints ensure incremental validation
|
|
121
|
+
- Property tests validate universal correctness properties from the design document
|
|
122
|
+
- The `ITEM_PATH` constant value is `'managed_recurring/items'` (no `/v1/` prefix — `Base::Versioned` prepends version automatically)
|
|
123
|
+
- Path interpolation follows the same `:placeholder` pattern as `Installments::Show` and `Payee::Retrieve`
|
|
124
|
+
- HTTP DELETE support follows the `METHOD_PATCH`/`load_patch_config` precedent
|
|
125
|
+
- All new files are auto-loaded by `dependencies.rb` glob patterns
|
|
126
|
+
|
|
127
|
+
## Task Dependency Graph
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"waves": [
|
|
132
|
+
{ "id": 0, "tasks": ["1.1", "1.2", "2.1"] },
|
|
133
|
+
{ "id": 1, "tasks": ["1.3", "1.4", "3.1"] },
|
|
134
|
+
{ "id": 2, "tasks": ["3.2", "4.1", "5.1"] },
|
|
135
|
+
{ "id": 3, "tasks": ["4.2", "4.3", "5.2", "5.3"] },
|
|
136
|
+
{ "id": 4, "tasks": ["6.1"] }
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"specId": "55eb2a05-457c-4c7a-b5c5-23e33de035dc", "workflowType": "requirements-first", "specType": "feature"}
|