zai_payment 2.8.0 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98109f5cacbac15031860abc6adb10c57f3ff7f232978965afe4c3052c962805
4
- data.tar.gz: 126e97d1b18c1fba6e8b98e600727339f949c96e39064e7815832cb2ed5f62de
3
+ metadata.gz: b3f20fe256ab69c787f421db039fac49e817c855ca7aa07441380fb1d03ab2ca
4
+ data.tar.gz: 995f5e6a67dbc86b4ebadd2918c96dd63ba0effe5c8991826fd35e89bfdd6c0c
5
5
  SHA512:
6
- metadata.gz: e319a397758406f149749a2f7a30f8217ba9b58666d311134f16734bee042c52f2d248c91e90ae83ddbd11445f2d6f58609ae5f3c9b09bed14f3f7a8a990d569
7
- data.tar.gz: 03fa17ae8f34e051daa8c26ca7d141ff94b0fc712b0f489554cb1636a2c797670c0ae5b4243c9dd851634508599c00979bc98d37dae77ae7032b2453e1e23fa2
6
+ metadata.gz: e7152d67c815e5698d8f61aa4f28fa9957190b7ba97a3dac7fee73248698d04cf1d44acfca6988cd301fcf6e3094420f1b90d135e643af4b5150e8cde796c799
7
+ data.tar.gz: 811ec3899505dc68601c9432f7c4356f4e5fc3d44703bd156b5ce55daeb5ec90ceede45d9fc1084fa09ec7f5c281856635d9d3f1b1064338094dddf4e93d2e63
data/changelog.md CHANGED
@@ -1,5 +1,24 @@
1
1
  ## [Released]
2
2
 
3
+ ## [2.8.1] - 2025-11-07
4
+
5
+ ### Fixed
6
+ - **Response Data Extraction Bug**: Fixed `.data` method returning only `routing_number` value instead of full object 🐛
7
+ - Removed `routing_number` from `RESPONSE_DATA_KEYS` constant - it's a field within responses, not a collection wrapper key
8
+ - The `.data` method was incorrectly treating `routing_number` as a top-level data key
9
+ - This caused `response.data` to return just `"803320"` (the routing number) instead of the complete virtual account object
10
+ - Now properly returns the full response object when no wrapper key is found
11
+ - Affected resources: Virtual Accounts (and potentially other resources with `routing_number` field)
12
+ - Updated test mocks to match actual API response format (flat objects for single resources)
13
+
14
+ ### Changed
15
+ - **Virtual Account Test Fixtures**: Updated response structure to match actual Zai API format
16
+ - Single resource responses (show, create, update) now return flat objects without wrapper keys
17
+ - Collection responses (list) continue to use `virtual_accounts` wrapper key
18
+ - All 87 virtual account tests passing with corrected response structure
19
+
20
+ **Full Changelog**: https://github.com/Sentia/zai-payment/compare/v2.8.0...v2.8.1
21
+
3
22
  ## [2.8.0] - 2025-11-07
4
23
 
5
24
  ### Added
@@ -117,7 +117,7 @@ Validate a US bank routing number before creating an account. This can be used t
117
117
  response = bank_accounts.validate_routing_number('122235821')
118
118
 
119
119
  if response.success?
120
- routing_info = response.data
120
+ routing_info = response.data['routing_number']
121
121
  puts "Routing Number: #{routing_info['routing_number']}"
122
122
  puts "Bank Name: #{routing_info['customer_name']}"
123
123
  puts "City: #{routing_info['city']}"
@@ -133,16 +133,18 @@ end
133
133
 
134
134
  ```ruby
135
135
  {
136
- "routing_number" => "122235821",
137
- "customer_name" => "US BANK NA",
138
- "address" => "EP-MN-WN1A",
139
- "city" => "ST. PAUL",
140
- "state_code" => "MN",
141
- "zip" => "55107",
142
- "zip_extension" => "1419",
143
- "phone_area_code" => "800",
144
- "phone_prefix" => "937",
145
- "phone_suffix" => "631"
136
+ "routing_number" => {
137
+ "routing_number" => "122235821",
138
+ "customer_name" => "US BANK NA",
139
+ "address" => "EP-MN-WN1A",
140
+ "city" => "ST. PAUL",
141
+ "state_code" => "MN",
142
+ "zip" => "55107",
143
+ "zip_extension" => "1419",
144
+ "phone_area_code" => "800",
145
+ "phone_prefix" => "937",
146
+ "phone_suffix" => "631"
147
+ }
146
148
  }
147
149
  ```
