zai_payment 2.5.0 → 2.6.1

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.
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZaiPayment
4
+ module Resources
5
+ # BpayAccount resource for managing Zai BPay accounts
6
+ #
7
+ # @see https://developer.hellozai.com/reference/createbpayaccount
8
+ class BpayAccount
9
+ attr_reader :client
10
+
11
+ # Map of attribute keys to API field names
12
+ FIELD_MAPPING = {
13
+ user_id: :user_id,
14
+ account_name: :account_name,
15
+ biller_code: :biller_code,
16
+ bpay_crn: :bpay_crn
17
+ }.freeze
18
+
19
+ def initialize(client: nil)
20
+ @client = client || Client.new
21
+ end
22
+
23
+ # Get a specific BPay account by ID
24
+ #
25
+ # @param bpay_account_id [String] the BPay account ID
26
+ # @return [Response] the API response containing BPay account details
27
+ #
28
+ # @example
29
+ # bpay_accounts = ZaiPayment::Resources::BpayAccount.new
30
+ # response = bpay_accounts.show("bpay_account_id")
31
+ # response.data # => {"id" => "bpay_account_id", "active" => true, ...}
32
+ #
33
+ # @see https://developer.hellozai.com/reference/showbpayaccount
34
+ def show(bpay_account_id)
35
+ validate_id!(bpay_account_id, 'bpay_account_id')
36
+ client.get("/bpay_accounts/#{bpay_account_id}")
37
+ end
38
+
39
+ # Redact a BPay account
40
+ #
41
+ # Redacts a BPay account using the given bpay_account_id. Redacted BPay accounts
42
+ # can no longer be used as a disbursement destination.
43
+ #
44
+ # @param bpay_account_id [String] the BPay account ID
45
+ # @return [Response] the API response
46
+ #
47
+ # @example
48
+ # bpay_accounts = ZaiPayment::Resources::BpayAccount.new
49
+ # response = bpay_accounts.redact("bpay_account_id")
50
+ #
51
+ # @see https://developer.hellozai.com/reference/redactbpayaccount
52
+ def redact(bpay_account_id)
53
+ validate_id!(bpay_account_id, 'bpay_account_id')
54
+ client.delete("/bpay_accounts/#{bpay_account_id}")
55
+ end
56
+
57
+ # Get the user associated with a BPay account
58
+ #
59
+ # Show the User the BPay Account is associated with using a given bpay_account_id.
60
+ #
61
+ # @param bpay_account_id [String] the BPay account ID
62
+ # @return [Response] the API response containing user details
63
+ #
64
+ # @example
65
+ # bpay_accounts = ZaiPayment::Resources::BpayAccount.new
66
+ # response = bpay_accounts.show_user("bpay_account_id")
67
+ # response.data # => {"id" => "user_id", "full_name" => "Samuel Seller", ...}
68
+ #
69
+ # @see https://developer.hellozai.com/reference/showbpayaccountuser
70
+ def show_user(bpay_account_id)
71
+ validate_id!(bpay_account_id, 'bpay_account_id')
72
+ client.get("/bpay_accounts/#{bpay_account_id}/users")
73
+ end
74
+
75
+ # Create a new BPay account
76
+ #
77
+ # Create a BPay Account to be used as a Disbursement destination.
78
+ #
79
+ # @param attributes [Hash] BPay account attributes
80
+ # @option attributes [String] :user_id (Required) User ID
81
+ # @option attributes [String] :account_name (Required) Name assigned by the platform/marketplace
82
+ # to identify the account (similar to a nickname). Defaults to "My Water Bill Company"
83
+ # @option attributes [Integer] :biller_code (Required) The Biller Code for the biller that will
84
+ # receive the payment. The Biller Code must be a numeric value with 3 to 10 digits.
85
+ # @option attributes [String] :bpay_crn (Required) Customer reference number (crn) to be used for
86
+ # this bpay account. The CRN must contain between 2 and 20 digits. Defaults to "987654321"
87
+ # @return [Response] the API response containing created BPay account
88
+ #
89
+ # @example Create a BPay account
90
+ # bpay_accounts = ZaiPayment::Resources::BpayAccount.new
91
+ # response = bpay_accounts.create(
92
+ # user_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
93
+ # account_name: 'My Water Bill Company',
94
+ # biller_code: 123456,
95
+ # bpay_crn: '987654321'
96
+ # )
97
+ #
98
+ # @see https://developer.hellozai.com/reference/createbpayaccount
99
+ def create(**attributes)
100
+ validate_create_attributes!(attributes)
101
+
102
+ body = build_bpay_account_body(attributes)
103
+ client.post('/bpay_accounts', body: body)
104
+ end
105
+
106
+ private
107
+
108
+ def validate_id!(value, field_name)
109
+ return unless value.nil? || value.to_s.strip.empty?
110
+
111
+ raise Errors::ValidationError, "#{field_name} is required and cannot be blank"
112
+ end
113
+
114
+ def validate_create_attributes!(attributes)
115
+ validate_required_attributes!(attributes)
116
+ validate_biller_code!(attributes[:biller_code]) if attributes[:biller_code]
117
+ validate_bpay_crn!(attributes[:bpay_crn]) if attributes[:bpay_crn]
118
+ end
119
+
120
+ def validate_required_attributes!(attributes)
121
+ required_fields = %i[user_id account_name biller_code bpay_crn]
122
+
123
+ missing_fields = required_fields.select do |field|
124
+ attributes[field].nil? || (attributes[field].respond_to?(:to_s) && attributes[field].to_s.strip.empty?)
125
+ end
126
+
127
+ return if missing_fields.empty?
128
+
129
+ raise Errors::ValidationError,
130
+ "Missing required fields: #{missing_fields.join(', ')}"
131
+ end
132
+
133
+ def validate_biller_code!(biller_code)
134
+ # Biller code must be a numeric value with 3 to 10 digits
135
+ biller_code_str = biller_code.to_s
136
+
137
+ return if biller_code_str.match?(/\A\d{3,10}\z/)
138
+
139
+ raise Errors::ValidationError,
140
+ 'biller_code must be a numeric value with 3 to 10 digits'
141
+ end
142
+
143
+ def validate_bpay_crn!(bpay_crn)
144
+ # CRN must contain between 2 and 20 digits
145
+ bpay_crn_str = bpay_crn.to_s
146
+
147
+ return if bpay_crn_str.match?(/\A\d{2,20}\z/)
148
+
149
+ raise Errors::ValidationError,
150
+ 'bpay_crn must contain between 2 and 20 digits'
151
+ end
152
+
153
+ def build_bpay_account_body(attributes)
154
+ body = {}
155
+
156
+ attributes.each do |key, value|
157
+ next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
158
+
159
+ api_field = FIELD_MAPPING[key]
160
+ body[api_field] = value if api_field
161
+ end
162
+
163
+ body
164
+ end
165
+ end
166
+ end
167
+ end
@@ -277,7 +277,13 @@ module ZaiPayment
277
277
  # @example
