Skip to content
Open
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
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.3.1
3.4.3
110 changes: 96 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,25 @@ gem build asaas-ruby.gemspec

### Changelog

- 0.2.24 - Add support to PIX billing type and fills missing CHANGELOG entries
- 0.2.23 - Add support to Ruby 2.7 and Rails 6.1
- 0.2.22 - Remove unecessary ActiveSupport version limit
- 0.2.21 - Add credit fields to Payment
- 0.2.20 - Adds debug flag to check responses
- 0.2.19 - Small fixes
- 0.2.18 - Account documents upload
- 0.2.17 - Add support to DEPOSIT billing type
- 0.2.16 - Wallet account tranfers
- 0.2.15 - Bank account tranfers
- 0.2.24 - Add support to PIX billing type and fills missing CHANGELOG entries
- 0.2.23 - Add support to Ruby 2.7 and Rails 6.1
- 0.2.22 - Remove unecessary ActiveSupport version limit
- 0.2.21 - Add credit fields to Payment
- 0.2.20 - Adds debug flag to check responses
- 0.2.19 - Small fixes
- 0.2.18 - Account documents upload
- 0.2.17 - Add support to DEPOSIT billing type
- 0.2.16 - Wallet account tranfers
- 0.2.15 - Bank account tranfers

### Requirements

- Ruby 2.3+.

## Usage

### Creating payments

```ruby
require 'asaas-ruby'

Expand All @@ -53,11 +55,91 @@ asaas_client.customers.create(customer)
charge = Asaas::Payment.new({
customer: customer.id,
dueDate: '2019-10-10',
billingType: 'BOLETO',
description: "Teste de boleto",
value: BigDecimal("103.54").to_f,
billingType: 'BOLETO', # PIX CREDIT_CARD ....
description: "Teste pagamento",
value: (Float Integer BigDecimal String).to_s, # 100.00
postalService: false
})

asaas_client.payments.create(charge)
```
```

### Pix dinâmico qr & code

```ruby
new_payment = Asaas::Payment.new({
billingType: "PIX",
customer: customer.id, # "cus_000005219617",
value: value, # Money.to_s 100.00
description: description
})
payment = asaas.payments.create(new_payment)

# Check if payment creation was successful and it's a PIX payment
# (payment will be an Asaas::Payment model or Asaas::Entity::Payment depending on API version and success)
if payment && !payment.is_a?(Asaas::Entity::Error) && payment.id # && payment.billingType == "PIX"
puts "Payment created successfully with ID: #{payment.id}"

# Fetch the PIX QR Code
qr_code_data = asaas.payments.pix_qr_code(payment.id)

if qr_code_data.is_a?(Asaas::Entity::PaymentPix)
puts "PIX QR Code details fetched successfully:"
puts " Encoded Image: #{qr_code_data.encodedImage ? qr_code_data.encodedImage[0..30] + '...' : 'N/A'}" # Truncated for brevity
puts " Payload: #{qr_code_data.payload}"
puts " Expiration Date: #{qr_code_data.expirationDate}"
elsif qr_code_data.is_a?(Asaas::Entity::Error)
puts "Error fetching PIX QR Code:"
qr_code_data.errors.each do |error|
puts " Code: #{error.code}, Description: #{error.description}"
end
else
puts "Unexpected response when fetching PIX QR Code."
end
else
puts "Failed to create PIX payment or payment ID is missing."
if payment.is_a?(Asaas::Entity::Error)
payment.errors.each do |error|
puts " Error Code: #{error.code}, Description: #{error.description}"
end
end
end
```

### Pix estático

TODO

### Transparent Checkout

Note: asaas uses CCV (others: CVV/CVC)

```ruby
charge = Asaas::Payment.new({
customer: customer.id, # "cus_000005219613",
billingType: 'CREDIT_CARD',
value: lots_money, # Money.to_s 100.00
dueDate: "%Y-%m-%d", # "2023-07-21"
# creditCard:
creditCardHolderName: card.name, # jose da silva sauro
creditCardNumber: card.number, # "5162306219378829"
creditCardExpiryMonth: card.month, # "05"
creditCardExpiryYear: card.year, # "2024"
creditCardCcv: card.cvv, # "318" NOTE: asaas call CCV, we call CVV
# creditCardHolder:
creditCardHolderFullName: card.holder, # "Marcelo Henrique Almeida"
creditCardHolderEmail: card.email, # "marcelo.almeida@gmail.com"
creditCardHolderCpfCnpj: card.doc, # "24971563792"
creditCardHolderAddressNumber: card.addr, # "277"
creditCardHolderPostalCode: card.zip, # "89223-005"
creditCardHolderAddressNumber: card.addr, # "277"
creditCardHolderAddressComplement: "", # card.compl,
creditCardHolderMobilePhone: card.phone, # "47 99999-9999"
creditCardHolderPhone: ""
# },
remoteIp: card.ip # user.last_ip
})

@asaas.payments.create(charge)

