diff --git a/config-schema.dhall b/config-schema.dhall index 805b538cc41171a503f343dc18d6c18a2362edfb..b6086665413504b4b65634cdc877a3951662a234 100644 --- a/config-schema.dhall +++ b/config-schema.dhall @@ -81,18 +81,10 @@ } , simpleswap_api_key : Text , sims : - { CAD : { per_gb : Natural } - , USD : { per_gb : Natural } - , esim : - List - { mapKey : < CAD | USD > - , mapValue : { plan : Text, price : Natural } - } - , sim : - List - { mapKey : < CAD | USD > - , mapValue : { plan : Text, price : Natural } - } + { annual : { CAD : Natural, USD : Natural } + , esim : { CAD : Natural, USD : Natural } + , per_gb : { CAD : Natural, USD : Natural } + , sim : { CAD : Natural, USD : Natural } } , sip : { app : Text, realm : Text } , sip_host : Text diff --git a/config.dhall.sample b/config.dhall.sample index 08b23cfdfb811a64c42c7d9f83ecdc4b6f50e88a..3d7a39b0fa3ebc95ed0c07eb21cb7d484dacfba0 100644 --- a/config.dhall.sample +++ b/config.dhall.sample @@ -67,14 +67,10 @@ in } ], sims = { - CAD = { per_gb = 100 }, - USD = { per_gb = 100 }, - sim = [ - { mapKey = .CAD, mapValue = { price = 1, plan = "$1 / GB + $1 / year" } } - ], - esim = [ - { mapKey = .CAD, mapValue = { price = 1, plan = "$1 / GB + $1 / year" } } - ] + annual = { CAD = 100, USD = 100 }, + esim = { CAD = 1, USD = 1 }, + per_gb = { CAD = 100, USD = 100 }, + sim = { CAD = 1, USD = 1 } }, electrum = { rpc_uri = "", diff --git a/lib/sim_kind.rb b/lib/sim_kind.rb index 553552ffd8c5fc6dc4e00b2c4afd32036f6eece4..c232bd1397917efe595c23af895c8508016657ca 100644 --- a/lib/sim_kind.rb +++ b/lib/sim_kind.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require_relative "sim_pricing" + class SIMKind def initialize(variant) @klass = @@ -19,13 +21,16 @@ class SIMKind end # @param [Customer] customer - # @raise [ArgumentError] If matching `CONFIG[:sims]` - # key not found for `@variant` and customer + # @raise [ArgumentError] If matching SIM price is missing from `CONFIG[:sims]` def get_processor(customer) - cfg = cfg(customer.currency) - raise ArgumentError, "Invalid config" unless cfg - - @klass.for(customer, **cfg) + price = price_cents(customer.currency) + raise ArgumentError, "Invalid config" unless price + + @klass.for( + customer, + price: price, + plan: SIMPricing.plan_label(customer.currency, CONFIG) + ) end # @return [String] The result of either @@ -38,15 +43,15 @@ class SIMKind # @return [Float, NilClass] Returns nil if `customer.currency` # is nil, or if @variant is malformed. def price(customer) - cfg = cfg(customer.currency || :USD) - cfg[:price] / 100.to_d + price = price_cents(customer.currency || :USD) + price / 100.to_d if price end protected # @param [Symbol] currency One of the currencies from # CONFIG[:plans] entries - def cfg(currency) + def price_cents(currency) CONFIG.dig(:sims, @variant.to_sym, currency) end end diff --git a/lib/sim_pricing.rb b/lib/sim_pricing.rb index cc4005d778b60349cdb37bae390fd3a66cbb184b..9374187c26027be9bddbfbbbc7186310b12abcd2 100644 --- a/lib/sim_pricing.rb +++ b/lib/sim_pricing.rb @@ -5,8 +5,34 @@ require "bigdecimal" module SIMPricing # SIM refill billing records currency amounts in transactions. Use BigDecimal # because the configured per-GB price is stored in cents. + def self.per_gb_price(currency, config) + configured_price_dollars(:per_gb, currency, config) + end + + def self.annual_price(currency, config) + configured_price_dollars(:annual, currency, config) + end + + def self.configured_price_dollars(price_type, currency, config) + BigDecimal( + config.fetch(:sims).fetch(price_type).fetch(currency) + ) / 100 + end + private_class_method :configured_price_dollars + def self.five_gb_refill_price(currency, config) - (BigDecimal(config[:sims][currency][:per_gb]) / 100) * 5 + per_gb_price(currency, config) * 5 + end + + def self.per_gb_label(currency, config) + "$%.2f / GB" % per_gb_price(currency, config) + end + + def self.plan_label(currency, config) + "$%.2f / GB + $%.2f / year" % [ + per_gb_price(currency, config), + annual_price(currency, config) + ] end # CustomerRepo#put_monthly_limits stores limits with to_i, so render monthly diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 84cdc9f835ee67c5c26c772899a8818e5607382a..0d0c056cb1095fea3ab69908dfd55e46d5925fac 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -783,11 +783,9 @@ Command.new( }.then { |iq| case iq.form.field("http://jabber.org/protocol/commands#actions")&.value when "order-sim" - SIMOrder.for(customer, **CONFIG.dig(:sims, :sim, customer.currency)) + SIMKind.new("sim").get_processor(customer) when "order-esim" - SIMOrder::ESIM.for( - customer, **CONFIG.dig(:sims, :esim, customer.currency) - ) + SIMKind.new("esim").get_processor(customer) when "edit-nicknames" EditSimNicknames.new(customer, sims) else diff --git a/test/test_helper.rb b/test/test_helper.rb index f2b7c34f7acbacb87e9d32331d5d0d78a7742cf0..cca7599c3535f814c1463e8ac30636981b9f4df9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -161,15 +161,21 @@ CONFIG = { electrum_notify_url: ->(*) { "http://notify.example.com" }, admin_notify: "admin_room@example.com", sims: { - USD: { per_gb: 100 }, - CAD: { per_gb: 120 }, + annual: { + USD: 100, + CAD: 120 + }, + per_gb: { + USD: 100, + CAD: 120 + }, sim: { - USD: { price: 500, plan: "1GB" }, - CAD: { price: 600, plan: "1GB" } + USD: 500, + CAD: 600 }, esim: { - USD: { price: 300, plan: "500MB" }, - CAD: { price: 400, plan: "500MB" } + USD: 300, + CAD: 400 } }, keep_area_codes: [ diff --git a/test/test_monthly_data_limit.rb b/test/test_monthly_data_limit.rb index 354e0001b9530a7b0446fad3aa14ceb08605fc60..7d4ac2f96276565663d8e0db09c15781add7f3a6 100644 --- a/test/test_monthly_data_limit.rb +++ b/test/test_monthly_data_limit.rb @@ -63,13 +63,26 @@ class MonthlyDataLimitTest < Minitest::Test assert_equal 60, limits[:max] end + def test_formats_refill_price_for_display + assert_equal "$1.20 / GB", SIMPricing.per_gb_label(:CAD, CONFIG) + end + + def test_formats_plan_price_for_display + assert_equal( + "$1.20 / GB + $1.20 / year", + SIMPricing.plan_label(:CAD, CONFIG) + ) + end + def test_does_not_need_sim_pricing_without_sims assert_equal({}, MonthlyDataLimit.for_sims([], :CAD, CONFIG)) end def test_uses_integer_dollars_for_fractional_refill_price config = CONFIG.merge( - sims: CONFIG[:sims].merge(CAD: { per_gb: 125 }) + sims: CONFIG[:sims].merge( + per_gb: CONFIG[:sims][:per_gb].merge(CAD: 125) + ) ) limits = MonthlyDataLimit.for_currency(:CAD, config)