278
278
  # users = ZaiPayment::Resources::User.new
279
279
  # response = users.wallet_account("user_id")
280
- # response.data # => {"id" => "...", "balance" => ..., ...}
280
+ # # The response.data method automatically extracts the wallet_accounts object
281
+ # wallet = response.data
282
+ # wallet["id"] # => "5c1c6b10-4c56-0137-8cd7-0242ac110002"
283
+ # wallet["balance"] # => 663337
284
+ # wallet["currency"] # => "AUD"
285
+ # wallet["active"] # => true
286
+ # wallet["links"]["transactions"] # => "/wallet_accounts/.../transactions"
281
287
  #
282
288
  # @see https://developer.hellozai.com/reference/showuserwalletaccounts
283
289
  def wallet_account(user_id)
@@ -8,7 +8,7 @@ module ZaiPayment
8
8
  RESPONSE_DATA_KEYS = %w[
9
9
  webhooks users items fees transactions
10
10
  batch_transactions bpay_accounts bank_accounts card_accounts
11
- routing_number
11
+ wallet_accounts routing_number
12
12
  ].freeze
13
13
 
14
14
  def initialize(faraday_response)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZaiPayment
4
- VERSION = '2.5.0'
4
+ VERSION = '2.6.1'
5
5
  end
data/lib/zai_payment.rb CHANGED
@@ -15,6 +15,7 @@ require_relative 'zai_payment/resources/user'
15
15
  require_relative 'zai_payment/resources/item'
16
16
  require_relative 'zai_payment/resources/token_auth'
17
17
  require_relative 'zai_payment/resources/bank_account'
