From d9e9f246d0f0db933f87d5d9deb21d8b081fdfe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Thu, 2 Oct 2025 12:00:34 -0300 Subject: [PATCH 01/10] chore: removes style changes --- CHANGELOG.md | 4 + lib/incognia_api.rb | 2 + lib/incognia_api/bank_account_info.rb | 56 ++++++++++++ lib/incognia_api/pix_key.rb | 16 ++++ spec/bank_account_info_spec.rb | 118 ++++++++++++++++++++++++++ spec/incognia_spec.rb | 109 +++++++++++++++++------- 6 files changed, 274 insertions(+), 31 deletions(-) create mode 100644 lib/incognia_api/bank_account_info.rb create mode 100644 lib/incognia_api/pix_key.rb create mode 100644 spec/bank_account_info_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f0a849..9eb4930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## [Unreleased] +## [3.1.0] - 2025-10-01 + +- Adds support for passing optional debtor_account and creditor_account parameters for registering payments + ## [3.0.0] - 2025-09-22 - Update `faraday` dependency to version 2.13.4 - Remove `faraday_middleware` dependency diff --git a/lib/incognia_api.rb b/lib/incognia_api.rb index bb57e6f..ff18de3 100644 --- a/lib/incognia_api.rb +++ b/lib/incognia_api.rb @@ -8,6 +8,8 @@ require_relative "incognia_api/api" require_relative "incognia_api/location" require_relative "incognia_api/person_id" +require_relative "incognia_api/pix_key" +require_relative "incognia_api/bank_account_info" require_relative "incognia_api/resources/api_resource" require_relative "incognia_api/resources/signup_assessment" diff --git a/lib/incognia_api/bank_account_info.rb b/lib/incognia_api/bank_account_info.rb new file mode 100644 index 0000000..f97858a --- /dev/null +++ b/lib/incognia_api/bank_account_info.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require_relative "pix_key" +require_relative "person_id" + +module Incognia + class BankAccountInfo + attr_reader :account_type, :account_purpose, :holder_type, :holder_tax_id, + :country, :ispb_code, :branch_code, :account_number, + :account_check_digit, :pix_keys + + def initialize( + holder_type:, holder_tax_id:, branch_code:, account_number:, account_type: nil, + account_purpose: nil, + country: nil, + ispb_code: nil, + account_check_digit: nil, + pix_keys: [] + ) + @account_type = account_type + @account_purpose = account_purpose + @holder_type = holder_type + @holder_tax_id = holder_tax_id + @country = country + @ispb_code = ispb_code + @branch_code = branch_code + @account_number = account_number + @account_check_digit = account_check_digit + @pix_keys = pix_keys + end + + def to_hash + h = { + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit + }.compact + + if holder_tax_id + h[:holder_tax_id] = + holder_tax_id.respond_to?(:to_hash) ? holder_tax_id.to_hash : holder_tax_id + end + + if pix_keys && !pix_keys.empty? + h[:pix_keys] = pix_keys.map { |k| k.respond_to?(:to_hash) ? k.to_hash : k } + end + + h + end + end +end diff --git a/lib/incognia_api/pix_key.rb b/lib/incognia_api/pix_key.rb new file mode 100644 index 0000000..a1cd460 --- /dev/null +++ b/lib/incognia_api/pix_key.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Incognia + class PixKey + attr_reader :type, :value + + def initialize(type:, value:) + @type = type + @value = value + end + + def to_hash + {type: type, value: value} + end + end +end diff --git a/spec/bank_account_info_spec.rb b/spec/bank_account_info_spec.rb new file mode 100644 index 0000000..b5fb056 --- /dev/null +++ b/spec/bank_account_info_spec.rb @@ -0,0 +1,118 @@ +require "spec_helper" + +module Incognia + RSpec.describe BankAccountInfo do + let(:account_type) { "savings" } + let(:account_purpose) { "rural" } + let(:holder_type) { "business" } + let(:holder_tax_id) { Incognia::PersonId.new(type: "cpf", value: "12345678901") } + let(:country) { "BR" } + let(:ispb_code) { "18236120" } + let(:branch_code) { "0001" } + let(:account_number) { "123456" } + let(:account_check_digit) { "0" } + let(:pix_keys) do + [ + Incognia::PixKey.new(type: "cpf", value: "12345678901"), + Incognia::PixKey.new(type: "email", value: "human@being.com") + ] + end + + subject(:bank_account_info) do + described_class.new( + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + holder_tax_id: holder_tax_id, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit, + pix_keys: pix_keys + ) + end + + it "requires holder_type, holder_tax_id, branch_code, and account_number" do + expect { described_class.new }.to raise_error(ArgumentError) + + expect { + described_class.new( + holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), + branch_code: "0001", + account_number: "123456" + ) + }.to raise_error(ArgumentError) # missing holder_type + + expect { + described_class.new( + holder_type: "business", + branch_code: "0001", + account_number: "123456" + ) + }.to raise_error(ArgumentError) # missing holder_tax_id + + expect { + described_class.new( + holder_type: "business", + holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), + account_number: "123456" + ) + }.to raise_error(ArgumentError) # missing branch_code + + expect { + described_class.new( + holder_type: "business", + holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), + branch_code: "0001" + ) + }.to raise_error(ArgumentError) # missing account_number + + expect { + described_class.new( + holder_type: "business", + holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), + branch_code: "0001", + account_number: "123456" + ) + }.not_to raise_error + end + + describe "#to_hash" do + it "returns the API format" do + expect(bank_account_info.to_hash).to eql( + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + holder_tax_id: {type: "cpf", value: "12345678901"}, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit, + pix_keys: [{type: "cpf", value: "12345678901"}, {type: "email", value: "human@being.com"}] + ) + end + end + + describe "readers" do + it "exposes attribute readers" do + expect(bank_account_info.account_type).to eq(account_type) + expect(bank_account_info.account_purpose).to eq(account_purpose) + expect(bank_account_info.holder_type).to eq(holder_type) + expect(bank_account_info.holder_tax_id.to_hash).to eq(type: "cpf", value: "12345678901") + expect(bank_account_info.country).to eq(country) + expect(bank_account_info.ispb_code).to eq(ispb_code) + expect(bank_account_info.branch_code).to eq(branch_code) + expect(bank_account_info.account_number).to eq(account_number) + expect(bank_account_info.account_check_digit).to eq(account_check_digit) + expect(bank_account_info.pix_keys.map(&:to_hash)).to eql( + [ + {type: "cpf", value: "12345678901"}, + {type: "email", value: "human@being.com"} + ] + ) + end + end + end +end diff --git a/spec/incognia_spec.rb b/spec/incognia_spec.rb index 6b1da4e..c330e32 100644 --- a/spec/incognia_spec.rb +++ b/spec/incognia_spec.rb @@ -27,9 +27,9 @@ module Incognia RSpec.describe Incognia::Api do before do Incognia.configure( - client_id: 'client_id', - client_secret: 'client_secret', - host: 'https://api.incognia.com/api' + client_id: "client_id", + client_secret: "client_secret", + host: "https://api.incognia.com/api" ) end @@ -63,8 +63,8 @@ module Incognia let(:line_format) do "#{number} #{street} #{city} #{state} #{postal_code}" end - let(:coordinates_format) { { lat: 40.748360070638, lng: -73.985097204837 } } - let(:structured_address) { Address.new(structured: structured_format ) } + let(:coordinates_format) { {lat: 40.748360070638, lng: -73.985097204837} } + let(:structured_address) { Address.new(structured: structured_format) } let(:address) { Address.new(line: line_format) } let(:coordinates_address) { Address.new(coordinates: coordinates_format) } let(:request_token) { SecureRandom.uuid } @@ -84,7 +84,6 @@ module Incognia end context "HTTP request" do - it "hits the endpoint with person_id" do person_id = PersonId.new(type: "cpf", value: "12345678901") @@ -103,7 +102,7 @@ module Incognia expect(stub).to have_been_made.once end - shared_examples_for 'receiving one of the required tokens' do |token_name| + shared_examples_for "receiving one of the required tokens" do |token_name| let(:token_value) { SecureRandom.uuid } it "hits the endpoint with #{token_name}" do @@ -111,7 +110,7 @@ module Incognia stub = stub_signup_request stub.with( - body: { token_name => token_value }, + body: {token_name => token_value}, headers: { 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ } @@ -131,7 +130,7 @@ module Incognia stub_token_request stub = stub_signup_request.with( - body: { request_token: request_token, address_line: line_format }, + body: {request_token: request_token, address_line: line_format}, headers: { 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ } @@ -180,9 +179,9 @@ module Incognia stub_token_request stub = stub_signup_request.with( - body: { request_token: request_token }.merge(opts), + body: {request_token: request_token}.merge(opts), headers: { - 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ + "Content-Type" => "application/json", "Authorization" => /Bearer.*/ } ) @@ -198,11 +197,11 @@ module Incognia it_behaves_like 'receiving optional args', 'account_id' do let(:opts) { { account_id: SecureRandom.uuid } } end - it_behaves_like 'receiving optional args', 'external_id' do - let(:opts) { { external_id: SecureRandom.uuid } } + it_behaves_like "receiving optional args", "external_id" do + let(:opts) { {external_id: SecureRandom.uuid} } end - it_behaves_like 'receiving optional args', 'policy_id' do - let(:opts) { { policy_id: SecureRandom.uuid } } + it_behaves_like "receiving optional args", "policy_id" do + let(:opts) { {policy_id: SecureRandom.uuid} } end end end @@ -240,7 +239,7 @@ module Incognia person_id: person_id.to_hash }, headers: { - 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ + "Content-Type" => "application/json", "Authorization" => /Bearer.*/ } ) @@ -249,7 +248,7 @@ module Incognia expect(stub).to have_been_made.once end - shared_examples_for 'receiving one of the required tokens with account_id' do |token_name| + shared_examples_for "receiving one of the required tokens with account_id" do |token_name| let(:token_value) { SecureRandom.uuid } it "hits the endpoint with #{token_name} and account_id" do @@ -288,45 +287,45 @@ module Incognia type: 'login', request_token: request_token, account_id: account_id, - location: location.to_hash, + location: location.to_hash } stub = stub_login_request.with( body: body, headers: { - 'Content-Type' => 'application/json', - 'Authorization' => /Bearer.*/ + "Content-Type" => "application/json", + "Authorization" => /Bearer.*/ } ) described_class.register_login( request_token: request_token, account_id: account_id, - location: location, + location: location ) - + expect(stub).to have_been_made.once end end - context 'when location with a timestamp is provided' do + context "when location with a timestamp is provided" do let(:location) { Location.new(latitude: 37.7749, longitude: -122.4194, collected_at: "2025-04-27T05:03:45-02:00") } - it_behaves_like 'a login request that includes location in the request body' + it_behaves_like "a login request that includes location in the request body" end - context 'when location without a timestamp is provided' do + context "when location without a timestamp is provided" do let(:location) { Location.new(latitude: 37.7749, longitude: -122.4194) } - it_behaves_like 'a login request that includes location in the request body' + it_behaves_like "a login request that includes location in the request body" end - - context 'when receiving any other optional arguments' do - shared_examples_for 'receiving optional args' do |optional_arguments| + + context "when receiving any other optional arguments" do + shared_examples_for "receiving optional args" do |optional_arguments| it "hits the endpoint also with #{optional_arguments}" do stub_token_request stub = stub_login_request.with( body: { - type: 'login', + type: "login", request_token: request_token, account_id: account_id }.merge(opts), @@ -400,7 +399,55 @@ module Incognia expect(stub).to have_been_made.once end - shared_examples_for 'receiving one of the required tokens with account_id' do |token_name| + it "hits the endpoint with debtor_account and creditor_account" do + debtor_account = BankAccountInfo.new( + holder_type: "business", + holder_tax_id: PersonId.new(type: "cpf", value: "12345678901"), + branch_code: "0001", + account_number: "123456" + ) + + creditor_account = BankAccountInfo.new( + account_type: "savings", + account_purpose: "rural", + holder_type: "business", + holder_tax_id: PersonId.new(type: "cpf", value: "12345678901"), + country: "BR", + ispb_code: "18236120", + branch_code: "0002", + account_number: "654321", + account_check_digit: "0", + pix_keys: [ + PixKey.new(type: "cpf", value: "12345678901"), + PixKey.new(type: "email", value: "human@being.com") + ] + ) + + stub = stub_payment_request.with( + body: { + type: "payment", + request_token: request_token, + account_id: account_id, + debtor_account: debtor_account.to_hash, + creditor_account: creditor_account.to_hash + }, + headers: { + "Content-Type" => "application/json", + "Authorization" => /Bearer.*/ + } + ) + + described_class.register_payment( + request_token: request_token, + account_id: account_id, + debtor_account: debtor_account, + creditor_account: creditor_account + ) + + expect(stub).to have_been_made.once + end + + shared_examples_for "receiving one of the required tokens with account_id" do |token_name| let(:token_value) { SecureRandom.uuid } it "hits the endpoint with #{token_name} and account_id" do From ba8a7d7a6c00c517b1c596c6c7311fe772b938df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Thu, 2 Oct 2025 12:23:09 -0300 Subject: [PATCH 02/10] fix: adds missing file to git --- lib/incognia_api/api.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/incognia_api/api.rb b/lib/incognia_api/api.rb index 89f0ead..0a16bcf 100644 --- a/lib/incognia_api/api.rb +++ b/lib/incognia_api/api.rb @@ -59,7 +59,7 @@ def register_feedback(event:, occurred_at: nil, expires_at: nil, person_id: nil, response.success? end - def register_payment(account_id:, request_token: nil, location: nil, person_id: nil, **opts) + def register_payment(account_id:, request_token: nil, location: nil, person_id: nil, debtor_account: nil, creditor_account: nil, **opts) params = { type: :payment, account_id: account_id, @@ -67,6 +67,8 @@ def register_payment(account_id:, request_token: nil, location: nil, person_id: }.compact params.merge!(location: location.to_hash) if location params.merge!(person_id: person_id.to_hash) if person_id + params.merge!(debtor_account: debtor_account.to_hash) if debtor_account + params.merge!(creditor_account: creditor_account.to_hash) if creditor_account params.merge!(opts) response = connection.request( From b408be9f9d4edf7d216c09cbd7182dc0a5fbb0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Thu, 2 Oct 2025 12:36:49 -0300 Subject: [PATCH 03/10] chore: undoes style modifications --- spec/incognia_spec.rb | 61 ++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/spec/incognia_spec.rb b/spec/incognia_spec.rb index c330e32..b695772 100644 --- a/spec/incognia_spec.rb +++ b/spec/incognia_spec.rb @@ -27,9 +27,9 @@ module Incognia RSpec.describe Incognia::Api do before do Incognia.configure( - client_id: "client_id", - client_secret: "client_secret", - host: "https://api.incognia.com/api" + client_id: 'client_id', + client_secret: 'client_secret', + host: 'https://api.incognia.com/api' ) end @@ -63,8 +63,8 @@ module Incognia let(:line_format) do "#{number} #{street} #{city} #{state} #{postal_code}" end - let(:coordinates_format) { {lat: 40.748360070638, lng: -73.985097204837} } - let(:structured_address) { Address.new(structured: structured_format) } + let(:coordinates_format) { { lat: 40.748360070638, lng: -73.985097204837 } } + let(:structured_address) { Address.new(structured: structured_format ) } let(:address) { Address.new(line: line_format) } let(:coordinates_address) { Address.new(coordinates: coordinates_format) } let(:request_token) { SecureRandom.uuid } @@ -84,6 +84,7 @@ module Incognia end context "HTTP request" do + it "hits the endpoint with person_id" do person_id = PersonId.new(type: "cpf", value: "12345678901") @@ -102,7 +103,7 @@ module Incognia expect(stub).to have_been_made.once end - shared_examples_for "receiving one of the required tokens" do |token_name| + shared_examples_for 'receiving one of the required tokens' do |token_name| let(:token_value) { SecureRandom.uuid } it "hits the endpoint with #{token_name}" do @@ -110,7 +111,7 @@ module Incognia stub = stub_signup_request stub.with( - body: {token_name => token_value}, + body: { token_name => token_value }, headers: { 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ } @@ -130,7 +131,7 @@ module Incognia stub_token_request stub = stub_signup_request.with( - body: {request_token: request_token, address_line: line_format}, + body: { request_token: request_token, address_line: line_format }, headers: { 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ } @@ -179,9 +180,9 @@ module Incognia stub_token_request stub = stub_signup_request.with( - body: {request_token: request_token}.merge(opts), + body: { request_token: request_token }.merge(opts), headers: { - "Content-Type" => "application/json", "Authorization" => /Bearer.*/ + 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ } ) @@ -197,11 +198,11 @@ module Incognia it_behaves_like 'receiving optional args', 'account_id' do let(:opts) { { account_id: SecureRandom.uuid } } end - it_behaves_like "receiving optional args", "external_id" do - let(:opts) { {external_id: SecureRandom.uuid} } + it_behaves_like 'receiving optional args', 'external_id' do + let(:opts) { { external_id: SecureRandom.uuid } } end - it_behaves_like "receiving optional args", "policy_id" do - let(:opts) { {policy_id: SecureRandom.uuid} } + it_behaves_like 'receiving optional args', 'policy_id' do + let(:opts) { { policy_id: SecureRandom.uuid } } end end end @@ -239,7 +240,7 @@ module Incognia person_id: person_id.to_hash }, headers: { - "Content-Type" => "application/json", "Authorization" => /Bearer.*/ + 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ } ) @@ -248,7 +249,7 @@ module Incognia expect(stub).to have_been_made.once end - shared_examples_for "receiving one of the required tokens with account_id" do |token_name| + shared_examples_for 'receiving one of the required tokens with account_id' do |token_name| let(:token_value) { SecureRandom.uuid } it "hits the endpoint with #{token_name} and account_id" do @@ -287,45 +288,45 @@ module Incognia type: 'login', request_token: request_token, account_id: account_id, - location: location.to_hash + location: location.to_hash, } stub = stub_login_request.with( body: body, headers: { - "Content-Type" => "application/json", - "Authorization" => /Bearer.*/ + 'Content-Type' => 'application/json', + 'Authorization' => /Bearer.*/ } ) described_class.register_login( request_token: request_token, account_id: account_id, - location: location + location: location, ) - + expect(stub).to have_been_made.once end end - context "when location with a timestamp is provided" do + context 'when location with a timestamp is provided' do let(:location) { Location.new(latitude: 37.7749, longitude: -122.4194, collected_at: "2025-04-27T05:03:45-02:00") } - it_behaves_like "a login request that includes location in the request body" + it_behaves_like 'a login request that includes location in the request body' end - context "when location without a timestamp is provided" do + context 'when location without a timestamp is provided' do let(:location) { Location.new(latitude: 37.7749, longitude: -122.4194) } - it_behaves_like "a login request that includes location in the request body" + it_behaves_like 'a login request that includes location in the request body' end - - context "when receiving any other optional arguments" do - shared_examples_for "receiving optional args" do |optional_arguments| + + context 'when receiving any other optional arguments' do + shared_examples_for 'receiving optional args' do |optional_arguments| it "hits the endpoint also with #{optional_arguments}" do stub_token_request stub = stub_login_request.with( body: { - type: "login", + type: 'login', request_token: request_token, account_id: account_id }.merge(opts), @@ -447,7 +448,7 @@ module Incognia expect(stub).to have_been_made.once end - shared_examples_for "receiving one of the required tokens with account_id" do |token_name| + shared_examples_for 'receiving one of the required tokens with account_id' do |token_name| let(:token_value) { SecureRandom.uuid } it "hits the endpoint with #{token_name} and account_id" do From d431d2ac352d87482a36541066cbc7dbf6f1084c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Thu, 2 Oct 2025 12:50:03 -0300 Subject: [PATCH 04/10] chore: updates version --- lib/incognia_api/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/incognia_api/version.rb b/lib/incognia_api/version.rb index 9c182c7..cebd329 100644 --- a/lib/incognia_api/version.rb +++ b/lib/incognia_api/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Incognia - VERSION = "3.0.0" + VERSION = "3.1.0" end From d5e98c9da83a951cf3193bd481eda0603ecd85ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Fri, 3 Oct 2025 08:25:46 -0300 Subject: [PATCH 05/10] chore: refactors tests and serialization --- lib/incognia_api/bank_account_info.rb | 37 +++++++++++------------- spec/bank_account_info_spec.rb | 41 ++++++++++++--------------- spec/incognia_spec.rb | 4 +-- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/lib/incognia_api/bank_account_info.rb b/lib/incognia_api/bank_account_info.rb index f97858a..5b342e9 100644 --- a/lib/incognia_api/bank_account_info.rb +++ b/lib/incognia_api/bank_account_info.rb @@ -30,27 +30,24 @@ def initialize( end def to_hash - h = { - account_type: account_type, - account_purpose: account_purpose, - holder_type: holder_type, - country: country, - ispb_code: ispb_code, - branch_code: branch_code, - account_number: account_number, - account_check_digit: account_check_digit + { + account_type:, + account_purpose:, + holder_type:, + country:, + ispb_code:, + branch_code:, + account_number:, + account_check_digit:, + holder_tax_id: serialize_hash(holder_tax_id), + pix_keys: pix_keys&.map { |k| serialize_hash(k) } }.compact - - if holder_tax_id - h[:holder_tax_id] = - holder_tax_id.respond_to?(:to_hash) ? holder_tax_id.to_hash : holder_tax_id - end - - if pix_keys && !pix_keys.empty? - h[:pix_keys] = pix_keys.map { |k| k.respond_to?(:to_hash) ? k.to_hash : k } - end - - h + end + + private + + def serialize_hash(value) + value.respond_to?(:to_hash) ? value.to_hash : value end end end diff --git a/spec/bank_account_info_spec.rb b/spec/bank_account_info_spec.rb index b5fb056..dd65a84 100644 --- a/spec/bank_account_info_spec.rb +++ b/spec/bank_account_info_spec.rb @@ -38,42 +38,42 @@ module Incognia expect { described_class.new( - holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), - branch_code: "0001", - account_number: "123456" + holder_tax_id: holder_tax_id, + branch_code: branch_code, + account_number: account_number ) }.to raise_error(ArgumentError) # missing holder_type expect { described_class.new( - holder_type: "business", - branch_code: "0001", - account_number: "123456" + holder_type: holder_type, + branch_code: branch_code, + account_number: account_number ) }.to raise_error(ArgumentError) # missing holder_tax_id expect { described_class.new( - holder_type: "business", - holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), - account_number: "123456" + holder_type: holder_type, + holder_tax_id: holder_tax_id, + account_number: account_number ) }.to raise_error(ArgumentError) # missing branch_code expect { described_class.new( - holder_type: "business", - holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), - branch_code: "0001" + holder_type: holder_type, + holder_tax_id: holder_tax_id, + branch_code: branch_code ) }.to raise_error(ArgumentError) # missing account_number expect { described_class.new( - holder_type: "business", - holder_tax_id: Incognia::PersonId.new(type: "cpf", value: "12345678901"), - branch_code: "0001", - account_number: "123456" + holder_type: holder_type, + holder_tax_id: holder_tax_id, + branch_code: branch_code, + account_number: account_number ) }.not_to raise_error end @@ -100,18 +100,13 @@ module Incognia expect(bank_account_info.account_type).to eq(account_type) expect(bank_account_info.account_purpose).to eq(account_purpose) expect(bank_account_info.holder_type).to eq(holder_type) - expect(bank_account_info.holder_tax_id.to_hash).to eq(type: "cpf", value: "12345678901") + expect(bank_account_info.holder_tax_id).to eq(holder_tax_id) expect(bank_account_info.country).to eq(country) expect(bank_account_info.ispb_code).to eq(ispb_code) expect(bank_account_info.branch_code).to eq(branch_code) expect(bank_account_info.account_number).to eq(account_number) expect(bank_account_info.account_check_digit).to eq(account_check_digit) - expect(bank_account_info.pix_keys.map(&:to_hash)).to eql( - [ - {type: "cpf", value: "12345678901"}, - {type: "email", value: "human@being.com"} - ] - ) + expect(bank_account_info.pix_keys).to eql(pix_keys) end end end diff --git a/spec/incognia_spec.rb b/spec/incognia_spec.rb index b695772..498e1a9 100644 --- a/spec/incognia_spec.rb +++ b/spec/incognia_spec.rb @@ -412,14 +412,14 @@ module Incognia account_type: "savings", account_purpose: "rural", holder_type: "business", - holder_tax_id: PersonId.new(type: "cpf", value: "12345678901"), + holder_tax_id: PersonId.new(type: "cpf", value: "00000000011"), country: "BR", ispb_code: "18236120", branch_code: "0002", account_number: "654321", account_check_digit: "0", pix_keys: [ - PixKey.new(type: "cpf", value: "12345678901"), + PixKey.new(type: "cpf", value: "00000000011"), PixKey.new(type: "email", value: "human@being.com") ] ) From 4058a7b89e775038f1f66ddee0dbff2b0763ef87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Fri, 3 Oct 2025 09:03:14 -0300 Subject: [PATCH 06/10] fix: support for ruby 3.0.1 syntax --- lib/incognia_api/bank_account_info.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/incognia_api/bank_account_info.rb b/lib/incognia_api/bank_account_info.rb index 5b342e9..01f9513 100644 --- a/lib/incognia_api/bank_account_info.rb +++ b/lib/incognia_api/bank_account_info.rb @@ -31,21 +31,21 @@ def initialize( def to_hash { - account_type:, - account_purpose:, - holder_type:, - country:, - ispb_code:, - branch_code:, - account_number:, - account_check_digit:, - holder_tax_id: serialize_hash(holder_tax_id), - pix_keys: pix_keys&.map { |k| serialize_hash(k) } + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit, + holder_tax_id: serialize_hash(holder_tax_id), + pix_keys: pix_keys&.map { |k| serialize_hash(k) } }.compact end - + private - + def serialize_hash(value) value.respond_to?(:to_hash) ? value.to_hash : value end From 5dcb91626982ad8d8b03c4611255dc3888f396f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Fri, 3 Oct 2025 09:38:00 -0300 Subject: [PATCH 07/10] chore: refactors spec --- spec/bank_account_info_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/bank_account_info_spec.rb b/spec/bank_account_info_spec.rb index dd65a84..9f49587 100644 --- a/spec/bank_account_info_spec.rb +++ b/spec/bank_account_info_spec.rb @@ -84,13 +84,13 @@ module Incognia account_type: account_type, account_purpose: account_purpose, holder_type: holder_type, - holder_tax_id: {type: "cpf", value: "12345678901"}, + holder_tax_id: holder_tax_id.to_hash, country: country, ispb_code: ispb_code, branch_code: branch_code, account_number: account_number, account_check_digit: account_check_digit, - pix_keys: [{type: "cpf", value: "12345678901"}, {type: "email", value: "human@being.com"}] + pix_keys: pix_keys.map(&:to_hash) ) end end From f73ea325d51b77648b2e789683b6f46f11402920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Mon, 6 Oct 2025 17:15:40 -0300 Subject: [PATCH 08/10] chore: refactors tests and renames class --- Gemfile.lock | 2 +- lib/incognia_api.rb | 2 +- lib/incognia_api/bank_account.rb | 54 +++++++++++++ spec/bank_account_spec.rb | 133 +++++++++++++++++++++++++++++++ spec/incognia_spec.rb | 4 +- spec/person_id_spec.rb | 1 - 6 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 lib/incognia_api/bank_account.rb create mode 100644 spec/bank_account_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index 23effcb..0c0d251 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - incognia_api (3.0.0) + incognia_api (3.1.0) faraday (~> 2.13) GEM diff --git a/lib/incognia_api.rb b/lib/incognia_api.rb index ff18de3..2361627 100644 --- a/lib/incognia_api.rb +++ b/lib/incognia_api.rb @@ -9,7 +9,7 @@ require_relative "incognia_api/location" require_relative "incognia_api/person_id" require_relative "incognia_api/pix_key" -require_relative "incognia_api/bank_account_info" +require_relative "incognia_api/bank_account" require_relative "incognia_api/resources/api_resource" require_relative "incognia_api/resources/signup_assessment" diff --git a/lib/incognia_api/bank_account.rb b/lib/incognia_api/bank_account.rb new file mode 100644 index 0000000..1c8a318 --- /dev/null +++ b/lib/incognia_api/bank_account.rb @@ -0,0 +1,54 @@ +require_relative "pix_key" +require_relative "person_id" + +module Incognia + class BankAccount + attr_reader :account_type, :account_purpose, :holder_type, :holder_tax_id, + :country, :ispb_code, :branch_code, :account_number, + :account_check_digit, :pix_keys + + def initialize( + holder_type:, holder_tax_id:, branch_code:, account_number:, account_type: nil, + account_purpose: nil, + country: nil, + ispb_code: nil, + account_check_digit: nil, + pix_keys: nil + ) + @account_type = account_type + @account_purpose = account_purpose + @holder_type = holder_type + @holder_tax_id = holder_tax_id + @country = country + @ispb_code = ispb_code + @branch_code = branch_code + @account_number = account_number + @account_check_digit = account_check_digit + @pix_keys = pix_keys + end + + def to_hash + h = { + account_type:, + account_purpose:, + holder_type:, + country:, + ispb_code:, + branch_code:, + account_number:, + account_check_digit: + }.compact + + if holder_tax_id + h[:holder_tax_id] = + holder_tax_id.respond_to?(:to_hash) ? holder_tax_id.to_hash : holder_tax_id + end + + if pix_keys && !pix_keys.empty? + h[:pix_keys] = pix_keys.map { |k| k.respond_to?(:to_hash) ? k.to_hash : k } + end + + h + end + end +end diff --git a/spec/bank_account_spec.rb b/spec/bank_account_spec.rb new file mode 100644 index 0000000..782dcd8 --- /dev/null +++ b/spec/bank_account_spec.rb @@ -0,0 +1,133 @@ +require "spec_helper" + +module Incognia + RSpec.describe BankAccount do + let(:account_type) { "savings" } + let(:account_purpose) { "rural" } + let(:holder_type) { "business" } + let(:holder_tax_id) { Incognia::PersonId.new(type: "cpf", value: "12345678901") } + let(:country) { "BR" } + let(:ispb_code) { "18236120" } + let(:branch_code) { "0001" } + let(:account_number) { "123456" } + let(:account_check_digit) { "0" } + let(:pix_keys) do + [ + Incognia::PixKey.new(type: "cpf", value: "12345678901"), + Incognia::PixKey.new(type: "email", value: "human@being.com") + ] + end + let(:required_attrs) do + { + holder_type: holder_type, + holder_tax_id: holder_tax_id, + branch_code: branch_code, + account_number: account_number + } + end + + subject(:bank_account) do + described_class.new( + account_type:, + account_purpose:, + holder_type:, + holder_tax_id:, + country:, + ispb_code:, + branch_code:, + account_number:, + account_check_digit:, + pix_keys: + ) + end + + it "raises error when no required kwargs are provided" do + expect { described_class.new }.to raise_error(ArgumentError) + end + + it "requires holder_type" do + expect { described_class.new(**required_attrs.except(:holder_type)) }.to raise_error(ArgumentError) + end + + it "requires holder_tax_id" do + expect { described_class.new(**required_attrs.except(:holder_tax_id)) }.to raise_error(ArgumentError) + end + + it "requires branch_code" do + expect { described_class.new(**required_attrs.except(:branch_code)) }.to raise_error(ArgumentError) + end + + it "requires account_number" do + expect { described_class.new(**required_attrs.except(:account_number)) }.to raise_error(ArgumentError) + end + + it "does not raise error when all required kwargs are provided" do + expect { described_class.new(**required_attrs) }.not_to raise_error + end + + describe "#to_hash" do + context "with only required fields" do + subject(:only_required) { described_class.new(**required_attrs) } + + it "returns required fields (optional fields omitted)" do + h = only_required.to_hash + expect(h).to include( + holder_type: holder_type, + holder_tax_id: holder_tax_id.to_hash, + branch_code: branch_code, + account_number: account_number + ) + expect(h).not_to include(:account_type, :account_purpose, :country, :ispb_code, :account_check_digit, :pix_keys) + end + end + + context "when informing optional fields" do + it "returns the API format with all fields" do + expect(bank_account.to_hash).to eql( + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + holder_tax_id: holder_tax_id.to_hash, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit, + pix_keys: pix_keys.map(&:to_hash) + ) + end + end + + context "when holder_tax_id is not a PersonId nor a Hash" do + it "keeps the value unchanged" do + raw_id = "12345678901" + account = described_class.new(**required_attrs.merge(holder_tax_id: raw_id)) + expect(account.to_hash[:holder_tax_id]).to eq(raw_id) + end + end + + context "when pix_keys do not contain PixKey nor Hash items" do + it "keeps the items unchanged" do + raw_keys = ["a", :b, 123] + account = described_class.new(**required_attrs.merge(pix_keys: raw_keys)) + expect(account.to_hash[:pix_keys]).to eq(raw_keys) + end + end + end + + describe "readers" do + it "exposes attribute readers" do + expect(bank_account.account_type).to eq(account_type) + expect(bank_account.account_purpose).to eq(account_purpose) + expect(bank_account.holder_type).to eq(holder_type) + expect(bank_account.holder_tax_id).to eq(holder_tax_id) + expect(bank_account.country).to eq(country) + expect(bank_account.ispb_code).to eq(ispb_code) + expect(bank_account.branch_code).to eq(branch_code) + expect(bank_account.account_number).to eq(account_number) + expect(bank_account.account_check_digit).to eq(account_check_digit) + expect(bank_account.pix_keys).to eql(pix_keys) + end + end + end +end diff --git a/spec/incognia_spec.rb b/spec/incognia_spec.rb index 498e1a9..b5b0929 100644 --- a/spec/incognia_spec.rb +++ b/spec/incognia_spec.rb @@ -401,14 +401,14 @@ module Incognia end it "hits the endpoint with debtor_account and creditor_account" do - debtor_account = BankAccountInfo.new( + debtor_account = BankAccount.new( holder_type: "business", holder_tax_id: PersonId.new(type: "cpf", value: "12345678901"), branch_code: "0001", account_number: "123456" ) - creditor_account = BankAccountInfo.new( + creditor_account = BankAccount.new( account_type: "savings", account_purpose: "rural", holder_type: "business", diff --git a/spec/person_id_spec.rb b/spec/person_id_spec.rb index 660f2cc..215ceeb 100644 --- a/spec/person_id_spec.rb +++ b/spec/person_id_spec.rb @@ -1,4 +1,3 @@ -# spec/incognia/person_id_spec.rb require "spec_helper" module Incognia From 72ea2f271ec7b818433933bf40337dc88ecc0c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Mon, 6 Oct 2025 17:35:58 -0300 Subject: [PATCH 09/10] fix: removes syntax sugar for ruby 3.0 compatibility --- lib/incognia_api/bank_account.rb | 16 ++++++++-------- spec/bank_account_spec.rb | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/incognia_api/bank_account.rb b/lib/incognia_api/bank_account.rb index 1c8a318..180ba30 100644 --- a/lib/incognia_api/bank_account.rb +++ b/lib/incognia_api/bank_account.rb @@ -29,14 +29,14 @@ def initialize( def to_hash h = { - account_type:, - account_purpose:, - holder_type:, - country:, - ispb_code:, - branch_code:, - account_number:, - account_check_digit: + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit }.compact if holder_tax_id diff --git a/spec/bank_account_spec.rb b/spec/bank_account_spec.rb index 782dcd8..a15c073 100644 --- a/spec/bank_account_spec.rb +++ b/spec/bank_account_spec.rb @@ -28,16 +28,16 @@ module Incognia subject(:bank_account) do described_class.new( - account_type:, - account_purpose:, - holder_type:, - holder_tax_id:, - country:, - ispb_code:, - branch_code:, - account_number:, - account_check_digit:, - pix_keys: + account_type: account_type, + account_purpose: account_purpose, + holder_type: holder_type, + holder_tax_id: holder_tax_id, + country: country, + ispb_code: ispb_code, + branch_code: branch_code, + account_number: account_number, + account_check_digit: account_check_digit, + pix_keys: pix_keys ) end From 2aea3f86b9921d8a430ae3ac263ba3872a4c00ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Ori=C3=A1?= Date: Mon, 6 Oct 2025 17:44:49 -0300 Subject: [PATCH 10/10] fix: removes BankAccountInfo and its spec --- lib/incognia_api/bank_account_info.rb | 53 ------------ spec/bank_account_info_spec.rb | 113 -------------------------- 2 files changed, 166 deletions(-) delete mode 100644 lib/incognia_api/bank_account_info.rb delete mode 100644 spec/bank_account_info_spec.rb diff --git a/lib/incognia_api/bank_account_info.rb b/lib/incognia_api/bank_account_info.rb deleted file mode 100644 index 01f9513..0000000 --- a/lib/incognia_api/bank_account_info.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -require_relative "pix_key" -require_relative "person_id" - -module Incognia - class BankAccountInfo - attr_reader :account_type, :account_purpose, :holder_type, :holder_tax_id, - :country, :ispb_code, :branch_code, :account_number, - :account_check_digit, :pix_keys - - def initialize( - holder_type:, holder_tax_id:, branch_code:, account_number:, account_type: nil, - account_purpose: nil, - country: nil, - ispb_code: nil, - account_check_digit: nil, - pix_keys: [] - ) - @account_type = account_type - @account_purpose = account_purpose - @holder_type = holder_type - @holder_tax_id = holder_tax_id - @country = country - @ispb_code = ispb_code - @branch_code = branch_code - @account_number = account_number - @account_check_digit = account_check_digit - @pix_keys = pix_keys - end - - def to_hash - { - account_type: account_type, - account_purpose: account_purpose, - holder_type: holder_type, - country: country, - ispb_code: ispb_code, - branch_code: branch_code, - account_number: account_number, - account_check_digit: account_check_digit, - holder_tax_id: serialize_hash(holder_tax_id), - pix_keys: pix_keys&.map { |k| serialize_hash(k) } - }.compact - end - - private - - def serialize_hash(value) - value.respond_to?(:to_hash) ? value.to_hash : value - end - end -end diff --git a/spec/bank_account_info_spec.rb b/spec/bank_account_info_spec.rb deleted file mode 100644 index 9f49587..0000000 --- a/spec/bank_account_info_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -require "spec_helper" - -module Incognia - RSpec.describe BankAccountInfo do - let(:account_type) { "savings" } - let(:account_purpose) { "rural" } - let(:holder_type) { "business" } - let(:holder_tax_id) { Incognia::PersonId.new(type: "cpf", value: "12345678901") } - let(:country) { "BR" } - let(:ispb_code) { "18236120" } - let(:branch_code) { "0001" } - let(:account_number) { "123456" } - let(:account_check_digit) { "0" } - let(:pix_keys) do - [ - Incognia::PixKey.new(type: "cpf", value: "12345678901"), - Incognia::PixKey.new(type: "email", value: "human@being.com") - ] - end - - subject(:bank_account_info) do - described_class.new( - account_type: account_type, - account_purpose: account_purpose, - holder_type: holder_type, - holder_tax_id: holder_tax_id, - country: country, - ispb_code: ispb_code, - branch_code: branch_code, - account_number: account_number, - account_check_digit: account_check_digit, - pix_keys: pix_keys - ) - end - - it "requires holder_type, holder_tax_id, branch_code, and account_number" do - expect { described_class.new }.to raise_error(ArgumentError) - - expect { - described_class.new( - holder_tax_id: holder_tax_id, - branch_code: branch_code, - account_number: account_number - ) - }.to raise_error(ArgumentError) # missing holder_type - - expect { - described_class.new( - holder_type: holder_type, - branch_code: branch_code, - account_number: account_number - ) - }.to raise_error(ArgumentError) # missing holder_tax_id - - expect { - described_class.new( - holder_type: holder_type, - holder_tax_id: holder_tax_id, - account_number: account_number - ) - }.to raise_error(ArgumentError) # missing branch_code - - expect { - described_class.new( - holder_type: holder_type, - holder_tax_id: holder_tax_id, - branch_code: branch_code - ) - }.to raise_error(ArgumentError) # missing account_number - - expect { - described_class.new( - holder_type: holder_type, - holder_tax_id: holder_tax_id, - branch_code: branch_code, - account_number: account_number - ) - }.not_to raise_error - end - - describe "#to_hash" do - it "returns the API format" do - expect(bank_account_info.to_hash).to eql( - account_type: account_type, - account_purpose: account_purpose, - holder_type: holder_type, - holder_tax_id: holder_tax_id.to_hash, - country: country, - ispb_code: ispb_code, - branch_code: branch_code, - account_number: account_number, - account_check_digit: account_check_digit, - pix_keys: pix_keys.map(&:to_hash) - ) - end - end - - describe "readers" do - it "exposes attribute readers" do - expect(bank_account_info.account_type).to eq(account_type) - expect(bank_account_info.account_purpose).to eq(account_purpose) - expect(bank_account_info.holder_type).to eq(holder_type) - expect(bank_account_info.holder_tax_id).to eq(holder_tax_id) - expect(bank_account_info.country).to eq(country) - expect(bank_account_info.ispb_code).to eq(ispb_code) - expect(bank_account_info.branch_code).to eq(branch_code) - expect(bank_account_info.account_number).to eq(account_number) - expect(bank_account_info.account_check_digit).to eq(account_check_digit) - expect(bank_account_info.pix_keys).to eql(pix_keys) - end - end - end -end