Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Do yourself a favor: go grab some ice cubes by installing this refreshing librar
- [Accounts](#accounts)
- [Account Numbers](#account-numbers)
- [Transfers](#transfers)
- [Transfer Batches](#transfer-batches)
- [Simulate](#simulate)
- [Account Verifications](#account-verifications)
- [Entity onboardings API Examples](#entity-onboardings-api-examples)
Expand Down Expand Up @@ -139,6 +140,15 @@ transfer = client.v2.transfers.create(
)
client.v2.transfers.return('transfer_id')

# Transfer Batches
transfer_batches = client.v2.transfer_batches.list
transfer_batch = client.v2.transfer_batches.get('transfer_batch_id')
transfer_batch = client.v2.transfer_batches.create(
description: 'Supplier payments',
currency: 'MXN',
transfers: [{...}]
)

# Simulate
simulated_transfer = client.v2.simulate.receive_transfer(
account_number_id: 'account_number_id',
Expand Down Expand Up @@ -360,6 +370,42 @@ transfers = client.v2.transfers.list
returned_transfer = client.v2.transfers.return('transfer_id')
```

#### Transfer Batches

```ruby
require 'fintoc'

client = Fintoc::Client.new('api_key', jws_private_key: 'jws_private_key')

# Create a transfer batch. Each transfer has the same shape as `transfers.create`, without `currency`
transfer_batch = client.v2.transfer_batches.create(
description: 'Supplier payments',
currency: 'MXN',
transfers: [
{
account_id: 'account_id',
amount: 10000,
comment: 'Invoice 1234',
reference_id: '123456',
counterparty: { account_number: '735969000000203297' }
}
]
)

# Get a specific transfer batch
transfer_batch = client.v2.transfer_batches.get('transfer_batch_id')

# List transfer batches, optionally filtered by status and creation date
transfer_batches = client.v2.transfer_batches.list(
'status[]': %w[succeeded partially_succeeded],
since: '2026-10-01T00:00:00Z',
until: '2026-10-31T23:59:59Z'
)

# List the transfers of a batch
transfers = client.v2.transfers.list(transfer_batch_id: 'transfer_batch_id')
```

#### Simulate

```ruby
Expand Down
7 changes: 7 additions & 0 deletions lib/fintoc/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class InvalidExpiresAtError < FintocError; end
class InvalidInstallmentsCurrencyError < FintocError; end
class InvalidClabeError < FintocError; end
class MismatchTransferAccountCurrencyError < FintocError; end
class InvalidTransfersError < FintocError; end
class InvalidTransfersSizeError < FintocError; end
class InvalidDescriptionSizeError < FintocError; end

# 401 Unauthorized Errors
class AuthenticationError < FintocError; end
Expand Down Expand Up @@ -124,6 +127,7 @@ class InvalidTransferStatusError < FintocError; end
class InvalidTransferDirectionError < FintocError; end
class AccountNumberLimitReachedError < FintocError; end
class AccountCannotBeBlockedError < FintocError; end
class InvalidSenderAccountsError < FintocError; end

# 422 Unprocessable Entity Errors
class InvalidOtpCodeError < FintocError; end
Expand All @@ -150,6 +154,9 @@ class InternalServerError < FintocError; end
class UnrecognizedRequestError < FintocError; end
class CoreResponseError < FintocError; end

# 501 Not Implemented Errors
class OperationNotImplementedError < FintocError; end

# Webhook Errors
class WebhookSignatureError < FintocError; end

Expand Down
5 changes: 5 additions & 0 deletions lib/fintoc/v2/client/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'fintoc/v2/managers/accounts_manager'
require 'fintoc/v2/managers/account_numbers_manager'
require 'fintoc/v2/managers/transfers_manager'
require 'fintoc/v2/managers/transfer_batches_manager'
require 'fintoc/v2/managers/simulate_manager'
require 'fintoc/v2/managers/account_verifications_manager'

Expand All @@ -25,6 +26,10 @@ def transfers
@transfers ||= Managers::TransfersManager.new(self)
end

def transfer_batches
@transfer_batches ||= Managers::TransferBatchesManager.new(self)
end

def simulate
@simulate ||= Managers::SimulateManager.new(self)
end
Expand Down
47 changes: 47 additions & 0 deletions lib/fintoc/v2/managers/transfer_batches_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'fintoc/v2/resources/transfer_batch'

module Fintoc
module V2
module Managers
class TransferBatchesManager
def initialize(client)
@client = client
end

def create(description:, currency:, transfers:, idempotency_key: nil)
data = _create_transfer_batch(description:, currency:, transfers:, idempotency_key:)
build_transfer_batch(data)
end

def get(transfer_batch_id)
data = _get_transfer_batch(transfer_batch_id)
build_transfer_batch(data)
end

def list(**params)
_list_transfer_batches(**params).map { |data| build_transfer_batch(data) }
end

private

def _create_transfer_batch(description:, currency:, transfers:, idempotency_key: nil)
@client
.post(version: :v2, use_jws: true, idempotency_key:)
.call('transfer_batches', description:, currency:, transfers:)
end

def _get_transfer_batch(transfer_batch_id)
@client.get(version: :v2).call("transfer_batches/#{transfer_batch_id}")
end

def _list_transfer_batches(**params)
@client.get(version: :v2).call('transfer_batches', **params)
end

def build_transfer_batch(data)
Fintoc::V2::TransferBatch.new(**data, client: @client)
end
end
end
end
end
114 changes: 114 additions & 0 deletions lib/fintoc/v2/resources/transfer_batch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
require 'money'

module Fintoc
module V2
class TransferBatch
attr_reader :id, :object, :mode, :description, :status, :currency, :transfer_count,
:amount, :succeeded_count, :settled_amount, :created_at, :authorized_at,
:rejected_at, :expired_at, :succeeded_at, :partially_succeeded_at

def initialize( # rubocop:disable Metrics/MethodLength
id:,
object:,
mode:,
status:,
currency:,
transfer_count:,
amount:,
description: nil,
succeeded_count: nil,
settled_amount: nil,
created_at: nil,
authorized_at: nil,
rejected_at: nil,
expired_at: nil,
succeeded_at: nil,
partially_succeeded_at: nil,
client: nil,
**
)
@id = id
@object = object
@mode = mode
@description = description
@status = status
@currency = currency
@transfer_count = transfer_count
@amount = amount
@succeeded_count = succeeded_count
@settled_amount = settled_amount
@created_at = created_at
@authorized_at = authorized_at
@rejected_at = rejected_at
@expired_at = expired_at
@succeeded_at = succeeded_at
@partially_succeeded_at = partially_succeeded_at
@client = client
end

def to_s
amount_str = Money.from_cents(@amount, @currency).format
"📦 #{amount_str} (#{@id}) - #{@status}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usamos emoticones en otra parte? no sea que rompa alguna integración

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sii en el sdk se usan jaja nose porque pero seguí el patrón nomas

end

def refresh
fresh_transfer_batch = @client.transfer_batches.get(@id)
refresh_from_transfer_batch(fresh_transfer_batch)
end

def pending_authorization?
@status == 'pending_authorization'
end

def in_progress?
@status == 'in_progress'
end

def rejected?
@status == 'rejected'
end

def expired?
@status == 'expired'
end

def succeeded?
@status == 'succeeded'
end

def partially_succeeded?
@status == 'partially_succeeded'
end

def failed?
@status == 'failed'
end

private

def refresh_from_transfer_batch(transfer_batch) # rubocop:disable Metrics/MethodLength
unless transfer_batch.id == @id
raise ArgumentError, 'Transfer batch must be the same instance'
end

@object = transfer_batch.object
@mode = transfer_batch.mode
@description = transfer_batch.description
@status = transfer_batch.status
@currency = transfer_batch.currency
@transfer_count = transfer_batch.transfer_count
@amount = transfer_batch.amount
@succeeded_count = transfer_batch.succeeded_count
@settled_amount = transfer_batch.settled_amount
@created_at = transfer_batch.created_at
@authorized_at = transfer_batch.authorized_at
@rejected_at = transfer_batch.rejected_at
@expired_at = transfer_batch.expired_at
@succeeded_at = transfer_batch.succeeded_at
@partially_succeeded_at = transfer_batch.partially_succeeded_at

self
end
end
end
end
2 changes: 2 additions & 0 deletions spec/lib/fintoc/v2/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

it_behaves_like 'a client with transfers manager'

it_behaves_like 'a client with transfer batches manager'

it_behaves_like 'a client with simulate manager'

it_behaves_like 'a client with account verifications manager'
Expand Down
Loading
Loading