diff --git a/README.md b/README.md index 91b4034..dae0aaa 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,73 @@ assessment = api.register_login( # => # ``` +### Registering Payment + +This method registers a new payment for the given installation and account, returning a `hash`, +containing the risk assessment and supporting evidence. + +```ruby +api = Incognia::Api.new(client_id: 'client-id', + client_secret: 'client-secret') + +addresses = [ + { + 'type': 'shipping', + 'structured_address': { + 'locale': 'pt-BR', + 'country_name': 'Brasil', + 'country_code': 'BR', + 'state': 'SP', + 'city': 'São Paulo', + 'borough': '', + 'neighborhood': 'Bela Vista', + 'street': 'Av. Paulista', + 'number': '1578', + 'complements': 'Andar 2', + 'postal_code': '01310-200' + }, + 'address_coordinates': { + 'lat': -23.561414, + 'lng': -46.6558819 + } + } +] + +payment_value = { + 'amount': 5.0, + 'currency': 'BRL' +} + +payment_methods = [ + { + 'type': 'credit_card', + 'credit_card_info': { + 'bin': '123456', + 'last_four_digits': '1234', + 'expiry_year': '2027', + 'expiry_month': '10' + } + }, + { + 'type': 'debit_card', + 'debit_card_info': { + 'bin': '123456', + 'last_four_digits': '1234', + 'expiry_year': '2027', + 'expiry_month': '10' + } + } +] + +assessment = api.register_payment(installation_id: 'installation-id', + account_id: 'account-id', + external_id: 'external-id', + addresses: addresses, + payment_value: payment_value, + payment_methods: payment_methods) + +``` + ### Registering a Feedback This method registers a feedback event for the given identifiers (optional arguments), returning true when success. diff --git a/lib/incognia_api.rb b/lib/incognia_api.rb index fb267b4..0ffe03c 100644 --- a/lib/incognia_api.rb +++ b/lib/incognia_api.rb @@ -9,6 +9,7 @@ require_relative "incognia_api/resources/api_resource" require_relative "incognia_api/resources/signup_assessment" require_relative "incognia_api/resources/login_assessment" +require_relative "incognia_api/resources/payment_assessment" require_relative "incognia_api/resources/credentials" require_relative "incognia_api/constants/feedback_event" diff --git a/lib/incognia_api/api.rb b/lib/incognia_api/api.rb index 2e6b200..5317e8d 100644 --- a/lib/incognia_api/api.rb +++ b/lib/incognia_api/api.rb @@ -69,5 +69,18 @@ def register_feedback(event: , timestamp: nil, **ids) response.success? end + + def register_payment(installation_id:, account_id:, **opts) + params = { installation_id: installation_id, account_id: account_id, type: :payment } + params.merge!(opts) + + response = connection.request( + :post, + 'v2/authentication/transactions', + params + ) + + PaymentAssessment.from_hash(response.body) if response.success? + end end end diff --git a/lib/incognia_api/resources/payment_assessment.rb b/lib/incognia_api/resources/payment_assessment.rb new file mode 100644 index 0000000..e74b21f --- /dev/null +++ b/lib/incognia_api/resources/payment_assessment.rb @@ -0,0 +1,5 @@ +require_relative "api_resource" + +module Incognia + class PaymentAssessment < APIResource; end +end diff --git a/spec/fixtures/payment-unknown.json b/spec/fixtures/payment-unknown.json new file mode 100644 index 0000000..13c4050 --- /dev/null +++ b/spec/fixtures/payment-unknown.json @@ -0,0 +1,36 @@ +{ + "id": "f3bf8d46-6dcd-49a0-92f3-51f95b05f6fb", + "risk_assessment": "unknown", + "reasons": [], + "evidence": { + "device_model": "iPhone9,3", + "known_account": false, + "location_services": { + "location_permission_enabled": true, + "location_sensors_enabled": true + }, + "device_integrity": { + "probable_root": false, + "emulator": false, + "gps_spoofing": false, + "from_official_store": true, + "app_tampering": false, + "installation_source": "not_available" + }, + "device_fraud_reputation": "unknown", + "device_behavior_reputation": "unknown", + "accessed_accounts": 2, + "app_reinstallations": 0, + "active_installations": 2, + "first_device_login": true, + "app_tampering": { + "result": "not_available", + "app_debugging": "not_available", + "code_injection": "not_available", + "signature_mismatch": "not_available", + "package_mismatch": "not_available" + } + }, + "installation_id": "lXV12s2FdW4MjBMd8_Cn9G1bs9zOzOidLiLwQBdHZQK4TACs7Xe6Eaxgz-YTBlKj76xbmnnDLHIjA48sAXKlxKXRRKN_QLP4OfGUQqWDvRdm6RFbj9vSbsir0WQom0PCyBh5F0hspJ0i_Jf5jKUpsA", + "device_id": "jNC_Bwb2Vr9hIXATUuboOTFxzV8acb67671o4DddhvSCu_X5QcQwJ_-IiUb_roULOul_Nkbps-XpREP4Btz3Ew" +} \ No newline at end of file diff --git a/spec/helpers/api_spec_helpers.rb b/spec/helpers/api_spec_helpers.rb index 682483e..b9ee1c1 100644 --- a/spec/helpers/api_spec_helpers.rb +++ b/spec/helpers/api_spec_helpers.rb @@ -12,6 +12,9 @@ def self.included(rspec) rspec.let(:missing_required_params_fixture) do File.new("spec/fixtures/missing-required-params.json").read end + rspec.let(:unknown_payment_fixture) do + File.new("spec/fixtures/payment-unknown.json").read + end end def url_regex(endpoint) @@ -90,4 +93,14 @@ def stub_register_feedback_request status: 200, headers: { 'Content-Type' => 'application/json' }) end + + def stub_payment_request + stub_request( + :post, "https://api.incognia.com/api/v2/authentication/transactions" + ).with(body: hash_including(type: 'payment')). + to_return( + status: 200, + body: unknown_payment_fixture, + headers: { 'Content-Type' => 'application/json' }) + end end diff --git a/spec/incognia_spec.rb b/spec/incognia_spec.rb index 1669ff7..548c8f5 100644 --- a/spec/incognia_spec.rb +++ b/spec/incognia_spec.rb @@ -274,6 +274,85 @@ module Incognia end + describe "#register_payment" do + let(:installation_id) { SecureRandom.uuid } + let(:account_id) { SecureRandom.uuid } + + it "when successful returns the resource" do + stub_token_request + stub_payment_request + + payment = api.register_payment( + installation_id: installation_id, + account_id: account_id + ) + + expected = JSON.parse(unknown_payment_fixture, symbolize_names: true) + expect(payment.id).to eql expected[:id] + expect(payment.risk_assessment).to eql expected[:risk_assessment] + expect_evidences_to_match(payment, expected) + end + + context "HTTP request" do + it "hits the endpoint with installation_id and account_id" do + stub_token_request + + stub = stub_payment_request.with( + body: { + type: 'payment', + installation_id: installation_id, account_id: account_id + }, + headers: { + 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ + } + ) + + payment = api.register_payment( + installation_id: installation_id, + account_id: account_id + ) + + expect(stub).to have_been_made.once + end + + 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_payment_request.with( + body: { + type: 'payment', + installation_id: installation_id, + account_id: account_id + }.merge(opts), + headers: { + 'Content-Type' => 'application/json', 'Authorization' => /Bearer.*/ + } + ) + + payment = api.register_payment( + installation_id: installation_id, + account_id: account_id, + **opts + ) + + expect(stub).to have_been_made.once + end + end + + it_behaves_like 'receiving optional args', 'external_id', 'payment request', 'aaa' do + let(:opts) { { external_id: 'external-id' } } + end + it_behaves_like 'receiving optional args', 'payment_value' do + let(:opts) { { payment_value: { 'amount': 5.0, 'currency': 'BRL' } } } + end + it_behaves_like 'receiving optional args', 'external_id and payment_value' do + let(:opts) { { external_id: 'external-id', payment_value: 12.5 } } + end + end + end + end describe "#register_feedback" do let(:event) { Incognia::Constants::FeedbackEvent.constants.sample.to_s } @@ -389,5 +468,4 @@ def expect_evidences_to_match(model, expected) to eql expected[:evidence][:location_services][:location_sensors_enabled] end end - end