From 7b807e11da4e7d222aeb3e97ac54f84071bf0567 Mon Sep 17 00:00:00 2001 From: nofxx Date: Fri, 16 May 2025 21:29:56 -0300 Subject: [PATCH 1/5] update gem versions --- .ruby-version | 2 +- asaas-ruby.gemspec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ruby-version b/.ruby-version index a625450..6cb9d3d 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.1 \ No newline at end of file +3.4.3 diff --git a/asaas-ruby.gemspec b/asaas-ruby.gemspec index 7d14141..952ea91 100644 --- a/asaas-ruby.gemspec +++ b/asaas-ruby.gemspec @@ -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' From b0431379aa1302c76eaf7121de69791b4d2b1a58 Mon Sep 17 00:00:00 2001 From: nofxx Date: Tue, 20 May 2025 01:46:34 -0300 Subject: [PATCH 2/5] add transparent checkout --- README.md | 57 ++++++++++++++++++++++++++++++------- lib/asaas/entity/payment.rb | 2 +- lib/asaas/models/payment.rb | 22 +++++++++++++- spec/customer_spec.rb | 20 +++++++++++-- 4 files changed, 85 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 1bd3faa..f1763f8 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,16 @@ 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 @@ -38,6 +38,8 @@ gem build asaas-ruby.gemspec ## Usage +### Creating payments + ```ruby require 'asaas-ruby' @@ -60,4 +62,37 @@ charge = Asaas::Payment.new({ }) asaas_client.payments.create(charge) -``` \ No newline at end of file +``` + +### Transparent Checkout + +```ruby + charge = Asaas::Payment.new({ + customer: customer.id, # "cus_000005219613", + billingType: 'CREDIT_CARD', + value: value.to_i, # Money.to_s 100.00 + dueDate: 30.days.from_now.strftime("%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) + +# Note: asaas uses CCV (others: CVV/CVC) +``` diff --git a/lib/asaas/entity/payment.rb b/lib/asaas/entity/payment.rb index 11fcd20..2e790e1 100644 --- a/lib/asaas/entity/payment.rb +++ b/lib/asaas/entity/payment.rb @@ -42,7 +42,7 @@ class Payment attribute :creditCardHolderPhoneDDD, String attribute :creditCardHolderMobilePhone, String attribute :creditCardHolderMobilePhoneDDD, String - + attribute :remoteIp, String end end end \ No newline at end of file diff --git a/lib/asaas/models/payment.rb b/lib/asaas/models/payment.rb index b2ea49e..8d9ba5a 100644 --- a/lib/asaas/models/payment.rb +++ b/lib/asaas/models/payment.rb @@ -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::Coercible::BigDecimal.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) @@ -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 diff --git a/spec/customer_spec.rb b/spec/customer_spec.rb index 267d4e2..58fa44d 100644 --- a/spec/customer_spec.rb +++ b/spec/customer_spec.rb @@ -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) From 88aa15a2bd1db69bfe258ca57be42a50a6f08cfb Mon Sep 17 00:00:00 2001 From: nofxx Date: Wed, 21 May 2025 13:28:16 -0300 Subject: [PATCH 3/5] add payment pix api end --- lib/asaas-ruby.rb | 1 + lib/asaas/api.rb | 1 + lib/asaas/api/payment.rb | 10 ++++++++++ lib/asaas/api/payment_pix.rb | 25 +++++++++++++++++++++++++ lib/asaas/entity.rb | 1 + lib/asaas/entity/payment_pix.rb | 11 +++++++++++ lib/asaas/models/payment_pix.rb | 8 ++++++++ 7 files changed, 57 insertions(+) create mode 100644 lib/asaas/api/payment_pix.rb create mode 100644 lib/asaas/entity/payment_pix.rb create mode 100644 lib/asaas/models/payment_pix.rb diff --git a/lib/asaas-ruby.rb b/lib/asaas-ruby.rb index c9426d9..b7e3883 100644 --- a/lib/asaas-ruby.rb +++ b/lib/asaas-ruby.rb @@ -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' diff --git a/lib/asaas/api.rb b/lib/asaas/api.rb index 31fa195..8ad121b 100644 --- a/lib/asaas/api.rb +++ b/lib/asaas/api.rb @@ -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' diff --git a/lib/asaas/api/payment.rb b/lib/asaas/api/payment.rb index d0fb48d..2872deb 100644 --- a/lib/asaas/api/payment.rb +++ b/lib/asaas/api/payment.rb @@ -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 \ No newline at end of file diff --git a/lib/asaas/api/payment_pix.rb b/lib/asaas/api/payment_pix.rb new file mode 100644 index 0000000..bdfa141 --- /dev/null +++ b/lib/asaas/api/payment_pix.rb @@ -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 \ No newline at end of file diff --git a/lib/asaas/entity.rb b/lib/asaas/entity.rb index 9647b6c..9125968 100644 --- a/lib/asaas/entity.rb +++ b/lib/asaas/entity.rb @@ -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 \ No newline at end of file diff --git a/lib/asaas/entity/payment_pix.rb b/lib/asaas/entity/payment_pix.rb new file mode 100644 index 0000000..5212f91 --- /dev/null +++ b/lib/asaas/entity/payment_pix.rb @@ -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 diff --git a/lib/asaas/models/payment_pix.rb b/lib/asaas/models/payment_pix.rb new file mode 100644 index 0000000..b11e39f --- /dev/null +++ b/lib/asaas/models/payment_pix.rb @@ -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 From 2b69b82c165783183811358e168845295dc55802 Mon Sep 17 00:00:00 2001 From: nofxx Date: Wed, 21 May 2025 13:31:42 -0300 Subject: [PATCH 4/5] add examples readme --- README.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f1763f8..ebbf9a6 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,57 @@ charge = Asaas::Payment.new({ 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 + dueDate: asaas_date(1.days.from_now), # "2023-07-21" + 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", @@ -94,5 +143,4 @@ asaas_client.payments.create(charge) @asaas.payments.create(charge) -# Note: asaas uses CCV (others: CVV/CVC) ``` From 273513657d4c164539e2117e13b412ca77852cf7 Mon Sep 17 00:00:00 2001 From: nofxx Date: Wed, 21 May 2025 14:24:18 -0300 Subject: [PATCH 5/5] use BigDecimal until the end add specs --- README.md | 27 ++++--- lib/asaas/api/base.rb | 8 +- lib/asaas/models/payment.rb | 6 +- lib/asaas/models/transfer.rb | 6 +- lib/asaas/types.rb | 12 +++ spec/payment_spec.rb | 137 +++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 5 ++ 7 files changed, 180 insertions(+), 21 deletions(-) create mode 100644 spec/payment_spec.rb diff --git a/README.md b/README.md index ebbf9a6..dd6ecea 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,9 @@ 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 }) @@ -71,7 +71,6 @@ asaas_client.payments.create(charge) billingType: "PIX", customer: customer.id, # "cus_000005219617", value: value, # Money.to_s 100.00 - dueDate: asaas_date(1.days.from_now), # "2023-07-21" description: description }) payment = asaas.payments.create(new_payment) @@ -117,16 +116,16 @@ Note: asaas uses CCV (others: CVV/CVC) ```ruby charge = Asaas::Payment.new({ - customer: customer.id, # "cus_000005219613", + customer: customer.id, # "cus_000005219613", billingType: 'CREDIT_CARD', - value: value.to_i, # Money.to_s 100.00 - dueDate: 30.days.from_now.strftime("%Y-%m-%d"), # "2023-07-21" + 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 + 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" @@ -134,11 +133,11 @@ Note: asaas uses CCV (others: CVV/CVC) creditCardHolderAddressNumber: card.addr, # "277" creditCardHolderPostalCode: card.zip, # "89223-005" creditCardHolderAddressNumber: card.addr, # "277" - creditCardHolderAddressComplement: "", # card.compl, + creditCardHolderAddressComplement: "", # card.compl, creditCardHolderMobilePhone: card.phone, # "47 99999-9999" creditCardHolderPhone: "" # }, - # remoteIp: card.ip # user.last_ip + remoteIp: card.ip # user.last_ip }) @asaas.payments.create(charge) diff --git a/lib/asaas/api/base.rb b/lib/asaas/api/base.rb index c8e06f1..26b995a 100644 --- a/lib/asaas/api/base.rb +++ b/lib/asaas/api/base.rb @@ -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 diff --git a/lib/asaas/models/payment.rb b/lib/asaas/models/payment.rb index 8d9ba5a..b99df86 100644 --- a/lib/asaas/models/payment.rb +++ b/lib/asaas/models/payment.rb @@ -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::BigDecimal.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) @@ -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) diff --git a/lib/asaas/models/transfer.rb b/lib/asaas/models/transfer.rb index 861ff67..d5afd74 100644 --- a/lib/asaas/models/transfer.rb +++ b/lib/asaas/models/transfer.rb @@ -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) diff --git a/lib/asaas/types.rb b/lib/asaas/types.rb index d01827a..66264fb 100644 --- a/lib/asaas/types.rb +++ b/lib/asaas/types.rb @@ -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 \ No newline at end of file diff --git a/spec/payment_spec.rb b/spec/payment_spec.rb new file mode 100644 index 0000000..a6b1e60 --- /dev/null +++ b/spec/payment_spec.rb @@ -0,0 +1,137 @@ +require 'spec_helper' + +RSpec.describe Asaas::Payment do + let(:api_token) { 'test_api_token_for_payment_spec' } + let(:asaas_client) { Asaas::Client.new(api_token) } + let(:base_url) { Asaas::Configuration.get_endpoint(3) } # Assumes API v3 for payments + let(:customer_id) { 'cus_000000000001' } + + let(:request_headers) do + { + 'Access-Token' => api_token, + 'Content-Type' => 'application/json' + } + end + + let(:default_payment_response_attributes) do + { + object: 'payment', + id: 'pay_123456789012', + customer: customer_id, + billingType: 'PIX', + value: 10.0, + dueDate: '2024-12-31', + description: 'Test Payment from API', # Assuming API might return its own description or echo + status: 'PENDING' + } + end + + describe '.create' do + let(:payment_attributes_for_creation) do + { + customer: customer_id, + billingType: 'PIX', + value: 10.00, # Will be coerced to BigDecimal by model, then to float in JSON + dueDate: '2024-12-31', + description: 'Test Payment for creation' + } + end + + it 'creates a payment successfully with basic attributes' do + # The model will convert value to BigDecimal. to_h.to_json will make it a float. + expected_request_json_body = payment_attributes_for_creation.dup + expected_request_json_body[:value] = 10.0 # How it should look in JSON + + stub_request(:post, "#{base_url}/payments") + .with( + body: expected_request_json_body.to_json, + headers: request_headers + ) + .to_return(status: 200, body: default_payment_response_attributes.to_json, headers: { 'Content-Type' => 'application/json' }) + + payment_model = Asaas::Payment.new(payment_attributes_for_creation) + created_payment = asaas_client.payments.create(payment_model) + + expect(created_payment).to be_a(Asaas::Payment) + expect(created_payment.id).to eq('pay_123456789012') + expect(created_payment.value).to eq(BigDecimal('10.0')) # Model stores as BigDecimal + expect(created_payment.billingType).to eq('PIX') + expect(created_payment.description).to eq('Test Payment from API') # From mocked response + expect(created_payment.customer).to eq(customer_id) + end + + shared_examples 'value coercion for payment creation' do |input_value, expected_json_value_in_request| + it "handles value as #{input_value.class} (input: #{input_value}), sending #{expected_json_value_in_request} in JSON" do + attributes_for_model = payment_attributes_for_creation.merge(value: input_value) + + # This is what the JSON body of the POST request should look like + expected_request_body_hash = payment_attributes_for_creation.merge(value: expected_json_value_in_request) + + response_payload = default_payment_response_attributes.merge(value: expected_json_value_in_request).to_json + + stub_request(:post, "#{base_url}/payments") + .with( + body: expected_request_body_hash.to_json, + headers: request_headers + ) + .to_return(status: 200, body: response_payload, headers: { 'Content-Type' => 'application/json' }) + + payment_model = Asaas::Payment.new(attributes_for_model) + created_payment = asaas_client.payments.create(payment_model) + + expect(created_payment).to be_a(Asaas::Payment) + # The model attribute 'value' will be a BigDecimal after creation from response + expect(created_payment.value).to eq(BigDecimal(expected_json_value_in_request.to_s)) + end + end + + context 'when value is an Integer' do + include_examples 'value coercion for payment creation', 100, 100.0 + end + + context 'when value is a Float' do + include_examples 'value coercion for payment creation', 123.454, 123.454 + end + + context 'when value is a String representing a number' do + include_examples 'value coercion for payment creation', '1250.75', 1250.75 + end + + context 'when value is a BigDecimal' do + include_examples 'value coercion for payment creation', BigDecimal('55.99'), 55.99 + end + + context 'when value is a String like "50.00" (with trailing zeros)' do + include_examples 'value coercion for payment creation', '50.00', 50.0 + end + end + + describe '#pix_qr_code' do + let(:payment_id) { 'pay_pix_valid123' } + let(:pix_qr_code_response_body) { { encodedImage: 'base64...', payload: 'pixpayload', expirationDate: '2025-01-01T00:00:00Z' }.to_json } + + it 'fetches the PIX QR code successfully' do + stub_request(:get, "#{base_url}/payments/#{payment_id}/pixQrCode").with(headers: request_headers) + .to_return(status: 200, body: pix_qr_code_response_body, headers: { 'Content-Type' => 'application/json' }) + + qr_code_data = asaas_client.payments.pix_qr_code(payment_id) + expect(qr_code_data).to be_a(Asaas::Entity::PaymentPix) + expect(qr_code_data.encodedImage).to eq('base64...') + expect(qr_code_data.payload).to eq('pixpayload') + end + + it 'raises ArgumentError if payment_id is nil' do + expect { asaas_client.payments.pix_qr_code(nil) }.to raise_error(ArgumentError, "payment_id is required") + end + + it 'returns Asaas::Entity::Error when API call fails for QR code' do + error_response = { errors: [{ code: 'not_found', description: 'Payment not found.' }] }.to_json + stub_request(:get, "#{base_url}/payments/#{payment_id}/pixQrCode").with(headers: request_headers) + .to_return(status: 404, body: error_response, headers: { 'Content-Type' => 'application/json' }) + + result = asaas_client.payments.pix_qr_code(payment_id) + expect(result).to be_a(Asaas::Entity::Error) + expect(result.errors.first.code).to eq('not_found') + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0aa7157..2b847e5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,6 +16,11 @@ # users commonly want. # # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration + +# Add the project's lib directory to the load path to ensure 'asaas-ruby' can be required directly. +$LOAD_PATH.unshift(File.expand_path('../lib', __dir__)) +require 'asaas-ruby' + RSpec.configure do |config| # rspec-expectations config goes here. You can use an alternate # assertion/expectation library such as wrong or the stdlib/minitest