From 2e272b4b51e788b61de2f8aee625d8bb564139b0 Mon Sep 17 00:00:00 2001 From: Phillip Davis Date: Sat, 7 Feb 2026 08:37:47 -0500 Subject: [PATCH] fix: display correct price for data-only to that end: make `SIMKind` easier to hold by making internals, as well as the raw CONFIG[:sims] entry, protected --- lib/registration.rb | 17 +++++++---------- lib/sim_kind.rb | 36 ++++++++++++++++++++++++++++++------ test/test_registration.rb | 6 +++--- test/test_sim_kind.rb | 24 +++++++++++++----------- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/lib/registration.rb b/lib/registration.rb index 4ff149483b2b819a9607252dbc9313e4fae02b11..fd37f5f2c7aa816ed93d8b950b79211456947e9d 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -46,17 +46,17 @@ class Registration product: @sim_kind, instructions: instructions, currency_required: !@customer.currency, - title: "Pay for #{@sim_kind.klass.label}" + title: "Pay for #{@sim_kind.label}" ) }.then(&method(:parse)).then(&:write) end def instructions - cfg = @sim_kind.cfg(@customer.currency) - return nil unless cfg + price = @sim_kind.price(@customer) + return nil unless price <<~I - To activate your data SIM, you need to deposit $#{'%.2f' % (cfg[:price] / 100.0)} to your balance. + To activate your data SIM, you need to deposit $#{'%.2f' % price} to your balance. (If you'd like to pay in another cryptocurrency, currently we recommend using a service like simpleswap.io, morphtoken.com, changenow.io, or godex.io.) I end @@ -71,7 +71,7 @@ class Registration def process_payment(iq) Payment.for( iq, @customer, @sim_kind, - price: @sim_kind.cfg(@customer.currency)[:price], + price: @sim_kind.price(@customer), maybe_bill: Registration::Payment::JustCharge ).write.then { reload_customer(@customer) }.then { |customer| DataOnly.for(customer, @sim_kind) @@ -81,7 +81,7 @@ class Registration class DataOnly def self.for(customer, sim_kind) - price = sim_kind.price_dollars(customer.currency) + price = sim_kind.price(customer) unless price && customer.balance >= price return PayForSim.new(customer, sim_kind) end @@ -95,10 +95,7 @@ class Registration end def write - @sim_kind.klass.for( - @customer, - **@sim_kind.cfg(@customer.currency) - ).then { |order| + @sim_kind.get_processor(@customer).then { |order| # NOTE: cheogram will swallow any stanza # with type `completed` # `can_complete: false` is needed to prevent customer diff --git a/lib/sim_kind.rb b/lib/sim_kind.rb index 232656e4539aa41ee8c324c7523ec05f4dac0b04..c65f02c784a503621fa062148f32a6a7014baad8 100644 --- a/lib/sim_kind.rb +++ b/lib/sim_kind.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class SIMKind - attr_reader :klass - def initialize(variant) @klass = case variant @@ -18,14 +16,40 @@ class SIMKind new(form.field("sim_kind")&.value) end - def cfg(currency) - CONFIG.dig(:sims, @variant.to_sym, currency) + # @param [Customer] customer + # @raise [ArgumentError] If matching `CONFIG[:sims]` + # key not found for `@variant` and customer + def get_processor(customer) + cfg = cfg(customer.currency) + raise ArgumentError, "Invalid config" unless cfg + + @klass.new( + customer, + **cfg + ) + end + + # @return [String] The result of either + # SIMOrder.label or SIMOrder::ESIM.label + def label + @klass.label end - def price_dollars(currency) - cfg = cfg(currency) + # @param [Customer] customer + # @return [Float, NilClass] Returns nil if `customer.currency` + # is nil, or if @variant is malformed. + def price(customer) + cfg = cfg(customer.currency) return nil unless cfg cfg[:price] / 100.to_d end + +protected + + # @param [Symbol] currency One of the currencies from + # CONFIG[:plans] entries + def cfg(currency) + CONFIG.dig(:sims, @variant.to_sym, currency) + end end diff --git a/test/test_registration.rb b/test/test_registration.rb index 94437ff468321df8ac248b0f4aa61d6e9d90ef39..264e1ddfdce3ce4713411812b425426a5e969831 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -2540,7 +2540,7 @@ class RegistrationTest < Minitest::Test :for, ejector_mock ) do |*, price:, maybe_bill:| - assert_equal 500, price + assert_in_epsilon 5, price, 0.001 assert_equal( Registration::Payment::JustCharge, maybe_bill @@ -2589,7 +2589,7 @@ class RegistrationTest < Minitest::Test :for, ejector_mock ) do |*, price:, maybe_bill:| - assert_equal 500, price + assert_in_epsilon 5, price, 0.001 assert_equal( Registration::Payment::JustCharge, maybe_bill @@ -2626,7 +2626,7 @@ class RegistrationTest < Minitest::Test assert_equal @customer, customer assert_equal @sim_kind, sim_kind assert_equal Registration::Payment::JustCharge, maybe_bill - assert_equal 500, price + assert_in_epsilon 5, price, 0.001 end exe.customer_repo.expect( :find, diff --git a/test/test_sim_kind.rb b/test/test_sim_kind.rb index 8aaba041c516a5006a6e2bd4e59d6bbe6c0a38fa..a121bae47c263048f4bb4af7845594da6c5ed52e 100644 --- a/test/test_sim_kind.rb +++ b/test/test_sim_kind.rb @@ -25,53 +25,55 @@ class SIMKindTest < Minitest::Test @missing_form = Blather::Stanza::Iq::Command.new.tap { |iq| iq.form.fields = [] } + + @cust = customer(plan_name: "test_usd") end def test_initialize_with_sim kind = SIMKind.new("sim") - assert_equal SIMOrder, kind.klass + assert_instance_of SIMOrder, kind.get_processor(@cust) end def test_initialize_with_esim kind = SIMKind.new("esim") - assert_equal SIMOrder::ESIM, kind.klass + assert_instance_of SIMOrder::ESIM, kind.get_processor(@cust) end def test_initialize_with_invalid_variant kind = SIMKind.new("invalid") - assert_nil kind.klass + assert_raises(ArgumentError) { kind.get_processor(@cust) } end def test_initialize_with_nil kind = SIMKind.new(nil) - assert_nil kind.klass + assert_raises(NoMethodError) { kind.get_processor(@cust) } end def test_from_form_with_sim kind = SIMKind.from_form(@sim_form.form) - assert_equal SIMOrder, kind.klass + assert_instance_of SIMOrder, kind.get_processor(@cust) end def test_from_form_with_esim kind = SIMKind.from_form(@esim_form.form) - assert_equal SIMOrder::ESIM, kind.klass + assert_instance_of SIMOrder::ESIM, kind.get_processor(@cust) end - def test_cfg_returns_nil_when_customer_currency_nil + def test_price_returns_nil_when_customer_currency_nil kind = SIMKind.new("sim") cust = customer(currency: nil) - assert_nil kind.cfg(cust.currency) + assert_nil kind.price(cust) end - def test_cfg_returns_nil_when_config_missing_variant + def test_price_returns_nil_when_config_missing_variant kind = SIMKind.new("invalid") cust = customer(currency: :USD) - assert_nil kind.cfg(cust.currency) + assert_nil kind.price(cust) end def test_cfg_returns_nil_when_config_missing_currency kind = SIMKind.new("sim") cust = customer(currency: :EUR) - assert_nil kind.cfg(cust.currency) + assert_nil kind.price(cust) end end