Skip to content
Draft
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## v2.11.0

* Added the `phone_verification_method`,
`phone_was_verification_successful`, and `phone_verification_time`
attributes to `Minfraud::Components::Billing`. They describe the most
recent verification of the billing phone number.
* Boolean inputs are now always sent as JSON booleans, and `false` values
are no longer dropped from the request. Previously, `false` was omitted
for every boolean input. `true` was sent as the string `"true"` for
`/credit_card/was_3d_secure_successful` and for boolean custom inputs.
The `/order/has_gift_message`, `/order/is_gift`, and
`/payment/was_authorized` inputs already sent `true` as a JSON boolean.

## v2.10.0 (2026-07-21)

* Added the `residential` attribute to the `anonymizer` object on
Expand Down
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,20 @@ assessment = Minfraud::Assessments.new(
domain: 'maxmind.com',
},
billing: {
first_name: 'First',
last_name: 'Last',
company: 'Company',
address: '101 Address Rd.',
address_2: 'Unit 5',
city: 'New Haven',
region: 'CT',
country: 'US',
postal: '06510',
phone_number: '123-456-7890',
phone_country_code: '1',
first_name: 'First',
last_name: 'Last',
company: 'Company',
address: '101 Address Rd.',
address_2: 'Unit 5',
city: 'New Haven',
region: 'CT',
country: 'US',
postal: '06510',
phone_number: '123-456-7890',
phone_country_code: '1',
phone_verification_method: :delivered_code,
phone_verification_time: '2026-10-01T14:30:00Z',
phone_was_verification_successful: true,
},
shipping: {
first_name: 'ShipFirst',
Expand Down
19 changes: 7 additions & 12 deletions lib/minfraud/components/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,22 @@ def to_json(*_args)
#
# @return [Hash]
def populate!(hash, v_sym)
return hash unless (value = instance_variable_get(v_sym))
value = instance_variable_get(v_sym)
return hash if value.nil?

key = v_sym.to_s.gsub(/@/, '')
hash.merge!(key => represent(key, value))
hash.merge!(key => represent(value))
end

# Return the value according to the request format.
#
# @param key [Symbol] An instance variable symbol.
# Return the value according to the request format. Booleans stay
# booleans. Other values become strings.
#
# @param value [Object] An instance variable value.
#
# @return [Object]
def represent(key, value)
BOOLS.include?(key) ? value : value.to_s
def represent(value)
[true, false].include?(value) ? value : value.to_s
end

# Keys that have to remain boolean
BOOLS = %w[was_authorized is_gift has_gift_message].freeze

private_constant :BOOLS
end
end
end
50 changes: 49 additions & 1 deletion lib/minfraud/components/billing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,54 @@ module Components
# Billing corresponds to the billing object of a minFraud request.
#
# @see https://dev.maxmind.com/minfraud/api-documentation/requests/?lang=en#schema--request--billing
class Billing < Addressable; end
class Billing < Addressable
include ::Minfraud::Enum

# The most recent method used to verify the billing phone number. This
# must be one of +:delivered_code+, +:network+, or +:other+.
# +:delivered_code+ is a code delivered to the phone, such as by SMS,
# voice call, or messaging app. +:network+ is verification through the
# mobile network operator, such as silent network authentication.
#
# @!attribute phone_verification_method
#
# @return [Symbol, nil]
enum_accessor :phone_verification_method, %i[delivered_code network other]

# Whether the most recent verification of the billing phone number
# succeeded. Do not include this field if no verification was
# attempted.
#
# @return [Boolean, nil]
attr_accessor :phone_was_verification_successful

# The date and time of the most recent verification of the billing phone
# number. The string must be in the RFC 3339 date-time format, e.g.,
# "2012-04-12T23:20:50.52Z".
#
# @see https://datatracker.ietf.org/doc/html/rfc3339
#
# @return [String, nil]
attr_accessor :phone_verification_time

# @param params [Hash] Hash of parameters. Each key/value should
# correspond to one of the available attributes.
def initialize(params = {})
self.phone_verification_method = params[:phone_verification_method]
@phone_was_verification_successful = params[:phone_was_verification_successful]
@phone_verification_time = params[:phone_verification_time]
super
end

private

def validate
super
return if !Minfraud.enable_validation

validate_boolean('phone_was_verification_successful', @phone_was_verification_successful)
validate_rfc3339('phone_verification_time', @phone_verification_time)
end
end
end
end
22 changes: 22 additions & 0 deletions spec/components/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@
base_component.instance_variable_set(:@null, nil)
expect(base_component.to_json).to eq(expected)
end

it 'returns json with boolean values kept as booleans' do
base_component.instance_variable_set(:@yes, true)
base_component.instance_variable_set(:@no, false)
expect(base_component.to_json).to eq(
expected.merge('yes' => true, 'no' => false),
)
end
end
end

describe 'boolean inputs' do
[
[Minfraud::Components::CreditCard, :was_3d_secure_successful],
[Minfraud::Components::Order, :has_gift_message],
[Minfraud::Components::Order, :is_gift],
[Minfraud::Components::Payment, :was_authorized],
[Minfraud::Components::CustomInputs, :boolean_input],
].product([true, false]).each do |(component, field), value|
it "sends #{component}##{field} #{value} as a JSON boolean" do
expect(component.new(field => value).to_json).to eq(field.to_s => value)
end
end
end
end
56 changes: 53 additions & 3 deletions spec/components/billing_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,37 @@
require 'spec_helper'

describe Minfraud::Components::Billing do
describe '#initialize' do
it 'accepts each phone_verification_method value' do
%i[delivered_code network other].each do |method|
expect(described_class.new(phone_verification_method: method).phone_verification_method).to eq(method)
end
end

it 'raises an exception for an invalid phone_verification_method' do
expect do
described_class.new(phone_verification_method: :sms)
end.to raise_exception(Minfraud::NotEnumValueError)
end
end

describe '#to_json' do
[true, false].each do |successful|
it "sends phone_was_verification_successful #{successful} as a JSON boolean" do
billing = described_class.new(
phone_verification_method: 'network',
phone_verification_time: '2026-10-01T14:30:00Z',
phone_was_verification_successful: successful,
)
expect(billing.to_json).to eq(
'phone_verification_method' => 'network',
'phone_verification_time' => '2026-10-01T14:30:00Z',
'phone_was_verification_successful' => successful,
)
end
end
end

describe 'validation' do
before do
Minfraud.configure { |c| c.enable_validation = 1 }
Expand Down Expand Up @@ -32,11 +63,30 @@
end.to raise_exception(Minfraud::InvalidInputError)
end

it 'raises an exception for an invalid phone_was_verification_successful' do
expect do
described_class.new(
phone_was_verification_successful: 'true',
)
end.to raise_exception(Minfraud::InvalidInputError)
end

it 'raises an exception for an invalid phone_verification_time' do
expect do
described_class.new(
phone_verification_time: '2026-10-01 14:30:00',
)
end.to raise_exception(Minfraud::InvalidInputError)
end

it 'does not raise an exception for valid values' do
described_class.new(
region: 'BC',
country: 'CA',
phone_country_code: '1',
region: 'BC',
country: 'CA',
phone_country_code: '1',
phone_verification_method: :delivered_code,
phone_verification_time: '2026-10-01T14:30:00Z',
phone_was_verification_successful: false,
)
end
end
Expand Down
Loading