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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.kiro/specs/f2025112509-add_managed_recurring_api/.config.kiro +1 -0
  3. data/.kiro/specs/f2025112509-add_managed_recurring_api/design.md +332 -0
  4. data/.kiro/specs/f2025112509-add_managed_recurring_api/requirements.md +91 -0
  5. data/.kiro/specs/f2025112509-add_managed_recurring_api/tasks.md +139 -0
  6. data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/.config.kiro +1 -0
  7. data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/design.md +148 -0
  8. data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/requirements.md +81 -0
  9. data/.kiro/specs/f2025112603-add_reverify_endpoint_to_payee_account/tasks.md +48 -0
  10. data/.kiro/specs/f2025112606-add_list_payees_trx_request/.config.kiro +1 -0
  11. data/.kiro/specs/f2025112606-add_list_payees_trx_request/design.md +112 -0
  12. data/.kiro/specs/f2025112606-add_list_payees_trx_request/requirements.md +74 -0
  13. data/.kiro/specs/f2025112606-add_list_payees_trx_request/tasks.md +38 -0
  14. data/.kiro/specs/f2025112609_update_payee_request_params/design.md +86 -0
  15. data/.kiro/specs/f2025112609_update_payee_request_params/requirements.md +86 -0
  16. data/.kiro/specs/f2025112609_update_payee_request_params/tasks.md +40 -0
  17. data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/.config.kiro +1 -0
  18. data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/design.md +246 -0
  19. data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/requirements.md +287 -0
  20. data/.kiro/specs/f2025112612-add_payee_owner_documents_and_verification_requests/tasks.md +76 -0
  21. data/.kiro/specs/f2025112614-add_money_transfer_payout_attributes_to_payout_rq/design.md +84 -0
  22. data/.kiro/specs/f2025112614-add_money_transfer_payout_attributes_to_payout_rq/requirements.md +88 -0
  23. data/.kiro/specs/f2025112614-add_money_transfer_payout_attributes_to_payout_rq/tasks.md +38 -0
  24. data/.kiro/steering/product.md +15 -0
  25. data/.kiro/steering/spec-folder-naming.md +16 -0
  26. data/.kiro/steering/structure.md +96 -0
  27. data/.kiro/steering/tech.md +66 -0
  28. data/CHANGELOG.md +23 -0
  29. data/Gemfile.lock +4 -4
  30. data/README.md +33 -0
  31. data/VERSION +1 -1
  32. data/lib/genesis_ruby/api/constants/non_financial/kyc/address_document_supported_types.rb +81 -0
  33. data/lib/genesis_ruby/api/constants/non_financial/payee/document_types.rb +57 -0
  34. data/lib/genesis_ruby/api/constants/non_financial/payee/owner_types.rb +30 -0
  35. data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/purpose_of_payments.rb +50 -0
  36. data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/sender_account_number_types.rb +50 -0
  37. data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/source_of_funds.rb +44 -0
  38. data/lib/genesis_ruby/api/constants/transactions/parameters/money_transfer/types.rb +26 -0
  39. data/lib/genesis_ruby/api/constants/transactions/parameters/non_financial/billing_api/statement_response_fields.rb +37 -0
  40. data/lib/genesis_ruby/api/mixins/requests/financial/cards/mpi_attributes.rb +0 -10
  41. data/lib/genesis_ruby/api/mixins/requests/financial/money_transfer_payout_attributes.rb +131 -0
  42. data/lib/genesis_ruby/api/mixins/requests/non_financial/date_attributes.rb +87 -5
  43. data/lib/genesis_ruby/api/mixins/requests/non_financial/kyc/business_attributes.rb +42 -0
  44. data/lib/genesis_ruby/api/mixins/requests/non_financial/kyc/document_attributes.rb +8 -7
  45. data/lib/genesis_ruby/api/request.rb +15 -9
  46. data/lib/genesis_ruby/api/requests/base/non_financial/billing_api/base.rb +108 -0
  47. data/lib/genesis_ruby/api/requests/base/non_financial/payee/base.rb +54 -0
  48. data/lib/genesis_ruby/api/requests/financial/cards/authorize3d.rb +1 -3
  49. data/lib/genesis_ruby/api/requests/financial/cards/payout.rb +3 -1
  50. data/lib/genesis_ruby/api/requests/financial/cards/sale3d.rb +1 -3
  51. data/lib/genesis_ruby/api/requests/non_financial/billing_api/statement.rb +170 -0
  52. data/lib/genesis_ruby/api/requests/non_financial/billing_api/transactions.rb +20 -60
  53. data/lib/genesis_ruby/api/requests/non_financial/kyc/business/create.rb +45 -0
  54. data/lib/genesis_ruby/api/requests/non_financial/kyc/business/document.rb +60 -0
  55. data/lib/genesis_ruby/api/requests/non_financial/kyc/business/document_list.rb +59 -0
  56. data/lib/genesis_ruby/api/requests/non_financial/kyc/business/verification.rb +52 -0
  57. data/lib/genesis_ruby/api/requests/non_financial/kyc/verifications/address_by_document_proof.rb +92 -0
  58. data/lib/genesis_ruby/api/requests/non_financial/kyc/verifications/create.rb +4 -1
  59. data/lib/genesis_ruby/api/requests/non_financial/managed_recurring/cancel.rb +63 -0
  60. data/lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch.rb +63 -0
  61. data/lib/genesis_ruby/api/requests/non_financial/managed_recurring/fetch_all.rb +37 -0
  62. data/lib/genesis_ruby/api/requests/non_financial/payee/account/reverify.rb +61 -0
  63. data/lib/genesis_ruby/api/requests/non_financial/payee/associate_payee_with_owners.rb +105 -0
  64. data/lib/genesis_ruby/api/requests/non_financial/payee/create.rb +37 -7
  65. data/lib/genesis_ruby/api/requests/non_financial/payee/create_payee_document.rb +61 -0
  66. data/lib/genesis_ruby/api/requests/non_financial/payee/dissociate_payee_with_owners.rb +94 -0
  67. data/lib/genesis_ruby/api/requests/non_financial/payee/list.rb +38 -0
  68. data/lib/genesis_ruby/api/requests/non_financial/payee/list_payee_documents.rb +57 -0
  69. data/lib/genesis_ruby/api/requests/non_financial/payee/list_payee_owners.rb +70 -0
  70. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/associate_owner_with_owners.rb +109 -0
  71. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/create.rb +71 -0
  72. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/create_owner_document.rb +63 -0
  73. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/delete.rb +54 -0
  74. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/dissociate_owners.rb +96 -0
  75. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/list_owner_documents.rb +59 -0
  76. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/list_owners.rb +46 -0
  77. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/retrieve.rb +59 -0
  78. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/retrieve_owner_document.rb +62 -0
  79. data/lib/genesis_ruby/api/requests/non_financial/payee/owners/update.rb +66 -0
  80. data/lib/genesis_ruby/api/requests/non_financial/payee/retrieve_payee_document.rb +60 -0
  81. data/lib/genesis_ruby/api/requests/non_financial/payee/update.rb +34 -4
  82. data/lib/genesis_ruby/api/requests/non_financial/payee/verifications/create_payee_verification.rb +58 -0
  83. data/lib/genesis_ruby/api/requests/non_financial/payee/verifications/list_payee_verifications.rb +59 -0
  84. data/lib/genesis_ruby/api/requests/non_financial/payee/verifications/retrieve_payee_verification.rb +62 -0
  85. data/lib/genesis_ruby/api/requests/non_financial/tokenization/retokenize.rb +45 -0
  86. data/lib/genesis_ruby/api/requests/wpf/create.rb +19 -0
  87. data/lib/genesis_ruby/api/response.rb +15 -0
  88. data/lib/genesis_ruby/dependencies.rb +2 -0
  89. data/lib/genesis_ruby/network/adapter/net_http_adapter.rb +31 -5
  90. data/lib/genesis_ruby/network/base_network.rb +5 -0
  91. data/lib/genesis_ruby/network/net_http.rb +16 -4
  92. data/lib/genesis_ruby/utils/options/api_config.rb +43 -32
  93. data/lib/genesis_ruby/utils/options/network_adapter_config.rb +1 -1
  94. data/lib/genesis_ruby/version.rb +1 -1
  95. metadata +72 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12cd3e939b78536020d57469e7220098680c647f13ab38c88413b2e63d01fea0
4
- data.tar.gz: 1073ba6ff04f83a1832c49960d3e448418bc04697921d4843cd8c05ec6201e42
3
+ metadata.gz: 25761ad9b4ff17bdcd71f0b5e084c4fce9cbfc5754ade3addf54debd8fcac1df
4
+ data.tar.gz: 181e7917e70576f2cca9d38e7b59eef4799030ba21fcd52231e78206913827cc
5
5
  SHA512:
6
- metadata.gz: d003f0096e584454c1bae7e50d5414a0c1361e17619acd15f83e62782fa74988c3c0739cac2fec826ad9c28736bc5705293dcbfa5c861aead55e5556db9fe6ae
7
- data.tar.gz: d47c721dc4883cbb8d447dc0373b354a4663bef49f9ea512b836e679a7646b9c5da7ed4ab10cbad4b1b234f33fe6003cf3c56b385f33c62f08c6d3b0cae2b5bc
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"}