18
+ require_relative 'zai_payment/resources/bpay_account'
18
19
 
19
20
  module ZaiPayment
20
21
  class << self
@@ -63,5 +64,10 @@ module ZaiPayment
63
64
  def bank_accounts
64
65
  @bank_accounts ||= Resources::BankAccount.new(client: Client.new(base_endpoint: :core_base))
65
66
  end
67
+
68
+ # @return [ZaiPayment::Resources::BpayAccount] bpay_account resource instance
69
+ def bpay_accounts
70
+ @bpay_accounts ||= Resources::BpayAccount.new(client: Client.new(base_endpoint: :core_base))
71
+ end
66
72
  end
67
73
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zai_payment
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eddy Jaga
@@ -69,6 +69,7 @@ files:
69
69
  - docs/architecture.md
70
70
  - docs/authentication.md
71
71
  - docs/bank_accounts.md
72
+ - docs/bpay_accounts.md
72
73
  - docs/items.md
73
74
  - docs/readme.md
74
75
  - docs/token_auths.md
@@ -79,13 +80,12 @@ files:
79
80
  - docs/webhook_signature.md
80
81
  - docs/webhooks.md
81
82
  - examples/bank_accounts.md
83
+ - examples/bpay_accounts.md
82
84
  - examples/items.md
83
85
  - examples/rails_card_payment.md
84
86
  - examples/token_auths.md
85
87
  - examples/users.md
86
88
  - examples/webhooks.md
87
- - implementation.md
88
- - implementation_summary.md
89
89
  - lib/zai_payment.rb
90
90
  - lib/zai_payment/auth/token_provider.rb
91
91
  - lib/zai_payment/auth/token_store.rb
@@ -94,6 +94,7 @@ files:
94
94
  - lib/zai_payment/config.rb
95
95
  - lib/zai_payment/errors.rb
96
96
  - lib/zai_payment/resources/bank_account.rb
97
+ - lib/zai_payment/resources/bpay_account.rb
97
98
  - lib/zai_payment/resources/item.rb
98
99
  - lib/zai_payment/resources/token_auth.rb
99
100
  - lib/zai_payment/resources/user.rb
