zai_payment 2.3.2 → 2.5.0
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/badges/coverage.json +1 -1
- data/changelog.md +73 -0
- data/docs/bank_accounts.md +494 -0
- data/docs/items.md +575 -0
- data/examples/bank_accounts.md +637 -0
- data/examples/items.md +2115 -0
- data/examples/rails_card_payment.md +550 -14
- data/lib/zai_payment/resources/bank_account.rb +295 -0
- data/lib/zai_payment/resources/item.rb +257 -0
- data/lib/zai_payment/response.rb +1 -0
- data/lib/zai_payment/version.rb +1 -1
- data/lib/zai_payment.rb +6 -0
- data/readme.md +18 -150
- metadata +4 -2
- data/token_auth_implementation_summary.md +0 -249
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ZaiPayment
|
|
4
|
+
module Resources
|
|
5
|
+
# BankAccount resource for managing Zai bank accounts
|
|
6
|
+
#
|
|
7
|
+
# @see https://developer.hellozai.com/reference/createbankaccount
|
|
8
|
+
class BankAccount
|
|
9
|
+
attr_reader :client
|
|
10
|
+
|
|
11
|
+
# Map of attribute keys to API field names
|
|
12
|
+
FIELD_MAPPING = {
|
|
13
|
+
user_id: :user_id,
|
|
14
|
+
bank_name: :bank_name,
|
|
15
|
+
account_name: :account_name,
|
|
16
|
+
routing_number: :routing_number,
|
|
17
|
+
account_number: :account_number,
|
|
18
|
+
account_type: :account_type,
|
|
19
|
+
holder_type: :holder_type,
|
|
20
|
+
country: :country,
|
|
21
|
+
payout_currency: :payout_currency,
|
|
22
|
+
currency: :currency
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
# Map of UK-specific attribute keys to API field names
|
|
26
|
+
UK_FIELD_MAPPING = {
|
|
27
|
+
user_id: :user_id,
|
|
28
|
+
bank_name: :bank_name,
|
|
29
|
+
account_name: :account_name,
|
|
30
|
+
routing_number: :routing_number,
|
|
31
|
+
account_number: :account_number,
|
|
32
|
+
account_type: :account_type,
|
|
33
|
+
holder_type: :holder_type,
|
|
34
|
+
country: :country,
|
|
35
|
+
payout_currency: :payout_currency,
|
|
36
|
+
currency: :currency,
|
|
37
|
+
iban: :iban,
|
|
38
|
+
swift_code: :swift_code
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
# Valid account types
|
|
42
|
+
VALID_ACCOUNT_TYPES = %w[savings checking].freeze
|
|
43
|
+
|
|
44
|
+
# Valid holder types
|
|
45
|
+
VALID_HOLDER_TYPES = %w[personal business].freeze
|
|
46
|
+
|
|
47
|
+
def initialize(client: nil)
|
|
48
|
+
@client = client || Client.new
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Get a specific bank account by ID
|
|
52
|
+
#
|
|
53
|
+
# @param bank_account_id [String] the bank account ID
|
|
54
|
+
# @param include_decrypted_fields [Boolean] if true, the API will decrypt and return
|
|
55
|
+
# sensitive bank account fields (for example, the full account number). Defaults to false
|
|
56
|
+
# @return [Response] the API response containing bank account details
|
|
57
|
+
#
|
|
58
|
+
# @example
|
|
59
|
+
# bank_accounts = ZaiPayment::Resources::BankAccount.new
|
|
60
|
+
# response = bank_accounts.show("bank_account_id")
|
|
61
|
+
# response.data # => {"id" => "bank_account_id", "active" => true, ...}
|
|
62
|
+
#
|
|
63
|
+
# @example with decrypted fields
|
|
64
|
+
# response = bank_accounts.show("bank_account_id", include_decrypted_fields: true)
|
|
65
|
+
# # Returns full account number instead of masked version
|
|
66
|
+
#
|
|
67
|
+
# @see https://developer.hellozai.com/reference/showbankaccount
|
|
68
|
+
def show(bank_account_id, include_decrypted_fields: false)
|
|
69
|
+
validate_id!(bank_account_id, 'bank_account_id')
|
|
70
|
+
|
|
71
|
+
params = {}
|
|
72
|
+
params[:include_decrypted_fields] = include_decrypted_fields if include_decrypted_fields
|
|
73
|
+
|
|
74
|
+
client.get("/bank_accounts/#{bank_account_id}", params: params)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Create a new bank account for Australia
|
|
78
|
+
#
|
|
79
|
+
# @param attributes [Hash] bank account attributes
|
|
80
|
+
# @option attributes [String] :user_id (Required) User ID
|
|
81
|
+
# @option attributes [String] :bank_name (Required) Bank name (defaults to Bank of Australia)
|
|
82
|
+
# @option attributes [String] :account_name (Required) Account name (defaults to Samuel Seller)
|
|
83
|
+
# @option attributes [String] :routing_number (Required) Routing number / BSB number
|
|
84
|
+
# (defaults to 111123)
|
|
85
|
+
# @option attributes [String] :account_number (Required) Account number
|
|
86
|
+
# (defaults to 111234)
|
|
87
|
+
# @option attributes [String] :account_type (Required) Account type
|
|
88
|
+
# ('savings' or 'checking', defaults to checking)
|
|
89
|
+
# @option attributes [String] :holder_type (Required) Holder type ('personal' or 'business', defaults to personal)
|
|
90
|
+
# @option attributes [String] :country (Required) Country code (ISO 3166-1 alpha-3, max 3 chars, defaults to AUS)
|
|
91
|
+
# @option attributes [String] :payout_currency Optional currency code for payouts (ISO 4217 alpha-3)
|
|
92
|
+
# @option attributes [String] :currency Optional currency code (ISO 4217 alpha-3)
|
|
93
|
+
# @return [Response] the API response containing created bank account
|
|
94
|
+
#
|
|
95
|
+
# @example Create an Australian bank account
|
|
96
|
+
# bank_accounts = ZaiPayment::Resources::BankAccount.new
|
|
97
|
+
# response = bank_accounts.create_au(
|
|
98
|
+
# user_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
|
|
99
|
+
# bank_name: 'Bank of Australia',
|
|
100
|
+
# account_name: 'Samuel Seller',
|
|
101
|
+
# routing_number: '111123',
|
|
102
|
+
# account_number: '111234',
|
|
103
|
+
# account_type: 'checking',
|
|
104
|
+
# holder_type: 'personal',
|
|
105
|
+
# country: 'AUS',
|
|
106
|
+
# payout_currency: 'AUD',
|
|
107
|
+
# currency: 'AUD'
|
|
108
|
+
# )
|
|
109
|
+
#
|
|
110
|
+
# @see https://developer.hellozai.com/reference/createbankaccount
|
|
111
|
+
def create_au(**attributes)
|
|
112
|
+
validate_create_au_attributes!(attributes)
|
|
113
|
+
|
|
114
|
+
body = build_bank_account_body(attributes, :au)
|
|
115
|
+
client.post('/bank_accounts', body: body)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Create a new bank account for UK
|
|
119
|
+
#
|
|
120
|
+
# @param attributes [Hash] bank account attributes
|
|
121
|
+
# @option attributes [String] :user_id (Required) User ID
|
|
122
|
+
# @option attributes [String] :bank_name (Required) Bank name (defaults to Bank of UK)
|
|
123
|
+
# @option attributes [String] :account_name (Required) Account name (defaults to Samuel Seller)
|
|
124
|
+
# @option attributes [String] :routing_number (Required) Routing number / Sort Code / BSB
|
|
125
|
+
# number (defaults to 111123)
|
|
126
|
+
# @option attributes [String] :account_number (Required) Account number
|
|
127
|
+
# (defaults to 111234)
|
|
128
|
+
# @option attributes [String] :account_type (Required) Account type
|
|
129
|
+
# ('savings' or 'checking', defaults to checking)
|
|
130
|
+
# @option attributes [String] :holder_type (Required) Holder type ('personal' or 'business', defaults to personal)
|
|
131
|
+
# @option attributes [String] :country (Required) Country code (ISO 3166-1 alpha-3, max 3 chars, defaults to GBR)
|
|
132
|
+
# @option attributes [String] :payout_currency Optional currency code for payouts (ISO 4217 alpha-3)
|
|
133
|
+
# @option attributes [String] :currency Optional currency code (ISO 4217 alpha-3)
|
|
134
|
+
# @option attributes [String] :iban (Required for UK) IBAN number
|
|
135
|
+
# @option attributes [String] :swift_code (Required for UK) SWIFT Code / BIC
|
|
136
|
+
# @return [Response] the API response containing created bank account
|
|
137
|
+
#
|
|
138
|
+
# @example Create a UK bank account
|
|
139
|
+
# bank_accounts = ZaiPayment::Resources::BankAccount.new
|
|
140
|
+
# response = bank_accounts.create_uk(
|
|
141
|
+
# user_id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
|
|
142
|
+
# bank_name: 'Bank of UK',
|
|
143
|
+
# account_name: 'Samuel Seller',
|
|
144
|
+
# routing_number: '111123',
|
|
145
|
+
# account_number: '111234',
|
|
146
|
+
# account_type: 'checking',
|
|
147
|
+
# holder_type: 'personal',
|
|
148
|
+
# country: 'GBR',
|
|
149
|
+
# payout_currency: 'GBP',
|
|
150
|
+
# currency: 'GBP',
|
|
151
|
+
# iban: 'GB25QHWM02498765432109',
|
|
152
|
+
# swift_code: 'BUKBGB22'
|
|
153
|
+
# )
|
|
154
|
+
#
|
|
155
|
+
# @see https://developer.hellozai.com/reference/createbankaccount
|
|
156
|
+
def create_uk(**attributes)
|
|
157
|
+
validate_create_uk_attributes!(attributes)
|
|
158
|
+
|
|
159
|
+
body = build_bank_account_body(attributes, :uk)
|
|
160
|
+
client.post('/bank_accounts', body: body)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Redact a bank account
|
|
164
|
+
#
|
|
165
|
+
# Redacts a bank account using the given bank_account_id. Redacted bank accounts
|
|
166
|
+
# can no longer be used as a funding source or a disbursement destination.
|
|
167
|
+
#
|
|
168
|
+
# @param bank_account_id [String] the bank account ID
|
|
169
|
+
# @return [Response] the API response
|
|
170
|
+
#
|
|
171
|
+
# @example
|
|
172
|
+
# bank_accounts = ZaiPayment::Resources::BankAccount.new
|
|
173
|
+
# response = bank_accounts.redact("bank_account_id")
|
|
174
|
+
#
|
|
175
|
+
# @see https://developer.hellozai.com/reference/redactbankaccount
|
|
176
|
+
def redact(bank_account_id)
|
|
177
|
+
validate_id!(bank_account_id, 'bank_account_id')
|
|
178
|
+
client.delete("/bank_accounts/#{bank_account_id}")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Validate a US bank routing number
|
|
182
|
+
#
|
|
183
|
+
# Validates a US bank routing number before creating an account. This can be used to
|
|
184
|
+
# provide on-demand verification and further information of the bank information a user
|
|
185
|
+
# is providing.
|
|
186
|
+
#
|
|
187
|
+
# @param routing_number [String] the US bank routing number
|
|
188
|
+
# @return [Response] the API response containing routing number details
|
|
189
|
+
#
|
|
190
|
+
# @example
|
|
191
|
+
# bank_accounts = ZaiPayment::Resources::BankAccount.new
|
|
192
|
+
# response = bank_accounts.validate_routing_number("122235821")
|
|
193
|
+
# response.data # => {"routing_number" => "122235821", "customer_name" => "US BANK NA", ...}
|
|
194
|
+
#
|
|
195
|
+
# @see https://developer.hellozai.com/reference/validateroutingnumber
|
|
196
|
+
def validate_routing_number(routing_number)
|
|
197
|
+
validate_presence!(routing_number, 'routing_number')
|
|
198
|
+
|
|
199
|
+
params = { routing_number: routing_number }
|
|
200
|
+
client.get('/tools/routing_number', params: params)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
private
|
|
204
|
+
|
|
205
|
+
def validate_id!(value, field_name)
|
|
206
|
+
return unless value.nil? || value.to_s.strip.empty?
|
|
207
|
+
|
|
208
|
+
raise Errors::ValidationError, "#{field_name} is required and cannot be blank"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def validate_presence!(value, field_name)
|
|
212
|
+
return unless value.nil? || value.to_s.strip.empty?
|
|
213
|
+
|
|
214
|
+
raise Errors::ValidationError, "#{field_name} is required and cannot be blank"
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def validate_create_au_attributes!(attributes)
|
|
218
|
+
validate_required_au_attributes!(attributes)
|
|
219
|
+
validate_account_type!(attributes[:account_type]) if attributes[:account_type]
|
|
220
|
+
validate_holder_type!(attributes[:holder_type]) if attributes[:holder_type]
|
|
221
|
+
validate_country!(attributes[:country]) if attributes[:country]
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def validate_create_uk_attributes!(attributes)
|
|
225
|
+
validate_required_uk_attributes!(attributes)
|
|
226
|
+
validate_account_type!(attributes[:account_type]) if attributes[:account_type]
|
|
227
|
+
validate_holder_type!(attributes[:holder_type]) if attributes[:holder_type]
|
|
228
|
+
validate_country!(attributes[:country]) if attributes[:country]
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def validate_required_au_attributes!(attributes)
|
|
232
|
+
required_fields = %i[user_id bank_name account_name routing_number account_number
|
|
233
|
+
account_type holder_type country]
|
|
234
|
+
|
|
235
|
+
missing_fields = required_fields.select do |field|
|
|
236
|
+
attributes[field].nil? || attributes[field].to_s.strip.empty?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
return if missing_fields.empty?
|
|
240
|
+
|
|
241
|
+
raise Errors::ValidationError,
|
|
242
|
+
"Missing required fields: #{missing_fields.join(', ')}"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def validate_required_uk_attributes!(attributes)
|
|
246
|
+
required_fields = %i[user_id bank_name account_name routing_number account_number
|
|
247
|
+
account_type holder_type country iban swift_code]
|
|
248
|
+
|
|
249
|
+
missing_fields = required_fields.select do |field|
|
|
250
|
+
attributes[field].nil? || attributes[field].to_s.strip.empty?
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
return if missing_fields.empty?
|
|
254
|
+
|
|
255
|
+
raise Errors::ValidationError,
|
|
256
|
+
"Missing required fields: #{missing_fields.join(', ')}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def validate_account_type!(account_type)
|
|
260
|
+
return if VALID_ACCOUNT_TYPES.include?(account_type.to_s.downcase)
|
|
261
|
+
|
|
262
|
+
raise Errors::ValidationError,
|
|
263
|
+
"account_type must be one of: #{VALID_ACCOUNT_TYPES.join(', ')}"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def validate_holder_type!(holder_type)
|
|
267
|
+
return if VALID_HOLDER_TYPES.include?(holder_type.to_s.downcase)
|
|
268
|
+
|
|
269
|
+
raise Errors::ValidationError,
|
|
270
|
+
"holder_type must be one of: #{VALID_HOLDER_TYPES.join(', ')}"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def validate_country!(country)
|
|
274
|
+
# Country should be ISO 3166-1 alpha-3 code (3 letters)
|
|
275
|
+
return if country.to_s.match?(/\A[A-Z]{3}\z/i)
|
|
276
|
+
|
|
277
|
+
raise Errors::ValidationError, 'country must be a valid ISO 3166-1 alpha-3 code (e.g., AUS, GBR)'
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def build_bank_account_body(attributes, region)
|
|
281
|
+
body = {}
|
|
282
|
+
field_mapping = region == :uk ? UK_FIELD_MAPPING : FIELD_MAPPING
|
|
283
|
+
|
|
284
|
+
attributes.each do |key, value|
|
|
285
|
+
next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
286
|
+
|
|
287
|
+
api_field = field_mapping[key]
|
|
288
|
+
body[api_field] = value if api_field
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
body
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
@@ -25,6 +25,22 @@ module ZaiPayment
|
|
|
25
25
|
tax_invoice: :tax_invoice
|
|
26
26
|
}.freeze
|
|
27
27
|
|
|
28
|
+
ITEM_PAYMENT_ATTRIBUTES = {
|
|
29
|
+
account_id: :account_id,
|
|
30
|
+
device_id: :device_id,
|
|
31
|
+
ip_address: :ip_address,
|
|
32
|
+
cvv: :cvv,
|
|
33
|
+
merchant_phone: :merchant_phone
|
|
34
|
+
}.freeze
|
|
35
|
+
|
|
36
|
+
ITEM_ASYNC_PAYMENT_ATTRIBUTES = {
|
|
37
|
+
account_id: :account_id,
|
|
38
|
+
request_three_d_secure: :request_three_d_secure
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
# Valid values for request_three_d_secure parameter
|
|
42
|
+
REQUEST_THREE_D_SECURE_VALUES = %w[automatic challenge any].freeze
|
|
43
|
+
|
|
28
44
|
def initialize(client: nil)
|
|
29
45
|
@client = client || Client.new
|
|
30
46
|
end
|
|
@@ -299,6 +315,197 @@ module ZaiPayment
|
|
|
299
315
|
client.get("/items/#{item_id}/status")
|
|
300
316
|
end
|
|
301
317
|
|
|
318
|
+
# Make a payment
|
|
319
|
+
#
|
|
320
|
+
# @param item_id [String] the item ID
|
|
321
|
+
# @option attributes [String] :account_id Required account ID
|
|
322
|
+
# @option attributes [String] :device_id Optional device ID
|
|
323
|
+
# @option attributes [String] :ip_address Optional IP address
|
|
324
|
+
# @option attributes [String] :cvv Optional CVV
|
|
325
|
+
# @option attributes [String] :merchant_phone Optional merchant phone number
|
|
326
|
+
# @return [Response] the API response containing payment details
|
|
327
|
+
#
|
|
328
|
+
# @example Make a payment with required parameters
|
|
329
|
+
# items = ZaiPayment::Resources::Item.new
|
|
330
|
+
# response = items.make_payment("item_id", account_id: "account_id")
|
|
331
|
+
# response.data # => {"items" => {"id" => "...", "amount" => "...", ...}}
|
|
332
|
+
#
|
|
333
|
+
# @example Make a payment with optional parameters
|
|
334
|
+
# response = items.make_payment(
|
|
335
|
+
# "item_id",
|
|
336
|
+
# account_id: "account_id",
|
|
337
|
+
# device_id: "device_789",
|
|
338
|
+
# ip_address: "192.168.1.1",
|
|
339
|
+
# cvv: "123",
|
|
340
|
+
# merchant_phone: "+1234567890"
|
|
341
|
+
# )
|
|
342
|
+
#
|
|
343
|
+
# @see https://developer.hellozai.com/reference/makepayment
|
|
344
|
+
def make_payment(item_id, **attributes)
|
|
345
|
+
validate_id!(item_id, 'item_id')
|
|
346
|
+
|
|
347
|
+
body = build_item_payment_body(attributes)
|
|
348
|
+
|
|
349
|
+
client.patch("/items/#{item_id}/make_payment", body: body)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Cancel an item
|
|
353
|
+
|
|
354
|
+
# @param item_id [String] the item ID
|
|
355
|
+
# @return [Response] the API response containing cancellation details
|
|
356
|
+
#
|
|
357
|
+
# @example Cancel a payment
|
|
358
|
+
# items = ZaiPayment::Resources::Item.new
|
|
359
|
+
# response = items.cancel("item_id")
|
|
360
|
+
# response.data # => {"items" => {"id" => "...", "state" => "...", ...}}
|
|
361
|
+
#
|
|
362
|
+
# @see https://developer.hellozai.com/reference/cancelitem
|
|
363
|
+
def cancel(item_id)
|
|
364
|
+
validate_id!(item_id, 'item_id')
|
|
365
|
+
client.patch("/items/#{item_id}/cancel")
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Refund an item
|
|
369
|
+
#
|
|
370
|
+
# @param item_id [String] the item ID
|
|
371
|
+
# @option attributes [String] :refund_amount Optional refund amount
|
|
372
|
+
# @option attributes [String] :refund_message Optional refund message
|
|
373
|
+
# @option attributes [String] :account_id Optional account ID
|
|
374
|
+
# @return [Response] the API response containing refund details
|
|
375
|
+
#
|
|
376
|
+
# @example Refund an item
|
|
377
|
+
# items = ZaiPayment::Resources::Item.new
|
|
378
|
+
# response = items.refund("item_id")
|
|
379
|
+
# response.data # => {"items" => {"id" => "...", "state" => "...", ...}}
|
|
380
|
+
#
|
|
381
|
+
# @example Refund an item with optional parameters
|
|
382
|
+
# response = items.refund(
|
|
383
|
+
# "item_id",
|
|
384
|
+
# refund_amount: 10000,
|
|
385
|
+
# refund_message: "Refund for product XYZ",
|
|
386
|
+
# account_id: "account_789"
|
|
387
|
+
# )
|
|
388
|
+
#
|
|
389
|
+
# @see https://developer.hellozai.com/reference/refund
|
|
390
|
+
def refund(item_id, refund_amount: nil, refund_message: nil, account_id: nil)
|
|
391
|
+
validate_id!(item_id, 'item_id')
|
|
392
|
+
|
|
393
|
+
body = build_refund_body(
|
|
394
|
+
refund_amount: refund_amount,
|
|
395
|
+
refund_message: refund_message,
|
|
396
|
+
account_id: account_id
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
client.patch("/items/#{item_id}/refund", body: body)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Authorize Payment
|
|
403
|
+
#
|
|
404
|
+
# @param item_id [String] the item ID
|
|
405
|
+
# @option attributes [String] :account_id Required account ID
|
|
406
|
+
# @option attributes [String] :cvv Optional CVV
|
|
407
|
+
# @option attributes [String] :merchant_phone Optional merchant phone number
|
|
408
|
+
# @return [Response] the API response containing authorization details
|
|
409
|
+
#
|
|
410
|
+
# @example Authorize a payment
|
|
411
|
+
# items = ZaiPayment::Resources::Item.new
|
|
412
|
+
# response = items.authorize_payment("item_id", account_id: "account_id")
|
|
413
|
+
# response.data # => {"items" => {"id" => "...", "state" => "...", ...}}
|
|
414
|
+
#
|
|
415
|
+
# @example Authorize a payment with optional parameters
|
|
416
|
+
# response = items.authorize_payment(
|
|
417
|
+
# "item_id",
|
|
418
|
+
# account_id: "account_id",
|
|
419
|
+
# cvv: "123",
|
|
420
|
+
# merchant_phone: "+1234567890"
|
|
421
|
+
# )
|
|
422
|
+
#
|
|
423
|
+
# @see https://developer.hellozai.com/reference/authorizepayment
|
|
424
|
+
def authorize_payment(item_id, **attributes)
|
|
425
|
+
validate_id!(item_id, 'item_id')
|
|
426
|
+
|
|
427
|
+
client.patch("/items/#{item_id}/authorize_payment", body: build_item_payment_body(attributes))
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Capture Payment
|
|
431
|
+
#
|
|
432
|
+
# @param item_id [String] the item ID
|
|
433
|
+
# @option attributes [String] :amount Optional amount to capture
|
|
434
|
+
# @return [Response] the API response containing capture details
|
|
435
|
+
#
|
|
436
|
+
# @example Capture a payment
|
|
437
|
+
# items = ZaiPayment::Resources::Item.new
|
|
438
|
+
# response = items.capture_payment("item_id", amount: 10000)
|
|
439
|
+
# response.data # => {"items" => {"id" => "...", "state" => "...", ...}}
|
|
440
|
+
#
|
|
441
|
+
# @example Capture a payment with optional parameters
|
|
442
|
+
# response = items.capture_payment(
|
|
443
|
+
# "item_id",
|
|
444
|
+
# amount: 10000
|
|
445
|
+
# )
|
|
446
|
+
#
|
|
447
|
+
# @see https://developer.hellozai.com/reference/capturepayment
|
|
448
|
+
def capture_payment(item_id, **attributes)
|
|
449
|
+
validate_id!(item_id, 'item_id')
|
|
450
|
+
|
|
451
|
+
body = {}
|
|
452
|
+
body[:amount] = attributes[:amount] if attributes[:amount]
|
|
453
|
+
|
|
454
|
+
client.patch("/items/#{item_id}/capture_payment", body: body)
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
# Void Payment
|
|
458
|
+
#
|
|
459
|
+
# @param item_id [String] the item ID
|
|
460
|
+
# @return [Response] the API response containing void details
|
|
461
|
+
#
|
|
462
|
+
# @example Void a payment
|
|
463
|
+
# items = ZaiPayment::Resources::Item.new
|
|
464
|
+
# response = items.void_payment("item_id")
|
|
465
|
+
# response.data # => {"items" => {"id" => "...", "state" => "...", ...}}
|
|
466
|
+
#
|
|
467
|
+
# @see https://developer.hellozai.com/reference/voidpayment
|
|
468
|
+
def void_payment(item_id)
|
|
469
|
+
validate_id!(item_id, 'item_id')
|
|
470
|
+
client.patch("/items/#{item_id}/void_payment")
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# Make an async Payment
|
|
474
|
+
#
|
|
475
|
+
# Initiate a card payment with 3D Secure 2.0 authentication support. This endpoint
|
|
476
|
+
# initiates the payment process and returns a payment_token required for 3DS2
|
|
477
|
+
# component initialisation.
|
|
478
|
+
#
|
|
479
|
+
# @param item_id [String] the item ID
|
|
480
|
+
# @param account_id [String] Account id of the bank account/credit card, etc making payment (not user id)
|
|
481
|
+
# @option attributes [String] :request_three_d_secure Customise the 3DS (3D Secure) preference for this payment.
|
|
482
|
+
# Allowed values: 'automatic', 'challenge', 'any'. Defaults to 'automatic'.
|
|
483
|
+
# - 'automatic': 3DS preference is determined automatically by the system
|
|
484
|
+
# - 'challenge': Request a 3DS challenge is presented to the user
|
|
485
|
+
# - 'any': Request a 3DS challenge regardless of the challenge flow
|
|
486
|
+
# @return [Response] the API response containing payment details with payment_token
|
|
487
|
+
#
|
|
488
|
+
# @example Make an async payment with required parameters
|
|
489
|
+
# items = ZaiPayment::Resources::Item.new
|
|
490
|
+
# response = items.make_payment_async("item_id", account_id: "account_id")
|
|
491
|
+
# response.data # => {"payment_id" => "...", "payment_token" => "...", "items" => {...}}
|
|
492
|
+
#
|
|
493
|
+
# @example Make an async payment with 3DS challenge
|
|
494
|
+
# response = items.make_payment_async(
|
|
495
|
+
# "item_id",
|
|
496
|
+
# account_id: "account_id",
|
|
497
|
+
# request_three_d_secure: "challenge"
|
|
498
|
+
# )
|
|
499
|
+
#
|
|
500
|
+
# @see https://developer.hellozai.com/reference/makepaymentasync
|
|
501
|
+
def make_payment_async(item_id, **attributes)
|
|
502
|
+
validate_id!(item_id, 'item_id')
|
|
503
|
+
|
|
504
|
+
body = build_async_payment_body(attributes)
|
|
505
|
+
|
|
506
|
+
client.patch("/items/#{item_id}/make_payment_async", body: body)
|
|
507
|
+
end
|
|
508
|
+
|
|
302
509
|
private
|
|
303
510
|
|
|
304
511
|
def validate_id!(value, field_name)
|
|
@@ -346,6 +553,28 @@ module ZaiPayment
|
|
|
346
553
|
raise Errors::ValidationError, 'payment_type must be between 1 and 7'
|
|
347
554
|
end
|
|
348
555
|
|
|
556
|
+
def validate_request_three_d_secure!(value)
|
|
557
|
+
return if REQUEST_THREE_D_SECURE_VALUES.include?(value.to_s)
|
|
558
|
+
|
|
559
|
+
raise Errors::ValidationError,
|
|
560
|
+
"request_three_d_secure must be one of: #{REQUEST_THREE_D_SECURE_VALUES.join(', ')}"
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def build_item_payment_body(attributes)
|
|
564
|
+
validate_presence!(attributes[:account_id], 'account_id')
|
|
565
|
+
|
|
566
|
+
body = {}
|
|
567
|
+
|
|
568
|
+
attributes.each do |key, value|
|
|
569
|
+
next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
570
|
+
|
|
571
|
+
api_field = ITEM_PAYMENT_ATTRIBUTES[key]
|
|
572
|
+
body[api_field] = value if api_field
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
body
|
|
576
|
+
end
|
|
577
|
+
|
|
349
578
|
def build_item_body(attributes)
|
|
350
579
|
body = {}
|
|
351
580
|
|
|
@@ -358,6 +587,34 @@ module ZaiPayment
|
|
|
358
587
|
|
|
359
588
|
body
|
|
360
589
|
end
|
|
590
|
+
|
|
591
|
+
def build_refund_body(refund_amount: nil, refund_message: nil, account_id: nil)
|
|
592
|
+
body = {}
|
|
593
|
+
|
|
594
|
+
body[:refund_amount] = refund_amount if refund_amount
|
|
595
|
+
body[:refund_message] = refund_message if refund_message
|
|
596
|
+
body[:account_id] = account_id if account_id
|
|
597
|
+
|
|
598
|
+
body
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
def build_async_payment_body(attributes)
|
|
602
|
+
validate_presence!(attributes[:account_id], 'account_id')
|
|
603
|
+
|
|
604
|
+
# Validate request_three_d_secure if provided
|
|
605
|
+
validate_request_three_d_secure!(attributes[:request_three_d_secure]) if attributes[:request_three_d_secure]
|
|
606
|
+
|
|
607
|
+
body = {}
|
|
608
|
+
|
|
609
|
+
attributes.each do |key, value|
|
|
610
|
+
next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
611
|
+
|
|
612
|
+
api_field = ITEM_ASYNC_PAYMENT_ATTRIBUTES[key]
|
|
613
|
+
body[api_field] = value if api_field
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
body
|
|
617
|
+
end
|
|
361
618
|
end
|
|
362
619
|
end
|
|
363
620
|
end
|
data/lib/zai_payment/response.rb
CHANGED
data/lib/zai_payment/version.rb
CHANGED
data/lib/zai_payment.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative 'zai_payment/resources/webhook'
|
|
|
14
14
|
require_relative 'zai_payment/resources/user'
|
|
15
15
|
require_relative 'zai_payment/resources/item'
|
|
16
16
|
require_relative 'zai_payment/resources/token_auth'
|
|
17
|
+
require_relative 'zai_payment/resources/bank_account'
|
|
17
18
|
|
|
18
19
|
module ZaiPayment
|
|
19
20
|
class << self
|
|
@@ -57,5 +58,10 @@ module ZaiPayment
|
|
|
57
58
|
def token_auths
|
|
58
59
|
@token_auths ||= Resources::TokenAuth.new(client: Client.new(base_endpoint: :core_base))
|
|
59
60
|
end
|
|
61
|
+
|
|
62
|
+
# @return [ZaiPayment::Resources::BankAccount] bank_account resource instance
|
|
63
|
+
def bank_accounts
|
|
64
|
+
@bank_accounts ||= Resources::BankAccount.new(client: Client.new(base_endpoint: :core_base))
|
|
65
|
+
end
|
|
60
66
|
end
|
|
61
67
|
end
|