```
6 changes: 3 additions & 3 deletions asaas-ruby.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ Gem::Specification.new do |spec|

spec.add_dependency "activesupport", '>= 4.2'
spec.add_dependency "virtus", '>= 1.0'
spec.add_dependency "dry-types", '0.15.0'
spec.add_dependency "dry-struct", '0.7.0'
spec.add_dependency "dry-monads", '1.2.0'
spec.add_dependency "dry-types", '1.8.2'
spec.add_dependency "dry-struct", '1.8.0'
spec.add_dependency "dry-monads", '1.8.3'
spec.add_dependency "typhoeus", '>= 1.0'
spec.add_dependency "rest-client", '>= 1.8'
spec.add_dependency "awesome_print", '>= 1.6'
Expand Down
1 change: 1 addition & 0 deletions lib/asaas-ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Asaas
autoload :Customer, 'asaas/models/customer'
autoload :Notification, 'asaas/models/notification'
autoload :Payment, 'asaas/models/payment'
autoload :PaymentPix, 'asaas/models/payment_pix'
autoload :Discount, 'asaas/models/discount'
autoload :Interest, 'asaas/models/interest'
autoload :Fine, 'asaas/models/fine'
Expand Down
1 change: 1 addition & 0 deletions lib/asaas/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Api
autoload :Customer, 'asaas/api/customer'
autoload :Notification, 'asaas/api/notification'
autoload :Payment, 'asaas/api/payment'
autoload :PaymentPix, 'asaas/api/payment_pix'
autoload :Subscription, 'asaas/api/subscription'
autoload :Webhook, 'asaas/api/webhook'
autoload :Transfer, 'asaas/api/transfer'
Expand Down
8 changes: 7 additions & 1 deletion lib/asaas/api/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,13 @@ def get_headers
def body_parser(body)
return nil unless body

body.to_h.delete_if { |k, v| v.nil? || v.to_s.empty? }.to_json
# Convert BigDecimal values to Float to ensure standard decimal in JSON,
parsed_body = body.to_h.transform_values do |v|
v.is_a?(BigDecimal) ? v.to_f : v
end

# then remove nil or empty string values.
parsed_body.delete_if { |k, v| v.nil? || v.to_s.empty? }.to_json
end

def request_headers
Expand Down
10 changes: 10 additions & 0 deletions lib/asaas/api/payment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ def initialize(token, api_version)
super(token, api_version, '/payments')
end

# Fetches the PIX QR Code for a given payment ID.
# @param payment_id [String] The ID of the payment.
# @return [Asaas::Entity::PaymentPix, Asaas::Entity::Error] The PIX QR code entity or an error entity.
def pix_qr_code(payment_id)
raise ArgumentError, "payment_id is required" if payment_id.nil? || payment_id.to_s.empty?

payment_pix_api = Asaas::Api::PaymentPix.new(@token, @api_version, payment_id)
payment_pix_api.fetch
end

end
end
end
25 changes: 25 additions & 0 deletions lib/asaas/api/payment_pix.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Asaas
module Api
class PaymentPix < Asaas::Api::Base

def initialize(token, api_version, pid)
super(token, api_version, "/payments/#{pid}/pixQrCode")
end

# Method to fetch the QR Code data
# @return [Asaas::Entity::PaymentPix, Asaas::Entity::Error] The PIX QR code entity or an error entity.
def fetch
request(:get) # Calls Base#request with method GET, empty params, nil body
parse_response # Calls Base#parse_response, which will call our overridden response_success
end

protected

# Override response_success to handle the specific structure of pixQrCode response
def response_success
hash = JSON.parse(@response.body)
Asaas::Entity::PaymentPix.new(hash)
end
end
end
end
1 change: 1 addition & 0 deletions lib/asaas/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Entity
autoload :Meta, 'asaas/entity/meta'
autoload :Notification, 'asaas/entity/notification'
autoload :Payment, 'asaas/entity/payment'
autoload :PaymentPix, 'asaas/entity/payment_pix'
autoload :Subscription, 'asaas/entity/subscription'
end
end
2 changes: 1 addition & 1 deletion lib/asaas/entity/payment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Payment
attribute :creditCardHolderPhoneDDD, String
attribute :creditCardHolderMobilePhone, String
attribute :creditCardHolderMobilePhoneDDD, String

attribute :remoteIp, String
end
end
end
11 changes: 11 additions & 0 deletions lib/asaas/entity/payment_pix.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Asaas
module Entity
class PaymentPix
include Virtus.model

attribute :encodedImage, String
attribute :payload, String
attribute :expirationDate, String
end
end
end
26 changes: 23 additions & 3 deletions lib/asaas/models/payment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Payment < Model
attribute :id, Types::Coercible::String.optional.default(nil)
attribute :customer, Types::Coercible::String
attribute :billingType, BillingTypes.optional.default(nil)
attribute :value, Types::Coercible::Decimal.optional.default(nil)
attribute :value, Types::SafeCoercibleDecimal.optional.default(nil)
attribute :dueDate, Types::Coercible::String.optional.default(nil)
attribute :description, Types::Coercible::String.optional.default(nil)
attribute :externalReference, Types::Coercible::String.optional.default(nil)
Expand All @@ -20,8 +20,8 @@ class Payment < Model
attribute :dateCreated, Types::Coercible::String.optional.default(nil)
attribute :subscription, Types::Coercible::String.optional.default(nil)
attribute :originalDueDate, Types::Coercible::String.optional.default(nil)
attribute :originalValue, Types::Coercible::Decimal.optional.default(nil)
attribute :interestValue, Types::Coercible::Decimal.optional.default(nil)
attribute :originalValue, Types::SafeCoercibleDecimal.optional.default(nil)
attribute :interestValue, Types::SafeCoercibleDecimal.optional.default(nil)
attribute :confirmedDate, Types::Coercible::String.optional.default(nil)
attribute :paymentDate, Types::Coercible::String.optional.default(nil)
attribute :clientPaymentDate, Types::Coercible::String.optional.default(nil)
Expand All @@ -32,5 +32,25 @@ class Payment < Model

attribute :creditDate, Types::Coercible::String.optional.default(nil)
attribute :estimatedCreditDate, Types::Coercible::String.optional.default(nil)

# Transparent checkout
attribute :creditCardHolderName, Types::Coercible::String.optional.default(nil)
attribute :creditCardNumber, Types::Coercible::String.optional.default(nil)
attribute :creditCardExpiryMonth, Types::Coercible::String.optional.default(nil)
attribute :creditCardExpiryYear, Types::Coercible::String.optional.default(nil)
attribute :creditCardCcv, Types::Coercible::String.optional.default(nil)
# Credit card holder information
attribute :creditCardHolderFullName, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderEmail, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderCpfCnpj, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderAddress, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderAddressNumber, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderAddressComplement, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderProvince, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderCity, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderUf, Types::Coercible::String.optional.default(nil)
attribute :creditCardHolderPostalCode, Types::Coercible::String.optional.default(nil)

attribute :remoteIp, Types::Coercible::String.optional.default(nil)
end
end
8 changes: 8 additions & 0 deletions lib/asaas/models/payment_pix.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Asaas
class PaymentPix < Model

attribute :encodedImage, Types::Coercible::String.optional.default(nil) # Imagem do QrCode em base64
attribute :payload, Types::Coercible::String # Copia e Cola do QrCode
attribute :expirationDate, Types::Coercible::String.optional.default(nil)
end
end
6 changes: 3 additions & 3 deletions lib/asaas/models/transfer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ class Transfer < Model

attribute :id, Types::Coercible::String.optional.default(nil)
attribute :dateCreated, Types::Coercible::String.optional.default(nil)
attribute :value, Types::Coercible::Decimal.optional.default(nil)
attribute :netValue, Types::Coercible::Decimal.optional.default(nil)
attribute :transferFee, Types::Coercible::Decimal.optional.default(nil)
attribute :value, Types::SafeCoercibleDecimal.optional.default(nil)
attribute :netValue, Types::SafeCoercibleDecimal.optional.default(nil)
attribute :transferFee, Types::SafeCoercibleDecimal.optional.default(nil)
attribute :status, Status.optional.default(nil)
attribute :effectiveDate, Types::Coercible::String.optional.default(nil)
attribute :scheduleDate, Types::Coercible::String.optional.default(nil)
Expand Down
12 changes: 12 additions & 0 deletions lib/asaas/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,16 @@

module Types
include Dry::Types(default: :nominal)

# Custom Decimal type to ensure safe Float to BigDecimal conversion.
# This type explicitly converts Floats to Strings before creating a BigDecimal object
# to avoid the "can't omit precision for a Float" error.
SafeCoercibleDecimal = Types.Constructor(BigDecimal) do |value|
begin
# Explicitly convert all to string, as it should be
BigDecimal(value.to_s) # For Integer, BigDecimal itself, etc.
rescue ArgumentError, TypeError
Dry::Types::Undefined # Let dry-types handle it as a validation error or apply default.
end
end
end
20 changes: 17 additions & 3 deletions spec/customer_spec.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
require 'asaas-ruby'

RSpec.describe Asaas::Customer do
RSpec.describe Asaas::Customer do

let(:customer_token) { 'a97d808e77b51653df429b6f9eecf90e3034d6ae35393509fefa5c202bfeb8f9' }

before do
before do
Asaas::Configuration.token = '544333290e93b9bbcd8107b3d9586e3bef774fb41584790a5ff061e4e0392ed5'
end

it 'can create a new' do


it 'can create a new' do
stub_request(:post, "https://sandbox.asaas.com/api/v3/customers").
with(
body: "{\"name\":\"Marcos Junior\",\"cpfCnpj\":\"34960665807\",\"notificationDisabled\":false,\"deleted\":false}",
headers: {
'Access-Token'=>'a97d808e77b51653df429b6f9eecf90e3034d6ae35393509fefa5c202bfeb8f9',
'Content-Type'=>'application/json',
'Expect'=>'',
'User-Agent'=>'Typhoeus - https://github.com/typhoeus/typhoeus'
}).
to_return(status: 200, body: "OK", headers: {})


params = {name: 'Marcos Junior', cpfCnpj: '34960665807'}
customer = Asaas::Customer.new(params)

Expand Down
Loading