148
150
 
@@ -164,7 +164,7 @@ bank_accounts = ZaiPayment::Resources::BankAccount.new
164
164
  response = bank_accounts.validate_routing_number('122235821')
165
165
 
166
166
  if response.success?
167
- routing_info = response.data
167
+ routing_info = response.data['routing_number']
168
168
 
169
169
  puts "Routing Number Validation Results:"
170
170
  puts " Routing Number: #{routing_info['routing_number']}"
@@ -197,7 +197,7 @@ begin
197
197
  validation_response = bank_accounts.validate_routing_number(routing_number)
198
198
 
199
199
  if validation_response.success?
200
- bank_info = validation_response.data
200
+ bank_info = validation_response.data['routing_number']
201
201
 
202
202
  # Show user the bank information for confirmation
203
203
  puts "You are creating an account with:"
@@ -246,7 +246,7 @@ class BankAccountsController < ApplicationController
246
246
  response = bank_accounts.validate_routing_number(routing_number)
247
247
 
248
248
  if response.success?
249
- bank_info = response.data
249
+ bank_info = response.data['routing_number']
250
250
 
251
251
  # Return bank info to display in the form
252
252
  render json: {
@@ -15,6 +15,16 @@ module ZaiPayment
15
15
  reference_id: :reference_id
16
16
  }.freeze
17
17
 
18
+ # Map of attribute keys to API field names for withdraw
19
+ WITHDRAW_FIELD_MAPPING = {
20
+ account_id: :account_id,
21
+ amount: :amount,
22
+ custom_descriptor: :custom_descriptor,
23
+ reference_id: :reference_id,
24
+ end_to_end_id: :end_to_end_id,
25
+ ifti_information: :ifti_information
26
+ }.freeze
27
+
18
28
  def initialize(client: nil)
19
29
  @client = client || Client.new
20
30
  end
@@ -118,6 +128,58 @@ module ZaiPayment
118
128
  client.post("/wallet_accounts/#{wallet_account_id}/bill_payment", body: body)
119
129
  end
120
130
 
131
+ # Withdraw funds from a Wallet Account to a specified disbursement account
132
+ #
133
+ # @param wallet_account_id [String] the wallet account ID
134
+ # @param attributes [Hash] withdrawal attributes
135
+ # @option attributes [String] :account_id (Required) Account ID to withdraw to
136
+ # @option attributes [Integer] :amount (Required) Amount in cents to withdraw
137
+ # @option attributes [String] :custom_descriptor Custom descriptor for the withdrawal
138
+ # (max 200 chars for NPP, 18 for DE batch)
139
+ # @option attributes [String] :reference_id Unique reference information (cannot contain '.' character)
140
+ # @option attributes [String] :end_to_end_id Unique identifier for NPP IFTI payout tracking (mandatory for IFTI)
141
+ # @option attributess [Hash] :ifti_information IFTI payer information hash (required for IFTI payouts)
142
+ # @return [Response] the API response containing disbursement details
143
+ #
144
+ # @example Basic withdrawal
145
+ # wallet_accounts = ZaiPayment::Resources::WalletAccount.new
146
+ # response = wallet_accounts.withdraw(
147
+ # 'wallet_account_id',
148
+ # account_id: 'bank_account_id',
149
+ # amount: 10000
150
+ # )
151
+ #
152
+ # @example Withdrawal with custom descriptor and reference
153
+ # response = wallet_accounts.withdraw(
154
+ # 'wallet_account_id',
155
+ # account_id: 'bank_account_id',
156
+ # amount: 10000,
157
+ # custom_descriptor: 'Invoice #12345 Payment',
158
+ # reference_id: 'ref-12345'
159
+ # )
160
+ #
161
+ # @example NPP IFTI withdrawal
162
+ # response = wallet_accounts.withdraw(
163
+ # 'wallet_account_id',
164
+ # account_id: 'bank_account_id',
165
+ # amount: 10000,
166
+ # end_to_end_id: 'E2E-UNIQUE-ID-123',
167
+ # ifti_information: {
168
+ # payer_name: 'John Doe',
169
+ # payer_address: '123 Main St, Sydney NSW 2000',
170
+ # payer_country: 'AUS'
171
+ # }
172
+ # )
173
+ #
174
+ # @see https://developer.hellozai.com/reference
175
+ def withdraw(wallet_account_id, **attributes)
176
+ validate_id!(wallet_account_id, 'wallet_account_id')
177
+ validate_withdraw_attributes!(attributes)
178
+
179
+ body = build_withdraw_body(attributes)
180
+ client.post("/wallet_accounts/#{wallet_account_id}/withdraw", body: body)
181
+ end
182
+
121
183
  private
