airwallex 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24329b3008cb6844904a266d7cfed62b05bb0743935edd22a7ea1e3c1a98606e
4
- data.tar.gz: 73d9c743bfa6da7e652da8663b98965985aefcbe575d373f322a7023232278f3
3
+ metadata.gz: aff1a8f847f36f804c6ff9738480a8acd8e9aae867a9a3846311521337544c15
4
+ data.tar.gz: af199726a6f9cdcf4eef3d47c1ac1c24fd3ce92f9dd564c57730e75a8e4230ce
5
5
  SHA512:
6
- metadata.gz: caae41e87cb5071ed6d8fdba00d873c6d90a6eabf20406a33e6261f960d8b65cf4355a71df4cac01c60ea5cb74705e9491843f74c1458559c8e24c1d5bebb044
7
- data.tar.gz: 0b0924430871eb4065f78b75e2e1a6cad937089ebfec9801dbebcb8d5b7aa6e3ae49bbd882f8adb8406d0c3a17fd7a81956495dd9e194ea9349c41109b1faf2e
6
+ metadata.gz: 41ddfe80904d71772a0ed87a6f6f26ff3f857b8502bfde57c6e8b42bd53a162d6235ac6ae99ca52a11f2e4688dbe0682a96806ec2e97f1e2e3f617c038766c45
7
+ data.tar.gz: 907a5e84b3a38f3b4664ccf41d5ac4d62e04804073034845dfd9503b880113f2bc32d8c365ca9cca96dd6870ac4ebc1283ca93da93fb59128789b001b556ef47
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2025-11-25
4
+
5
+ ### Added
6
+ - Foreign Exchange resources:
7
+ - Rate resource (retrieve, list) for real-time exchange rate queries
8
+ - Quote resource (create, retrieve) for locking exchange rates with expiration helpers
9
+ - Conversion resource (create, retrieve, list) for executing currency conversions
10
+ - Balance resource (list, retrieve) for querying account balances across currencies
11
+ - Enhanced List operation to handle both array responses and paginated responses
12
+ - 38 new tests (278 total) covering FX and balance operations
13
+ - Comprehensive manual test suite for regression testing
14
+
15
+ ### Changed
16
+ - Refactored List operation for better code quality (reduced complexity from 12 to 7)
17
+ - Balance.retrieve now performs client-side filtering for currency lookup
18
+
19
+ ### Fixed
20
+ - List operation now correctly handles Balance API's direct array response format
21
+
22
+ ## [0.2.1] - 2025-11-25
23
+
24
+ ### Added
25
+ - BatchTransfer resource (create, retrieve, list) for bulk payout operations
26
+ - Dispute resource (retrieve, list, accept, submit_evidence) for chargeback management
27
+ - 25 new tests (240 total) covering batch transfers and disputes
28
+
3
29
  ## [0.2.0] - 2025-11-25
4
30
 
5
31
  ### Added
data/README.md CHANGED
@@ -154,6 +154,102 @@ payment_intent.confirm(payment_method_id: payment_method.id)
154
154
  methods = customer.payment_methods