data/implementation.md DELETED
@@ -1,304 +0,0 @@
1
- # User Management Implementation Summary
2
-
3
- ## Overview
4
-
5
- This document summarizes the implementation of the User Management feature for the Zai Payment Ruby library.
6
-
7
- ## Implementation Date
8
-
9
- October 23, 2025
10
-
11
- ## What Was Implemented
12
-
13
- ### 1. User Resource Class (`lib/zai_payment/resources/user.rb`)
14
-
15
- A comprehensive User resource that provides CRUD operations for managing both payin (buyer) and payout (seller/merchant) users.
16
-
17
- **Key Features:**
18
- - ✅ List users with pagination
19
- - ✅ Show user details by ID
20
- - ✅ Create payin users (buyers)
21
- - ✅ Create payout users (sellers/merchants)
22
- - ✅ Update user information
23
- - ✅ Comprehensive validation for all user types
24
- - ✅ Support for all Zai API user fields
25
-
26
- **Supported Fields:**
27
- - Email, first name, last name (required)
28
- - Country (ISO 3166-1 alpha-3 code, required)
29
- - Address details (line1, line2, city, state, zip)
30
- - Contact information (mobile, phone)
31
- - Date of birth (DD/MM/YYYY format)
32
- - Government ID number
33
- - Device ID and IP address (for fraud prevention)
34
- - User type designation (payin/payout)
35
-
36
- **Validation:**
37
- - Required field validation
38
- - Email format validation
39
- - Country code validation (3-letter ISO codes)
40
- - Date of birth format validation (DD/MM/YYYY)
41
- - User type validation (payin/payout)
42
-
43
- ### 2. Client Updates (`lib/zai_payment/client.rb`)
44
-
45
- **Changes:**
46
- - Added `base_endpoint` parameter to constructor
47
- - Updated `base_url` method to support multiple API endpoints
48
- - Users API uses `core_base` endpoint
49
- - Webhooks API uses `va_base` endpoint
50
-
51
- ### 3. Response Updates (`lib/zai_payment/response.rb`)
52
-
53
- **Changes:**
54
- - Updated `data` method to handle both `webhooks` and `users` response formats
55
- - Maintains backward compatibility with existing webhook code
56
-
57
- ### 4. Main Module Integration (`lib/zai_payment.rb`)
58
-
59
- **Changes:**
60
- - Added `require` for User resource
61
- - Added `users` accessor method
62
- - Properly configured User resource to use `core_base` endpoint
63
-
64
- ### 5. Comprehensive Test Suite (`spec/zai_payment/resources/user_spec.rb`)
65
-
66
- **Test Coverage:**
67
- - List users with pagination
68
- - Show user details
69
- - Create payin users with various configurations
70
- - Create payout users with required fields
71
- - Validation error handling
72
- - API error handling
73
- - Update operations
74
- - User type validation
75
- - Integration with main module
76
-
77
- **Test Statistics:**
78
- - 40+ test cases
79
- - Covers all CRUD operations
80
- - Tests both success and error scenarios
81
- - Validates all field types
82
- - Tests integration points
83
-
84
- ### 6. Documentation
85
-
86
- #### User Guide (`docs/users.md`)
87
- Comprehensive guide covering:
88
- - Overview of payin vs payout users
89
- - Required fields for each user type
90
- - Complete API reference
91
- - Field reference table
92
- - Error handling patterns
93
- - Best practices
94
- - Response structures
95
- - Complete examples
96
-
97
- #### Usage Examples (`examples/users.md`)
98
- Practical examples including:
99
- - Basic payin user creation
100
- - Complete payin user profiles
101
- - Progressive profile building
102
- - Individual payout users
103
- - International users (AU, UK, US)
104
- - List and pagination
105
- - Update operations
106
- - Error handling patterns
107
- - Rails integration example
108
- - Batch operations
109
- - User profile validation helper
110
- - RSpec integration tests
111
- - Common patterns with retry logic
112
-
113
- #### readme Updates (`readme.md`)
114
- - Added Users section with quick examples
115
- - Updated roadmap to mark Users as "Done"
116
- - Added documentation links
117
- - Updated Getting Started section
118
-
119
- ## API Endpoints
120
-
121
- The implementation works with the following Zai API endpoints:
122
-
123
- - `GET /users` - List users
124
- - `GET /users/:id` - Show user
125
- - `POST /users` - Create user
126
- - `PATCH /users/:id` - Update user
127
-
128
- ## Usage Examples
129
-
130
- ### Create a Payin User (Buyer)
131
-
132
- ```ruby
133
- response = ZaiPayment.users.create(
134
- email: 'buyer@example.com',
135
- first_name: 'John',
136
- last_name: 'Doe',
137
- country: 'USA',
138
- mobile: '+1234567890'
139
- )
140
-
141
- user_id = response.data['id']
142
- ```
143
-
144
- ### Create a Payout User (Seller/Merchant)
145
-
146
- ```ruby
147
- response = ZaiPayment.users.create(
148
- email: 'seller@example.com',
149
- first_name: 'Jane',
150
- last_name: 'Smith',
151
- country: 'AUS',
152
- dob: '01/01/1990',
153
- address_line1: '456 Market St',
154
- city: 'Sydney',
155
- state: 'NSW',
156
- zip: '2000',
157
- mobile: '+61412345678'
158
- )
159
-
160
- seller_id = response.data['id']
161
- ```
162
-
163
- ### List Users
164
-
165
- ```ruby
166
- response = ZaiPayment.users.list(limit: 10, offset: 0)
167
- users = response.data
168
- ```
169
-
170
- ### Show User
171
-
172
- ```ruby
173
- response = ZaiPayment.users.show('user_id')
174
- user = response.data
175
- ```
176
-
177
- ### Update User
178
-
179
- ```ruby
180
- response = ZaiPayment.users.update(
181
- 'user_id',
182
- mobile: '+9876543210',
183
- address_line1: '789 New St'
184
- )
185
- ```
186
-
187
- ## Key Differences: Payin vs Payout Users
188
-
189
- ### Payin User (Buyer) Requirements
190
- **Required:**
191
- - Email, first name, last name, country
192
- - Device ID and IP address (when charging)
193
-
194
- **Recommended:**
195
- - Address, city, state, zip
196
- - Mobile, DOB
197
-
198
- ### Payout User (Seller/Merchant) Requirements
199
- **Required:**
200
- - Email, first name, last name, country
201
- - Address, city, state, zip
202
- - Date of birth (DD/MM/YYYY format)
203
-
204
- **Recommended:**
205
- - Mobile, government number
206
-
207
- ## Validation Rules
208
-
209
- 1. **Email**: Must be valid email format
210
- 2. **Country**: Must be 3-letter ISO 3166-1 alpha-3 code (e.g., USA, AUS, GBR)
211
- 3. **Date of Birth**: Must be DD/MM/YYYY format (e.g., 01/01/1990)
212
- 4. **User Type**: Must be 'payin' or 'payout' (optional field)
213
-
214
- ## Error Handling
215
-
216
- The implementation provides proper error handling for:
217
- - `ValidationError` - Missing or invalid fields
218
- - `UnauthorizedError` - Authentication failures
219
- - `NotFoundError` - User not found
220
- - `ApiError` - General API errors
221
- - `ConnectionError` - Network issues
222
- - `TimeoutError` - Request timeouts
223
-
224
- ## Best Practices Implemented
225
-
226
- 1. **Progressive Profile Building**: Create users with minimal info, update later
227
- 2. **Proper Validation**: Validate data before API calls
228
- 3. **Error Recovery**: Handle errors gracefully with proper error classes
229
- 4. **Type Safety**: Validate user types and field formats
230
- 5. **Documentation**: Comprehensive guides and examples
231
- 6. **Testing**: Extensive test coverage for all scenarios
232
-
233
- ## Files Created/Modified
234
-
235
- ### Created Files:
236
- 1. `/lib/zai_payment/resources/user.rb` - User resource class
237
- 2. `/spec/zai_payment/resources/user_spec.rb` - Test suite
238
- 3. `/docs/users.md` - User management guide
239
- 4. `/examples/users.md` - Usage examples
240
-
241
- ### Modified Files:
242
- 1. `/lib/zai_payment/client.rb` - Added endpoint support
243
- 2. `/lib/zai_payment/response.rb` - Added users data handling
244
- 3. `/lib/zai_payment.rb` - Integrated User resource
245
- 4. `/readme.md` - Added Users section and updated roadmap
246
-
247
- ## Code Quality
248
-
249
- - ✅ No linter errors
250
- - ✅ Follows existing code patterns
251
- - ✅ Comprehensive test coverage
252
- - ✅ Well-documented with YARD comments
253
- - ✅ Follows Ruby best practices
254
- - ✅ Consistent with webhook implementation
255
-
256
- ## Architecture Decisions
257
-
258
- 1. **Endpoint Routing**: Users use `core_base`, webhooks use `va_base`
259
- 2. **Validation Strategy**: Client-side validation before API calls
260
- 3. **Field Mapping**: Direct 1:1 mapping with Zai API fields
261
- 4. **Error Handling**: Leverage existing error class hierarchy
262
- 5. **Testing Approach**: Match webhook test patterns
263
-
264
- ## Integration Points
265
-
266
- The User resource integrates seamlessly with:
267
- - Authentication system (OAuth2 tokens)
268
- - Error handling framework
269
- - Response wrapper
270
- - Configuration management
271
- - Testing infrastructure
272
-
273
- ## Next Steps
274
-
275
- The implementation is complete and ready for use. Recommended next steps:
276
-
277
- 1. ✅ Run the full test suite
278
- 2. ✅ Review documentation
279
- 3. ✅ Try examples in development environment
280
- 4. Consider adding:
281
- - Company user support (for payout users)
282
- - User verification status checking
283
- - Bank account associations
284
- - Payment method attachments
285
-
286
- ## References
287
-
288
- - [Zai: Onboarding a Payin User](https://developer.hellozai.com/docs/onboarding-a-pay-in-user)
289
- - [Zai: Onboarding a Payout User](https://developer.hellozai.com/docs/onboarding-a-pay-out-user)
290
- - [Zai API Reference](https://developer.hellozai.com/reference)
291
-
292
- ## Support
293
-
294
- For questions or issues:
295
- 1. Check the documentation in `/docs/users.md`
296
- 2. Review examples in `/examples/users.md`
297
- 3. Run tests: `bundle exec rspec spec/zai_payment/resources/user_spec.rb`
298
- 4. Refer to Zai Developer Portal: https://developer.hellozai.com/
299
-
300
- ---
301
-
302
- **Implementation completed successfully! 🎉**
303
-
304
- All CRUD operations for User management are now available in the ZaiPayment gem, following best practices and maintaining consistency with the existing codebase.