122
184
 
123
185
  def validate_id!(value, field_name)
@@ -159,6 +221,40 @@ module ZaiPayment
159
221
  raise Errors::ValidationError, "reference_id cannot contain single quote (') character"
160
222
  end
161
223
 
224
+ def validate_withdraw_attributes!(attributes)
225
+ validate_required_withdraw_attributes!(attributes)
226
+ validate_amount!(attributes[:amount]) if attributes[:amount]
227
+ validate_withdraw_reference_id!(attributes[:reference_id]) if attributes[:reference_id]
228
+ validate_custom_descriptor!(attributes[:custom_descriptor]) if attributes[:custom_descriptor]
229
+ end
230
+
231
+ def validate_required_withdraw_attributes!(attributes)
232
+ required_fields = %i[account_id amount]
233
+
234
+ missing_fields = required_fields.select do |field|
235
+ attributes[field].nil? || (attributes[field].respond_to?(:to_s) && attributes[field].to_s.strip.empty?)
236
+ end
237
+
238
+ return if missing_fields.empty?
239
+
240
+ raise Errors::ValidationError,
241
+ "Missing required fields: #{missing_fields.join(', ')}"
242
+ end
243
+
244
+ def validate_withdraw_reference_id!(reference_id)
245
+ # Reference ID cannot contain '.' character
246
+ return unless reference_id.to_s.include?('.')
247
+
248
+ raise Errors::ValidationError, "reference_id cannot contain '.' character"
249
+ end
250
+
251
+ def validate_custom_descriptor!(custom_descriptor)
252
+ # Basic validation - max 200 characters for NPP (API will enforce specific limits)
253
+ return if custom_descriptor.to_s.length <= 200
254
+
255
+ raise Errors::ValidationError, 'custom_descriptor must be 200 characters or less'
256
+ end
257
+
162
258
  def build_pay_bill_body(attributes)
163
259
  body = {}
164
260
 
@@ -171,6 +267,19 @@ module ZaiPayment
171
267
 
172
268
  body
173
269
  end
270
+
271
+ def build_withdraw_body(attributes)
272
+ body = {}
273
+
274
+ attributes.each do |key, value|
275
+ next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
276
+
277
+ api_field = WITHDRAW_FIELD_MAPPING[key]
278
+ body[api_field] = value if api_field
279
+ end
280
+
281
+ body
282
+ end
174
283
  end
175
284
  end
176
285
  end
@@ -8,7 +8,7 @@ module ZaiPayment
8
8
  RESPONSE_DATA_KEYS = %w[
9
9
  webhooks users items fees transactions
10
10
  batch_transactions batches bpay_accounts bank_accounts card_accounts
11
- wallet_accounts virtual_accounts routing_number disbursements pay_ids
11
+ wallet_accounts virtual_accounts disbursements pay_ids
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.8.0'
4
+ VERSION = '2.8.2'
5
5
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zai_payment
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eddy Jaga
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-11-21 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: base64
@@ -129,6 +130,7 @@ metadata:
129
130
  code_of_conduct_uri: https://github.com/Sentia/zai-payment/blob/main/code_of_conduct.md
130
131
  rubygems_mfa_required: 'true'
131
132
  documentation_uri: https://github.com/Sentia/zai-payment#readme
133
+ post_install_message:
132
134
  rdoc_options: []
133
135
  require_paths:
134
136
  - lib
@@ -143,7 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
145
  - !ruby/object:Gem::Version
144
146
  version: '0'
145
147
  requirements: []
146
- rubygems_version: 3.7.1
148
+ rubygems_version: 3.5.11
149
+ signing_key:
147
150
  specification_version: 4
148
151
  summary: Ruby gem for Zai payment integration
149
152
  test_files: []