zai_payment 2.9.0 → 2.9.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.
- checksums.yaml +4 -4
- data/lib/zai_payment/version.rb +1 -1
- metadata +6 -43
- data/.yardopts +0 -3
- data/IMPLEMENTATION_SUMMARY.md +0 -183
- data/RESPONSE_FORMAT_CORRECTION.md +0 -75
- data/Rakefile +0 -12
- data/badges/.gitkeep +0 -2
- data/badges/coverage.json +0 -1
- data/changelog.md +0 -750
- data/code_of_conduct.md +0 -132
- data/contributing.md +0 -383
- data/docs/architecture.md +0 -232
- data/docs/authentication.md +0 -647
- data/docs/bank_accounts.md +0 -496
- data/docs/batch_transactions.md +0 -340
- data/docs/bpay_accounts.md +0 -519
- data/docs/direct_api_usage.md +0 -489
- data/docs/items.md +0 -1241
- data/docs/pay_ids.md +0 -777
- data/docs/readme.md +0 -111
- data/docs/token_auths.md +0 -523
- data/docs/user_id_field.md +0 -284
- data/docs/user_quick_reference.md +0 -230
- data/docs/users.md +0 -750
- data/docs/virtual_accounts.md +0 -916
- data/docs/wallet_accounts.md +0 -493
- data/docs/webhook_security_quickstart.md +0 -136
- data/docs/webhook_signature.md +0 -244
- data/docs/webhooks.md +0 -417
- data/examples/bank_accounts.md +0 -637
- data/examples/batch_transactions.md +0 -450
- data/examples/bpay_accounts.md +0 -642
- data/examples/items.md +0 -2713
- data/examples/pay_ids.md +0 -871
- data/examples/rails_card_payment.md +0 -1252
- data/examples/token_auths.md +0 -687
- data/examples/users.md +0 -765
- data/examples/virtual_accounts.md +0 -1530
- data/examples/wallet_accounts.md +0 -733
- data/examples/webhooks.md +0 -635
- data/readme.md +0 -357
- data/sig/zai_payment.rbs +0 -4
data/examples/users.md
DELETED
|
@@ -1,765 +0,0 @@
|
|
|
1
|
-
# User Management Examples
|
|
2
|
-
|
|
3
|
-
This document provides practical examples for managing users in Zai Payment.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Setup](#setup)
|
|
8
|
-
- [Payin User Examples](#payin-user-examples)
|
|
9
|
-
- [Payout User Examples](#payout-user-examples)
|
|
10
|
-
- [Advanced Usage](#advanced-usage)
|
|
11
|
-
|
|
12
|
-
## Setup
|
|
13
|
-
|
|
14
|
-
```ruby
|
|
15
|
-
require 'zai_payment'
|
|
16
|
-
|
|
17
|
-
# Configure ZaiPayment
|
|
18
|
-
ZaiPayment.configure do |config|
|
|
19
|
-
config.environment = :prelive # or :production
|
|
20
|
-
config.client_id = ENV['ZAI_CLIENT_ID']
|
|
21
|
-
config.client_secret = ENV['ZAI_CLIENT_SECRET']
|
|
22
|
-
config.scope = ENV['ZAI_SCOPE']
|
|
23
|
-
end
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Payin User Examples
|
|
27
|
-
|
|
28
|
-
### Example 1: Basic Payin User (Buyer)
|
|
29
|
-
|
|
30
|
-
Create a buyer with minimal required information.
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
# Create a basic payin user
|
|
34
|
-
response = ZaiPayment.users.create(
|
|
35
|
-
user_type: 'payin',
|
|
36
|
-
email: 'buyer@example.com',
|
|
37
|
-
first_name: 'John',
|
|
38
|
-
last_name: 'Doe',
|
|
39
|
-
country: 'USA'
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
if response.success?
|
|
43
|
-
user = response.data
|
|
44
|
-
puts "Payin user created successfully!"
|
|
45
|
-
puts "User ID: #{user['id']}"
|
|
46
|
-
puts "Email: #{user['email']}"
|
|
47
|
-
|
|
48
|
-
# Note: device_id and ip_address will be required later
|
|
49
|
-
# when creating an item and charging a card
|
|
50
|
-
else
|
|
51
|
-
puts "Failed to create user"
|
|
52
|
-
end
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Example 2: Payin User with Complete Profile
|
|
56
|
-
|
|
57
|
-
Create a buyer with all recommended information for better fraud prevention.
|
|
58
|
-
|
|
59
|
-
```ruby
|
|
60
|
-
response = ZaiPayment.users.create(
|
|
61
|
-
# Required fields
|
|
62
|
-
user_type: 'payin',
|
|
63
|
-
email: 'john.buyer@example.com',
|
|
64
|
-
first_name: 'John',
|
|
65
|
-
last_name: 'Doe',
|
|
66
|
-
country: 'USA',
|
|
67
|
-
|
|
68
|
-
# Recommended fields
|
|
69
|
-
address_line1: '123 Main Street',
|
|
70
|
-
address_line2: 'Apt 4B',
|
|
71
|
-
city: 'New York',
|
|
72
|
-
state: 'NY',
|
|
73
|
-
zip: '10001',
|
|
74
|
-
mobile: '+1234567890',
|
|
75
|
-
dob: '15/01/1990'
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
user = response.data
|
|
79
|
-
puts "Complete payin user profile created: #{user['id']}"
|
|
80
|
-
|
|
81
|
-
# Note: device_id and ip_address can be stored separately
|
|
82
|
-
# and will be required when creating an item and charging a card
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Example 3: Progressive Profile Building
|
|
86
|
-
|
|
87
|
-
Create a user quickly, then update with additional information later.
|
|
88
|
-
|
|
89
|
-
```ruby
|
|
90
|
-
# Step 1: Quick user creation during signup
|
|
91
|
-
response = ZaiPayment.users.create(
|
|
92
|
-
user_type: 'payin',
|
|
93
|
-
email: 'quicksignup@example.com',
|
|
94
|
-
first_name: 'Jane',
|
|
95
|
-
last_name: 'Smith',
|
|
96
|
-
country: 'AUS'
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
user_id = response.data['id']
|
|
100
|
-
puts "User created quickly: #{user_id}"
|
|
101
|
-
|
|
102
|
-
# Step 2: Update with shipping address during checkout
|
|
103
|
-
ZaiPayment.users.update(
|
|
104
|
-
user_id,
|
|
105
|
-
address_line1: '456 Collins Street',
|
|
106
|
-
city: 'Melbourne',
|
|
107
|
-
state: 'VIC',
|
|
108
|
-
zip: '3000',
|
|
109
|
-
mobile: '+61412345678'
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
puts "User profile updated with shipping address"
|
|
113
|
-
|
|
114
|
-
# Note: device_id and ip_address should be captured during
|
|
115
|
-
# payment flow and will be required when creating an item
|
|
116
|
-
# They are not stored in the user profile, but used at transaction time
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Payout User Examples
|
|
120
|
-
|
|
121
|
-
### Example 4: Individual Payout User (Seller)
|
|
122
|
-
|
|
123
|
-
Create a seller who will receive payments. All required fields must be provided.
|
|
124
|
-
|
|
125
|
-
```ruby
|
|
126
|
-
response = ZaiPayment.users.create(
|
|
127
|
-
# User type
|
|
128
|
-
user_type: 'payout',
|
|
129
|
-
|
|
130
|
-
# Required for payout users
|
|
131
|
-
email: 'seller@example.com',
|
|
132
|
-
first_name: 'Alice',
|
|
133
|
-
last_name: 'Johnson',
|
|
134
|
-
country: 'USA',
|
|
135
|
-
dob: '20/03/1985',
|
|
136
|
-
address_line1: '789 Market Street',
|
|
137
|
-
city: 'San Francisco',
|
|
138
|
-
state: 'CA',
|
|
139
|
-
zip: '94103',
|
|
140
|
-
|
|
141
|
-
# Recommended
|
|
142
|
-
mobile: '+14155551234',
|
|
143
|
-
government_number: '123456789' # SSN or Tax ID
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
seller = response.data
|
|
147
|
-
puts "Payout user created: #{seller['id']}"
|
|
148
|
-
puts "Verification state: #{seller['verification_state']}"
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Example 5: Australian Payout User
|
|
152
|
-
|
|
153
|
-
Create an Australian seller with appropriate details.
|
|
154
|
-
|
|
155
|
-
```ruby
|
|
156
|
-
response = ZaiPayment.users.create(
|
|
157
|
-
user_type: 'payout',
|
|
158
|
-
email: 'aussie.seller@example.com',
|
|
159
|
-
first_name: 'Bruce',
|
|
160
|
-
last_name: 'Williams',
|
|
161
|
-
country: 'AUS',
|
|
162
|
-
dob: '10/07/1980',
|
|
163
|
-
|
|
164
|
-
# Australian address
|
|
165
|
-
address_line1: '123 George Street',
|
|
166
|
-
city: 'Sydney',
|
|
167
|
-
state: 'NSW',
|
|
168
|
-
zip: '2000',
|
|
169
|
-
|
|
170
|
-
mobile: '+61298765432',
|
|
171
|
-
government_number: '123456789' # TFN (Tax File Number)
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
if response.success?
|
|
175
|
-
seller = response.data
|
|
176
|
-
puts "Australian seller created: #{seller['id']}"
|
|
177
|
-
puts "Ready for bank account setup"
|
|
178
|
-
end
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### Example 6: UK Payout User
|
|
182
|
-
|
|
183
|
-
Create a UK-based seller.
|
|
184
|
-
|
|
185
|
-
```ruby
|
|
186
|
-
response = ZaiPayment.users.create(
|
|
187
|
-
user_type: 'payout',
|
|
188
|
-
email: 'uk.merchant@example.com',
|
|
189
|
-
first_name: 'Oliver',
|
|
190
|
-
last_name: 'Brown',
|
|
191
|
-
country: 'GBR', # ISO 3166-1 alpha-3 code for United Kingdom
|
|
192
|
-
dob: '05/05/1992',
|
|
193
|
-
|
|
194
|
-
# UK address
|
|
195
|
-
address_line1: '10 Downing Street',
|
|
196
|
-
city: 'London',
|
|
197
|
-
state: 'England',
|
|
198
|
-
zip: 'SW1A 2AA',
|
|
199
|
-
|
|
200
|
-
mobile: '+447700900123',
|
|
201
|
-
government_number: 'AB123456C' # National Insurance Number
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
merchant = response.data
|
|
205
|
-
puts "UK merchant created: #{merchant['id']}"
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## Advanced Usage
|
|
209
|
-
|
|
210
|
-
### Example 7: List and Search Users
|
|
211
|
-
|
|
212
|
-
Retrieve and paginate through your users.
|
|
213
|
-
|
|
214
|
-
```ruby
|
|
215
|
-
# Get first page of users
|
|
216
|
-
page1 = ZaiPayment.users.list(limit: 10, offset: 0)
|
|
217
|
-
|
|
218
|
-
puts "Total users: #{page1.meta['total']}"
|
|
219
|
-
puts "Showing: #{page1.data.length} users"
|
|
220
|
-
|
|
221
|
-
page1.data.each_with_index do |user, index|
|
|
222
|
-
puts "#{index + 1}. #{user['email']} - #{user['first_name']} #{user['last_name']}"
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
# Get next page
|
|
226
|
-
page2 = ZaiPayment.users.list(limit: 10, offset: 10)
|
|
227
|
-
puts "\nNext page has #{page2.data.length} users"
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### Example 8: Get User Details
|
|
231
|
-
|
|
232
|
-
Retrieve complete details for a specific user.
|
|
233
|
-
|
|
234
|
-
```ruby
|
|
235
|
-
user_id = 'user_abc123'
|
|
236
|
-
|
|
237
|
-
response = ZaiPayment.users.show(user_id)
|
|
238
|
-
|
|
239
|
-
if response.success?
|
|
240
|
-
user = response.data
|
|
241
|
-
|
|
242
|
-
puts "User Details:"
|
|
243
|
-
puts " ID: #{user['id']}"
|
|
244
|
-
puts " Email: #{user['email']}"
|
|
245
|
-
puts " Name: #{user['first_name']} #{user['last_name']}"
|
|
246
|
-
puts " Country: #{user['country']}"
|
|
247
|
-
puts " City: #{user['city']}, #{user['state']}"
|
|
248
|
-
puts " Created: #{user['created_at']}"
|
|
249
|
-
puts " Verification: #{user['verification_state']}"
|
|
250
|
-
end
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Example 9: Update Multiple Fields
|
|
254
|
-
|
|
255
|
-
Update several user fields at once.
|
|
256
|
-
|
|
257
|
-
```ruby
|
|
258
|
-
user_id = 'user_abc123'
|
|
259
|
-
|
|
260
|
-
response = ZaiPayment.users.update(
|
|
261
|
-
user_id,
|
|
262
|
-
email: 'newemail@example.com',
|
|
263
|
-
mobile: '+1555123456',
|
|
264
|
-
address_line1: '999 Updated Street',
|
|
265
|
-
city: 'Boston',
|
|
266
|
-
state: 'MA',
|
|
267
|
-
zip: '02101'
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
updated_user = response.data
|
|
271
|
-
puts "User #{user_id} updated successfully"
|
|
272
|
-
puts "New email: #{updated_user['email']}"
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### Example 10: Error Handling
|
|
276
|
-
|
|
277
|
-
Properly handle validation and API errors.
|
|
278
|
-
|
|
279
|
-
```ruby
|
|
280
|
-
begin
|
|
281
|
-
response = ZaiPayment.users.create(
|
|
282
|
-
email: 'invalid-email', # Invalid format
|
|
283
|
-
first_name: 'Test',
|
|
284
|
-
last_name: 'User',
|
|
285
|
-
country: 'US' # Invalid: should be 3 letters
|
|
286
|
-
)
|
|
287
|
-
rescue ZaiPayment::Errors::ValidationError => e
|
|
288
|
-
puts "Validation failed: #{e.message}"
|
|
289
|
-
# Handle validation errors (e.g., show to user)
|
|
290
|
-
|
|
291
|
-
rescue ZaiPayment::Errors::UnauthorizedError => e
|
|
292
|
-
puts "Authentication failed: #{e.message}"
|
|
293
|
-
# Refresh token and retry
|
|
294
|
-
ZaiPayment.refresh_token!
|
|
295
|
-
retry
|
|
296
|
-
|
|
297
|
-
rescue ZaiPayment::Errors::NotFoundError => e
|
|
298
|
-
puts "Resource not found: #{e.message}"
|
|
299
|
-
|
|
300
|
-
rescue ZaiPayment::Errors::ApiError => e
|
|
301
|
-
puts "API error occurred: #{e.message}"
|
|
302
|
-
# Log error for debugging
|
|
303
|
-
|
|
304
|
-
rescue ZaiPayment::Errors::ConnectionError => e
|
|
305
|
-
puts "Connection failed: #{e.message}"
|
|
306
|
-
# Retry with exponential backoff
|
|
307
|
-
|
|
308
|
-
rescue ZaiPayment::Errors::TimeoutError => e
|
|
309
|
-
puts "Request timed out: #{e.message}"
|
|
310
|
-
# Retry request
|
|
311
|
-
end
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Example 11: Batch User Creation
|
|
315
|
-
|
|
316
|
-
Create multiple users efficiently.
|
|
317
|
-
|
|
318
|
-
```ruby
|
|
319
|
-
users_to_create = [
|
|
320
|
-
{
|
|
321
|
-
user_type: 'payin',
|
|
322
|
-
email: 'buyer1@example.com',
|
|
323
|
-
first_name: 'Alice',
|
|
324
|
-
last_name: 'Anderson',
|
|
325
|
-
country: 'USA'
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
user_type: 'payin',
|
|
329
|
-
email: 'buyer2@example.com',
|
|
330
|
-
first_name: 'Bob',
|
|
331
|
-
last_name: 'Brown',
|
|
332
|
-
country: 'USA'
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
user_type: 'payout',
|
|
336
|
-
email: 'seller1@example.com',
|
|
337
|
-
first_name: 'Charlie',
|
|
338
|
-
last_name: 'Chen',
|
|
339
|
-
country: 'AUS',
|
|
340
|
-
dob: '01/01/1990',
|
|
341
|
-
address_line1: '123 Test St',
|
|
342
|
-
city: 'Sydney',
|
|
343
|
-
state: 'NSW',
|
|
344
|
-
zip: '2000'
|
|
345
|
-
}
|
|
346
|
-
]
|
|
347
|
-
|
|
348
|
-
created_users = []
|
|
349
|
-
failed_users = []
|
|
350
|
-
|
|
351
|
-
users_to_create.each do |user_data|
|
|
352
|
-
begin
|
|
353
|
-
response = ZaiPayment.users.create(**user_data)
|
|
354
|
-
created_users << response.data
|
|
355
|
-
puts "✓ Created: #{user_data[:email]}"
|
|
356
|
-
rescue ZaiPayment::Errors::ApiError => e
|
|
357
|
-
failed_users << { user: user_data, error: e.message }
|
|
358
|
-
puts "✗ Failed: #{user_data[:email]} - #{e.message}"
|
|
359
|
-
end
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
puts "\nSummary:"
|
|
363
|
-
puts "Created: #{created_users.length} users"
|
|
364
|
-
puts "Failed: #{failed_users.length} users"
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### Example 12: User Profile Validator
|
|
368
|
-
|
|
369
|
-
Create a helper to validate user data before API call.
|
|
370
|
-
|
|
371
|
-
```ruby
|
|
372
|
-
class UserValidator
|
|
373
|
-
def self.validate_payin(attributes)
|
|
374
|
-
errors = []
|
|
375
|
-
|
|
376
|
-
errors << "Email is required" unless attributes[:email]
|
|
377
|
-
errors << "First name is required" unless attributes[:first_name]
|
|
378
|
-
errors << "Last name is required" unless attributes[:last_name]
|
|
379
|
-
errors << "Country is required" unless attributes[:country]
|
|
380
|
-
|
|
381
|
-
if attributes[:email] && !valid_email?(attributes[:email])
|
|
382
|
-
errors << "Email format is invalid"
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
if attributes[:country] && attributes[:country].length != 3
|
|
386
|
-
errors << "Country must be 3-letter ISO code"
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
if attributes[:dob] && !valid_dob?(attributes[:dob])
|
|
390
|
-
errors << "DOB must be in DD/MM/YYYY format"
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
errors
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
def self.validate_payout(attributes)
|
|
397
|
-
errors = validate_payin(attributes)
|
|
398
|
-
|
|
399
|
-
# Additional required fields for payout users
|
|
400
|
-
errors << "Address is required for payout users" unless attributes[:address_line1]
|
|
401
|
-
errors << "City is required for payout users" unless attributes[:city]
|
|
402
|
-
errors << "State is required for payout users" unless attributes[:state]
|
|
403
|
-
errors << "Zip is required for payout users" unless attributes[:zip]
|
|
404
|
-
errors << "DOB is required for payout users" unless attributes[:dob]
|
|
405
|
-
|
|
406
|
-
errors
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
private
|
|
410
|
-
|
|
411
|
-
def self.valid_email?(email)
|
|
412
|
-
email.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/)
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
def self.valid_dob?(dob)
|
|
416
|
-
dob.to_s.match?(%r{\A\d{2}/\d{2}/\d{4}\z})
|
|
417
|
-
end
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
# Usage
|
|
421
|
-
user_data = {
|
|
422
|
-
email: 'test@example.com',
|
|
423
|
-
first_name: 'Test',
|
|
424
|
-
last_name: 'User',
|
|
425
|
-
country: 'USA'
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
errors = UserValidator.validate_payin(user_data)
|
|
429
|
-
|
|
430
|
-
if errors.empty?
|
|
431
|
-
response = ZaiPayment.users.create(**user_data)
|
|
432
|
-
puts "User created: #{response.data['id']}"
|
|
433
|
-
else
|
|
434
|
-
puts "Validation errors:"
|
|
435
|
-
errors.each { |error| puts " - #{error}" }
|
|
436
|
-
end
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
### Example 13: Rails Integration
|
|
440
|
-
|
|
441
|
-
Example of integrating with a Rails application.
|
|
442
|
-
|
|
443
|
-
```ruby
|
|
444
|
-
# app/models/user.rb
|
|
445
|
-
class User < ApplicationRecord
|
|
446
|
-
after_create :create_zai_user
|
|
447
|
-
|
|
448
|
-
def create_zai_user
|
|
449
|
-
return if zai_user_id.present?
|
|
450
|
-
|
|
451
|
-
response = ZaiPayment.users.create(
|
|
452
|
-
email: email,
|
|
453
|
-
first_name: first_name,
|
|
454
|
-
last_name: last_name,
|
|
455
|
-
country: country_code,
|
|
456
|
-
user_type: user_type
|
|
457
|
-
)
|
|
458
|
-
|
|
459
|
-
update(zai_user_id: response.data['id'])
|
|
460
|
-
rescue ZaiPayment::Errors::ApiError => e
|
|
461
|
-
Rails.logger.error "Failed to create Zai user: #{e.message}"
|
|
462
|
-
# Handle error appropriately
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
def sync_to_zai
|
|
466
|
-
return unless zai_user_id
|
|
467
|
-
|
|
468
|
-
ZaiPayment.users.update(
|
|
469
|
-
zai_user_id,
|
|
470
|
-
email: email,
|
|
471
|
-
first_name: first_name,
|
|
472
|
-
last_name: last_name,
|
|
473
|
-
mobile: phone_number,
|
|
474
|
-
address_line1: address,
|
|
475
|
-
city: city,
|
|
476
|
-
state: state,
|
|
477
|
-
zip: zip_code
|
|
478
|
-
)
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
def fetch_from_zai
|
|
482
|
-
return unless zai_user_id
|
|
483
|
-
|
|
484
|
-
response = ZaiPayment.users.show(zai_user_id)
|
|
485
|
-
response.data
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
# app/controllers/users_controller.rb
|
|
490
|
-
class UsersController < ApplicationController
|
|
491
|
-
def create
|
|
492
|
-
@user = User.new(user_params)
|
|
493
|
-
|
|
494
|
-
if @user.save
|
|
495
|
-
# Zai user is created automatically via after_create callback
|
|
496
|
-
redirect_to @user, notice: 'User created successfully'
|
|
497
|
-
else
|
|
498
|
-
render :new
|
|
499
|
-
end
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
def sync_zai_profile
|
|
503
|
-
@user = User.find(params[:id])
|
|
504
|
-
@user.sync_to_zai
|
|
505
|
-
redirect_to @user, notice: 'Profile synced with Zai'
|
|
506
|
-
rescue ZaiPayment::Errors::ApiError => e
|
|
507
|
-
redirect_to @user, alert: "Sync failed: #{e.message}"
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
private
|
|
511
|
-
|
|
512
|
-
def user_params
|
|
513
|
-
params.require(:user).permit(
|
|
514
|
-
:email, :first_name, :last_name, :country_code, :user_type
|
|
515
|
-
)
|
|
516
|
-
end
|
|
517
|
-
end
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
## Testing Examples
|
|
521
|
-
|
|
522
|
-
### Example 14: RSpec Integration Tests
|
|
523
|
-
|
|
524
|
-
```ruby
|
|
525
|
-
# spec/models/user_spec.rb
|
|
526
|
-
require 'rails_helper'
|
|
527
|
-
|
|
528
|
-
RSpec.describe User, type: :model do
|
|
529
|
-
describe '#create_zai_user' do
|
|
530
|
-
let(:user) { build(:user, email: 'test@example.com') }
|
|
531
|
-
|
|
532
|
-
before do
|
|
533
|
-
stub_request(:post, %r{/users})
|
|
534
|
-
.to_return(
|
|
535
|
-
status: 201,
|
|
536
|
-
body: { id: 'zai_user_123', email: 'test@example.com' }.to_json,
|
|
537
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
538
|
-
)
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
it 'creates a Zai user after user creation' do
|
|
542
|
-
expect { user.save }.to change { user.zai_user_id }.from(nil).to('zai_user_123')
|
|
543
|
-
end
|
|
544
|
-
end
|
|
545
|
-
end
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
## Common Patterns
|
|
549
|
-
|
|
550
|
-
### Pattern 1: Two-Step User Creation
|
|
551
|
-
|
|
552
|
-
```ruby
|
|
553
|
-
# Step 1: Create user during signup (minimal info)
|
|
554
|
-
def create_initial_user(email:, name_parts:)
|
|
555
|
-
ZaiPayment.users.create(
|
|
556
|
-
user_type: 'payin', # or 'payout' based on your use case
|
|
557
|
-
email: email,
|
|
558
|
-
first_name: name_parts[:first],
|
|
559
|
-
last_name: name_parts[:last],
|
|
560
|
-
country: 'USA' # Default or from IP geolocation
|
|
561
|
-
)
|
|
562
|
-
end
|
|
563
|
-
|
|
564
|
-
# Step 2: Complete profile later
|
|
565
|
-
def complete_user_profile(user_id:, profile_data:)
|
|
566
|
-
ZaiPayment.users.update(user_id, **profile_data)
|
|
567
|
-
end
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
### Pattern 2: Smart Retry Logic
|
|
571
|
-
|
|
572
|
-
```ruby
|
|
573
|
-
def create_user_with_retry(attributes, max_retries: 3)
|
|
574
|
-
retries = 0
|
|
575
|
-
|
|
576
|
-
begin
|
|
577
|
-
ZaiPayment.users.create(**attributes)
|
|
578
|
-
rescue ZaiPayment::Errors::TimeoutError, ZaiPayment::Errors::ConnectionError => e
|
|
579
|
-
retries += 1
|
|
580
|
-
if retries < max_retries
|
|
581
|
-
sleep(2 ** retries) # Exponential backoff
|
|
582
|
-
retry
|
|
583
|
-
else
|
|
584
|
-
raise e
|
|
585
|
-
end
|
|
586
|
-
rescue ZaiPayment::Errors::UnauthorizedError
|
|
587
|
-
ZaiPayment.refresh_token!
|
|
588
|
-
retry
|
|
589
|
-
end
|
|
590
|
-
end
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
### Pattern 3: Business User with Company
|
|
594
|
-
|
|
595
|
-
Create a user representing a business entity with full company details.
|
|
596
|
-
|
|
597
|
-
```ruby
|
|
598
|
-
# Example: Create a merchant user with company information
|
|
599
|
-
response = ZaiPayment.users.create(
|
|
600
|
-
# User type
|
|
601
|
-
user_type: 'payout',
|
|
602
|
-
|
|
603
|
-
# Personal details (required for payout users)
|
|
604
|
-
email: 'john.director@example.com',
|
|
605
|
-
first_name: 'John',
|
|
606
|
-
last_name: 'Smith',
|
|
607
|
-
country: 'AUS',
|
|
608
|
-
dob: '15/06/1985',
|
|
609
|
-
address_line1: '789 Business Ave',
|
|
610
|
-
city: 'Melbourne',
|
|
611
|
-
state: 'VIC',
|
|
612
|
-
zip: '3000',
|
|
613
|
-
mobile: '+61412345678',
|
|
614
|
-
|
|
615
|
-
# Business role
|
|
616
|
-
authorized_signer_title: 'Director',
|
|
617
|
-
|
|
618
|
-
# Company details (required fields for payout companies)
|
|
619
|
-
company: {
|
|
620
|
-
name: 'Smith Trading Co',
|
|
621
|
-
legal_name: 'Smith Trading Company Pty Ltd',
|
|
622
|
-
tax_number: '53004085616', # ABN for Australian companies
|
|
623
|
-
business_email: 'accounts@smithtrading.com',
|
|
624
|
-
country: 'AUS',
|
|
625
|
-
address_line1: '123 Business Street',
|
|
626
|
-
city: 'Melbourne',
|
|
627
|
-
state: 'VIC',
|
|
628
|
-
zip: '3000',
|
|
629
|
-
phone: '+61398765432',
|
|
630
|
-
|
|
631
|
-
# Optional fields
|
|
632
|
-
address_line2: 'Suite 5',
|
|
633
|
-
charge_tax: true # GST registered
|
|
634
|
-
}
|
|
635
|
-
)
|
|
636
|
-
|
|
637
|
-
if response.success?
|
|
638
|
-
user = response.data
|
|
639
|
-
puts "Business user created: #{user['id']}"
|
|
640
|
-
puts "Company: #{user['company']['name']}"
|
|
641
|
-
end
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
### Pattern 4: Enhanced Fraud Prevention
|
|
645
|
-
|
|
646
|
-
Capture device information for payin users during payment flow.
|
|
647
|
-
|
|
648
|
-
```ruby
|
|
649
|
-
# Example: Payin user creation with recommended fields
|
|
650
|
-
response = ZaiPayment.users.create(
|
|
651
|
-
# Required fields
|
|
652
|
-
user_type: 'payin',
|
|
653
|
-
email: 'secure.buyer@example.com',
|
|
654
|
-
first_name: 'Sarah',
|
|
655
|
-
last_name: 'Johnson',
|
|
656
|
-
country: 'USA',
|
|
657
|
-
|
|
658
|
-
# Recommended verification fields
|
|
659
|
-
dob: '15/01/1990',
|
|
660
|
-
government_number: '123-45-6789', # SSN for US
|
|
661
|
-
drivers_license_number: 'D1234567',
|
|
662
|
-
drivers_license_state: 'CA',
|
|
663
|
-
|
|
664
|
-
# Contact and address
|
|
665
|
-
mobile: '+14155551234',
|
|
666
|
-
address_line1: '456 Market Street',
|
|
667
|
-
address_line2: 'Apt 12',
|
|
668
|
-
city: 'San Francisco',
|
|
669
|
-
state: 'CA',
|
|
670
|
-
zip: '94103'
|
|
671
|
-
)
|
|
672
|
-
|
|
673
|
-
user_id = response.data['id']
|
|
674
|
-
puts "User created with enhanced profile"
|
|
675
|
-
|
|
676
|
-
# Note: device_id and ip_address should be captured during payment
|
|
677
|
-
# and will be required when creating an item and charging a card.
|
|
678
|
-
# They are typically obtained from your payment form or checkout page.
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
### Pattern 5: Custom Branding for Merchants
|
|
682
|
-
|
|
683
|
-
Create a payout merchant user with custom branding for statements and payment pages.
|
|
684
|
-
|
|
685
|
-
```ruby
|
|
686
|
-
# Example: Merchant with custom branding
|
|
687
|
-
response = ZaiPayment.users.create(
|
|
688
|
-
user_type: 'payout',
|
|
689
|
-
email: 'merchant@brandedstore.com',
|
|
690
|
-
first_name: 'Alex',
|
|
691
|
-
last_name: 'Merchant',
|
|
692
|
-
country: 'AUS',
|
|
693
|
-
mobile: '+61411222333',
|
|
694
|
-
dob: '10/05/1985',
|
|
695
|
-
|
|
696
|
-
# Required address for payout users
|
|
697
|
-
address_line1: '789 Retail Plaza',
|
|
698
|
-
city: 'Brisbane',
|
|
699
|
-
state: 'QLD',
|
|
700
|
-
zip: '4000',
|
|
701
|
-
|
|
702
|
-
# Branding
|
|
703
|
-
logo_url: 'https://example.com/logo.png',
|
|
704
|
-
color_1: '#FF5733', # Primary brand color
|
|
705
|
-
color_2: '#C70039', # Secondary brand color
|
|
706
|
-
custom_descriptor: 'BRANDED STORE' # Shows on bank statements
|
|
707
|
-
)
|
|
708
|
-
|
|
709
|
-
merchant = response.data
|
|
710
|
-
puts "Branded merchant created: #{merchant['id']}"
|
|
711
|
-
puts "Custom descriptor: #{merchant['custom_descriptor']}"
|
|
712
|
-
```
|
|
713
|
-
|
|
714
|
-
### Pattern 6: AMEX Merchant Setup
|
|
715
|
-
|
|
716
|
-
Create a payout merchant specifically configured for American Express transactions.
|
|
717
|
-
|
|
718
|
-
```ruby
|
|
719
|
-
# Example: AMEX merchant with required fields
|
|
720
|
-
response = ZaiPayment.users.create(
|
|
721
|
-
user_type: 'payout',
|
|
722
|
-
email: 'director@amexshop.com',
|
|
723
|
-
first_name: 'Michael',
|
|
724
|
-
last_name: 'Director',
|
|
725
|
-
country: 'AUS',
|
|
726
|
-
mobile: '+61400111222',
|
|
727
|
-
dob: '20/03/1980',
|
|
728
|
-
|
|
729
|
-
# AMEX requirement: Must specify authorized signer title
|
|
730
|
-
authorized_signer_title: 'Managing Director',
|
|
731
|
-
|
|
732
|
-
# Required address for payout users
|
|
733
|
-
address_line1: '100 Corporate Drive',
|
|
734
|
-
city: 'Sydney',
|
|
735
|
-
state: 'NSW',
|
|
736
|
-
zip: '2000',
|
|
737
|
-
|
|
738
|
-
# Company for AMEX merchants (required fields for payout companies)
|
|
739
|
-
company: {
|
|
740
|
-
name: 'AMEX Shop',
|
|
741
|
-
legal_name: 'AMEX Shop Pty Limited',
|
|
742
|
-
tax_number: '51824753556',
|
|
743
|
-
business_email: 'finance@amexshop.com',
|
|
744
|
-
country: 'AUS',
|
|
745
|
-
address_line1: '100 Corporate Drive',
|
|
746
|
-
city: 'Sydney',
|
|
747
|
-
state: 'NSW',
|
|
748
|
-
zip: '2000',
|
|
749
|
-
phone: '+61299887766',
|
|
750
|
-
|
|
751
|
-
# Optional
|
|
752
|
-
charge_tax: true
|
|
753
|
-
}
|
|
754
|
-
)
|
|
755
|
-
|
|
756
|
-
puts "AMEX-ready merchant created: #{response.data['id']}"
|
|
757
|
-
```
|
|
758
|
-
|
|
759
|
-
## See Also
|
|
760
|
-
|
|
761
|
-
- [User Management Documentation](../docs/users.md)
|
|
762
|
-
- [Webhook Examples](webhooks.md)
|
|
763
|
-
- [Zai API Reference](https://developer.hellozai.com/reference)
|
|
764
|
-
|
|
765
|
-
|