155
155
  ```
156
156
 
157
+ ### Batch Transfers
158
+
159
+ ```ruby
160
+ # Create a batch of transfers for bulk payouts
161
+ batch = Airwallex::BatchTransfer.create(
162
+ request_id: "batch_#{Time.now.to_i}",
163
+ source_currency: 'USD',
164
+ transfers: [
165
+ { beneficiary_id: 'ben_001', amount: 100.00, reason: 'Seller payout' },
166
+ { beneficiary_id: 'ben_002', amount: 250.00, reason: 'Affiliate payment' },
167
+ { beneficiary_id: 'ben_003', amount: 500.00, reason: 'Vendor payment' }
168
+ ]
169
+ )
170
+
171
+ # Check batch status
172
+ batch = Airwallex::BatchTransfer.retrieve(batch.id)
173
+ puts "Completed: #{batch.success_count}/#{batch.total_count}"
174
+
175
+ # Check individual transfer statuses
176
+ batch.transfers.each do |transfer|
177
+ puts "#{transfer.id}: #{transfer.status}"
178
+ end
179
+ ```
180
+
181
+ ### Managing Disputes
182
+
183
+ ```ruby
184
+ # List all open disputes
185
+ disputes = Airwallex::Dispute.list(status: 'OPEN')
186
+
187
+ # Get specific dispute
188
+ dispute = Airwallex::Dispute.retrieve('dis_123')
189
+ puts "Dispute amount: #{dispute.amount} #{dispute.currency}"
190
+ puts "Reason: #{dispute.reason}"
191
+ puts "Evidence due: #{dispute.evidence_due_by}"
192
+
193
+ # Submit evidence to challenge
194
+ dispute.submit_evidence(
195
+ customer_communication: 'Email showing delivery confirmation',
196
+ shipping_tracking_number: '1Z999AA10123456784',
197
+ shipping_documentation: 'Proof of delivery with signature'
198
+ )
199
+
200
+ # Or accept dispute without challenging
201
+ dispute.accept
202
+ ```
203
+
204
+ ### Foreign Exchange & Multi-Currency
205
+
206
+ ```ruby
207
+ # Get real-time exchange rate
208
+ rate = Airwallex::Rate.retrieve(
209
+ buy_currency: 'EUR',
210
+ sell_currency: 'USD'
211
+ )
212
+ puts "Current rate: #{rate.client_rate}"
213
+
214
+ # Lock in a rate with a quote (valid for 24 hours)
215
+ quote = Airwallex::Quote.create(
216
+ buy_currency: 'EUR',
217
+ sell_currency: 'USD',
218
+ sell_amount: 10000.00,
219
+ validity: 'HR_24'
220
+ )
221
+
222
+ puts "Locked rate: #{quote.client_rate}"
223
+ puts "Expires in: #{quote.seconds_until_expiration} seconds"
224
+ puts "Is expired? #{quote.expired?}"
225
+
226
+ # Execute conversion using locked quote
227
+ conversion = Airwallex::Conversion.create(
228
+ quote_id: quote.id,
229
+ reason: 'Multi-currency settlement'
230
+ )
231
+
232
+ # Or convert at current market rate
233
+ conversion = Airwallex::Conversion.create(
234
+ buy_currency: 'EUR',
235
+ sell_currency: 'USD',
236
+ sell_amount: 5000.00,
237
+ reason: 'Currency exchange'
238
+ )
239
+
240
+ # Check account balances
241
+ balances = Airwallex::Balance.list
242
+ balances.each do |balance|
243
+ next if balance.available_amount <= 0
244
+ puts "#{balance.currency}: #{balance.available_amount} available"
245
+ end
246
+
247
+ # Get specific currency balance
248
+ usd_balance = Airwallex::Balance.retrieve('USD')
249
+ puts "USD Available: #{usd_balance.available_amount}"
250
+ puts "USD Total: #{usd_balance.total_amount}"
251
+ ```
252
+
157
253
  ## Usage
158
254
 
159
255
  ### Authentication
@@ -319,23 +415,29 @@ end
319
415
 
320
416
  ### Currently Implemented Resources
321
417
 
322
- - **Payment Acceptance**:
418
+ - **Payment Acceptance**:
323
419
  - PaymentIntent (create, retrieve, list, update, confirm, cancel, capture)
324
420
  - Refund (create, retrieve, list)
325
421
  - PaymentMethod (create, retrieve, list, update, delete, detach)
326
422
  - Customer (create, retrieve, list, update, delete)
327
- - **Payouts**:
423
+ - Dispute (retrieve, list, accept, submit_evidence)
424
+ - **Payouts**:
328
425
  - Transfer (create, retrieve, list, cancel)
329
426
  - Beneficiary (create, retrieve, list, delete)
427
+ - BatchTransfer (create, retrieve, list)
428
+ - **Foreign Exchange & Multi-Currency**:
429
+ - Rate (retrieve, list) - Real-time exchange rate queries
430
+ - Quote (create, retrieve) - Lock exchange rates with expiration tracking
431
+ - Conversion (create, retrieve, list) - Execute currency conversions
432
+ - Balance (list, retrieve) - Query account balances across currencies
330
433
  - **Webhooks**: Event handling, HMAC-SHA256 signature verification
331
434
 
332
435
  ### Coming in Future Versions
333
436
 
334
- - Disputes and chargebacks
335
- - Foreign exchange (rates, quotes, conversions)
336
437
  - Global accounts
337
438
  - Card issuing
338
- - Batch transfers
439
+ - Subscriptions and billing
440
+ - Virtual account numbers
339
441
 
340
442
  ## Environment Support
341
443
 
@@ -4,20 +4,39 @@ module Airwallex
4
4
  module APIOperations
5
5
  module List
6
6
  def list(params = {}, opts = {})
7
- response = Airwallex.client.get(
8
- resource_path,
9
- params,
10
- opts[:headers] || {}
11
- )
7
+ response = Airwallex.client.get(resource_path, params, opts[:headers] || {})
8
+ build_list_object(response, params)
9
+ end
10
+
11
+ private
12
12
 
13
+ def build_list_object(response, params)
13
14
  ListObject.new(
14
- data: response[:items] || response["items"] || [],
15
- has_more: response[:has_more] || response["has_more"] || false,
16
- next_cursor: response[:next_cursor] || response["next_cursor"],
15
+ data: extract_data(response),
16
+ has_more: extract_has_more(response),
17
+ next_cursor: extract_next_cursor(response),
17
18
  resource_class: self,
18
19
  params: params
19
20
  )
20
21
  end
22
+
23
+ def extract_data(response)
24
+ return response if response.is_a?(Array)
25
+
26
+ response[:items] || response["items"] || response[:data] || response["data"] || []
27
+ end
28
+
29
+ def extract_has_more(response)
30
+ return false unless response.is_a?(Hash)
31
+
32
+ response[:has_more] || response["has_more"] || false
33
+ end
34
+
35
+ def extract_next_cursor(response)
36
+ return nil unless response.is_a?(Hash)
37
+
38
+ response[:next_cursor] || response["next_cursor"]
39
+ end
21
40
  end
22
41
  end
23
42
  end
@@ -59,6 +59,7 @@ module Airwallex
59
59
  class RateLimitError < Error; end
60
60
  class APIError < Error; end
61
61
  class InsufficientFundsError < Error; end
62
+ class QuoteExpiredError < BadRequestError; end
62
63
  class SCARequiredError < PermissionError; end
63
64
  class SignatureVerificationError < Error; end
64
65
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Balance resource for account balance queries
5
+ #
6
+ # Query account balances across all currencies or for specific currencies.
7
+ # Shows available, pending, and reserved amounts.
8
+ #
9
+ # @example Get all balances
10
+ # balances = Airwallex::Balance.list
11
+ # balances.each do |balance|
12
+ # puts "#{balance.currency}: #{balance.available_amount}"
13
+ # end
14
+ #
15
+ # @example Get specific currency balance
16
+ # usd_balance = Airwallex::Balance.retrieve('USD')
17
+ # puts "Available: #{usd_balance.available_amount}"
18
+ # puts "Pending: #{usd_balance.pending_amount}"
19
+ # puts "Reserved: #{usd_balance.reserved_amount}"
20
+ #
21
+ class Balance < APIResource
22
+ extend APIOperations::List
23
+
24
+ def self.resource_path
25
+ "/api/v1/balances/current"
26
+ end
27
+
28
+ # Retrieve balance for a specific currency
29
+ #
30
+ # @param currency [String] Currency code (e.g., 'USD', 'EUR')
31
+ # @return [Airwallex::Balance] Balance object for the currency
32
+ def self.retrieve(currency)
33
+ response = Airwallex.client.get(resource_path, currency: currency)
34
+ # Balance API returns array directly at top level
35
+ balances_array = response.is_a?(Array) ? response : response[:data] || response["data"] || []
36
+ balances = ListObject.new(
37
+ data: balances_array,
38
+ has_more: false,
39
+ resource_class: self
40
+ )
41
+
42
+ # Filter to find the requested currency
43
+ balance = balances.find { |b| b.currency&.upcase == currency.upcase }
44
+ raise NotFoundError, "Balance not found for currency: #{currency}" unless balance
45
+
46
+ balance
47
+ end
48
+
49
+ # Calculate total balance
50
+ #
51
+ # @return [Float] Sum of available, pending, and reserved amounts
52
+ def total_amount
53
+ available = respond_to?(:available_amount) ? available_amount.to_f : 0.0
54
+ pending = respond_to?(:pending_amount) ? pending_amount.to_f : 0.0
55
+ reserved = respond_to?(:reserved_amount) ? reserved_amount.to_f : 0.0
56
+ (available + pending + reserved).round(2)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # BatchTransfer resource for bulk payout operations
5
+ #
6
+ # Batch transfers allow creating multiple transfers in a single API call,
7
+ # improving efficiency for bulk payout scenarios like marketplace payouts or payroll.
8
+ #
9
+ # @example Create a batch transfer
10
+ # batch = Airwallex::BatchTransfer.create(
11
+ # request_id: "batch_#{Time.now.to_i}",
12
+ # source_currency: "USD",
13
+ # transfers: [
14
+ # { beneficiary_id: "ben_001", amount: 100.00, reason: "Payout 1" },
15
+ # { beneficiary_id: "ben_002", amount: 200.00, reason: "Payout 2" }
16
+ # ]
17
+ # )
18
+ #
19
+ # @example Retrieve a batch transfer
20
+ # batch = Airwallex::BatchTransfer.retrieve("batch_123")
21
+ # batch.transfers.each { |t| puts "#{t.id}: #{t.status}" }
22
+ #
23
+ class BatchTransfer < APIResource
24
+ extend APIOperations::Create
25
+ extend APIOperations::Retrieve
26
+ extend APIOperations::List
27
+
28
+ def self.resource_path
29
+ "/api/v1/batch_transfers"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Conversion resource for currency exchange
5
+ #
6
+ # Execute currency conversions with locked quotes or at market rates.
7
+ # Conversions move funds between currency balances in your account.
8
+ #
9
+ # @example Convert with locked quote
10
+ # quote = Airwallex::Quote.create(
11
+ # buy_currency: 'EUR',
12
+ # sell_currency: 'USD',
13
+ # sell_amount: 1000.00
14
+ # )
15
+ # conversion = Airwallex::Conversion.create(
16
+ # quote_id: quote.id,
17
+ # request_id: "conv_#{Time.now.to_i}"
18
+ # )
19
+ #
20
+ # @example Convert at market rate
21
+ # conversion = Airwallex::Conversion.create(
22
+ # buy_currency: 'EUR',
23
+ # sell_currency: 'USD',
24
+ # sell_amount: 500.00,
25
+ # request_id: "conv_#{Time.now.to_i}"
26
+ # )
27
+ #
28
+ # @example List conversion history
29
+ # conversions = Airwallex::Conversion.list(
30
+ # sell_currency: 'USD',
31
+ # status: 'COMPLETED'
32
+ # )
33
+ #
34
+ class Conversion < APIResource
35
+ extend APIOperations::Create
36
+ extend APIOperations::Retrieve
37
+ extend APIOperations::List
38
+
39
+ def self.resource_path
40
+ "/api/v1/conversions"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents a customer for organizing payment methods and transactions
5
+ #
6
+ # Customers allow you to group payment methods and track payment history
7
+ # for individual users or accounts.
8
+ #
9
+ # @example Create a customer
10
+ # customer = Airwallex::Customer.create(
11
+ # email: "john@example.com",
12
+ # first_name: "John",
13
+ # last_name: "Doe",
14
+ # metadata: { internal_id: "user_789" }
15
+ # )
16
+ #
17
+ # @example List payment methods for a customer
18
+ # methods = Airwallex::PaymentMethod.list(customer_id: customer.id)
19
+ class Customer < APIResource
20
+ extend APIOperations::Create
21
+ extend APIOperations::Retrieve
22
+ extend APIOperations::List
23
+ extend APIOperations::Update
24
+ include APIOperations::Update
25
+ extend APIOperations::Delete
26
+
27
+ # @return [String] API resource path for customers
28
+ def self.resource_path
29
+ "/api/v1/pa/customers"
30
+ end
31
+
32
+ # List payment methods for this customer
33
+ #
34
+ # @param params [Hash] additional parameters
35
+ # @return [ListObject<PaymentMethod>] list of payment methods
36
+ def payment_methods(params = {})
37
+ PaymentMethod.list(params.merge(customer_id: id))
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Dispute resource for handling chargebacks and payment disputes
5
+ #
6
+ # Disputes represent chargebacks or payment disputes initiated by cardholders.
7
+ # Merchants can view disputes, submit evidence to challenge them, or accept them.
8
+ #
9
+ # @example List open disputes
10
+ # disputes = Airwallex::Dispute.list(status: 'OPEN')
11
+ #
12
+ # @example Retrieve a dispute
13
+ # dispute = Airwallex::Dispute.retrieve('dis_123')
14
+ #
15
+ # @example Submit evidence
16
+ # dispute = Airwallex::Dispute.retrieve('dis_123')
17
+ # dispute.submit_evidence(
18
+ # customer_communication: "Email showing delivery confirmation",
19
+ # shipping_tracking_number: "1Z999AA10123456784"
20
+ # )
21
+ #
22
+ # @example Accept a dispute
23
+ # dispute = Airwallex::Dispute.retrieve('dis_123')
24
+ # dispute.accept
25
+ #
26
+ class Dispute < APIResource
27
+ extend APIOperations::Retrieve
28
+ extend APIOperations::List
29
+
30
+ def self.resource_path
31
+ "/api/v1/disputes"
32
+ end
33
+
34
+ # Accept a dispute without challenging it
35
+ #
36
+ # @return [Airwallex::Dispute] The updated dispute object
37
+ def accept
38
+ response = Airwallex.client.post("#{resource_path}/#{id}/accept", {})
39
+ refresh_from(response)
40
+ self
41
+ end
42
+
43
+ # Submit evidence to challenge a dispute
44
+ #
45
+ # @param evidence [Hash] Evidence details
46
+ # @option evidence [String] :customer_communication Email or chat logs
47
+ # @option evidence [String] :shipping_tracking_number Tracking number
48
+ # @option evidence [String] :shipping_documentation Proof of shipping
49
+ # @option evidence [String] :customer_signature Signed receipt
50
+ # @option evidence [String] :receipt Proof of purchase
51
+ # @option evidence [String] :refund_policy Refund policy document
52
+ # @option evidence [String] :cancellation_policy Cancellation policy
53
+ # @option evidence [String] :additional_information Other relevant info
54
+ #
55
+ # @return [Airwallex::Dispute] The updated dispute object
56
+ def submit_evidence(evidence)
57
+ response = Airwallex.client.post("#{resource_path}/#{id}/evidence", evidence)
58
+ refresh_from(response)
59
+ self
60
+ end
61
+
62
+ private
63
+
64
+ def resource_path
65
+ self.class.resource_path
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents a payment method (card, bank account, etc.) that can be reused
5
+ #
6
+ # Payment methods allow you to store customer payment credentials securely
7
+ # and reuse them for future payments without collecting details again.
8
+ #
9
+ # @example Create a card payment method
10
+ # pm = Airwallex::PaymentMethod.create(
11
+ # type: "card",
12
+ # card: {
13
+ # number: "4242424242424242",
14
+ # expiry_month: "12",
15
+ # expiry_year: "2025",
16
+ # cvc: "123"
17
+ # },
18
+ # billing: {
19
+ # first_name: "John",
20
+ # email: "john@example.com"
21
+ # }
22
+ # )
23
+ #
24
+ # @example Use saved payment method
25
+ # payment_intent.confirm(payment_method_id: pm.id)
26
+ #
27
+ # @example Update billing details
28
+ # pm.update(billing: { address: { postal_code: "10001" } })
29
+ class PaymentMethod < APIResource
30
+ extend APIOperations::Create
31
+ extend APIOperations::Retrieve
32
+ extend APIOperations::List
33
+ extend APIOperations::Update
34
+ include APIOperations::Update
35
+ extend APIOperations::Delete
36
+
37
+ # @return [String] API resource path for payment methods
38
+ def self.resource_path
39
+ "/api/v1/pa/payment_methods"
40
+ end
41
+
42
+ # Detach this payment method from its customer
43
+ #
44
+ # @return [PaymentMethod] self
45
+ def detach
46
+ response = Airwallex.client.post("#{self.class.resource_path}/#{id}/detach", {})
47
+ refresh_from(response)
48
+ self
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Quote resource for locked exchange rates
5
+ #
6
+ # Create quotes to lock exchange rates for a short period (typically 30-60 seconds).
7
+ # Use quotes to guarantee the rate when executing conversions.
8
+ #
9
+ # @example Create a quote
10
+ # quote = Airwallex::Quote.create(
11
+ # buy_currency: 'EUR',
12
+ # sell_currency: 'USD',
13
+ # sell_amount: 1000.00
14
+ # )
15
+ # puts "Locked rate: #{quote.client_rate}, expires: #{quote.expires_at}"
16
+ #
17
+ # @example Use quote for conversion
18
+ # conversion = Airwallex::Conversion.create(quote_id: quote.id)
19
+ #
20
+ class Quote < APIResource
21
+ extend APIOperations::Create
22
+ extend APIOperations::Retrieve
23
+
24
+ def self.resource_path
25
+ "/api/v1/fx/quotes"
26
+ end
27
+
28
+ # Check if quote has expired
29
+ #
30
+ # @return [Boolean] true if quote is expired
31
+ def expired?
32
+ return false unless respond_to?(:expires_at) && expires_at
33
+
34
+ Time.parse(expires_at) < Time.now
35
+ rescue ArgumentError
36
+ true
37
+ end
38
+
39
+ # Get seconds until expiration
40
+ #
41
+ # @return [Integer, nil] seconds remaining, 0 if expired, nil if no expiration
42
+ def seconds_until_expiration
43
+ return nil unless respond_to?(:expires_at) && expires_at
44
+
45
+ remaining = Time.parse(expires_at) - Time.now
46
+ [remaining.to_i, 0].max
47
+ rescue ArgumentError
48
+ 0
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Rate resource for real-time exchange rates
5
+ #
6
+ # Get indicative exchange rates for currency pairs.
7
+ # Rates are real-time but not locked - use Quote for guaranteed rates.
8
+ #
9
+ # @example Get current rate
10
+ # rate = Airwallex::Rate.retrieve(buy_currency: 'EUR', sell_currency: 'USD')
11
+ # puts "1 USD = #{rate.client_rate} EUR"
12
+ #
13
+ # @example Get multiple rates (Note: API may not support multiple at once)
14
+ # rate = Airwallex::Rate.retrieve(
15
+ # buy_currency: 'EUR',
16
+ # sell_currency: 'USD'
17
+ # )
18
+ #
19
+ class Rate < APIResource
20
+ extend APIOperations::Retrieve
21
+ extend APIOperations::List
22
+
23
+ def self.resource_path
24
+ "/api/v1/fx/rates/current"
25
+ end
26
+
27
+ # Override retrieve to handle query parameters instead of ID
28
+ def self.retrieve(params = {})
29
+ response = Airwallex.client.get(resource_path, params)
30
+ new(response)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents a refund of a payment intent
5
+ #
6
+ # Refunds can be full or partial. Multiple refunds can be created for a single
7
+ # payment intent as long as the total refunded amount doesn't exceed the original amount.
8
+ #
9
+ # @example Create a full refund
10
+ # refund = Airwallex::Refund.create(
11
+ # payment_intent_id: "pi_123",
12
+ # amount: 100.00,
13
+ # reason: "requested_by_customer"
14
+ # )
15
+ #
16
+ # @example Create a partial refund
17
+ # refund = Airwallex::Refund.create(
18
+ # payment_intent_id: "pi_123",
19
+ # amount: 25.00
20
+ # )
21
+ #
22
+ # @example List refunds for a payment
23
+ # refunds = Airwallex::Refund.list(payment_intent_id: "pi_123")
24
+ class Refund < APIResource
25
+ extend APIOperations::Create
26
+ extend APIOperations::Retrieve
27
+ extend APIOperations::List
28
+
29
+ # @return [String] API resource path for refunds
30
+ def self.resource_path
31
+ "/api/v1/pa/refunds"
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Airwallex
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/airwallex.rb CHANGED
@@ -27,6 +27,12 @@ require_relative "airwallex/resources/beneficiary"
27
27
  require_relative "airwallex/resources/refund"
28
28
  require_relative "airwallex/resources/payment_method"
29
29
  require_relative "airwallex/resources/customer"
30
+ require_relative "airwallex/resources/batch_transfer"
31
+ require_relative "airwallex/resources/dispute"
32
+ require_relative "airwallex/resources/rate"
33
+ require_relative "airwallex/resources/quote"
34
+ require_relative "airwallex/resources/conversion"
35
+ require_relative "airwallex/resources/balance"
30
36
 
31
37
  module Airwallex
32
38
  class << self