Auto top up enough to get to auto_top_up_amount

Stephen Paul Weber created

If auto top up amount would not get us to $5 (because of very negative balance),
we don't want to loop multiple auto top ups, so instead just do one larger one
to get to auto_top_up_amount

Change summary

lib/customer.rb          | 11 ++++++++++-
test/test_low_balance.rb | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 1 deletion(-)

Detailed changes

lib/customer.rb 🔗

@@ -24,7 +24,7 @@ class Customer
 	def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan,
 	               :currency, :merchant_account, :plan_name, :minute_limit,
 	               :message_limit, :monthly_overage_limit, :activation_date,
-	               :expires_at, :monthly_price, :save_plan!, :auto_top_up_amount
+	               :expires_at, :monthly_price, :save_plan!
 	def_delegators :@sgx, :deregister!, :register!, :registered?, :set_ogm_url,
 	               :fwd, :transcription_enabled
 	def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage
@@ -84,6 +84,15 @@ class Customer
 		EMPromise.resolve(self)
 	end
 
+	def auto_top_up_amount
+		if @plan.auto_top_up_amount.positive? &&
+		   balance < -@plan.auto_top_up_amount + 5
+			-balance + @plan.auto_top_up_amount
+		else
+			@plan.auto_top_up_amount
+		end
+	end
+
 	def unused_invites
 		InvitesRepo.new(DB).unused_invites(customer_id)
 	end

test/test_low_balance.rb 🔗

@@ -138,6 +138,44 @@ class LowBalanceTest < Minitest::Test
 		end
 		em :test_notify!
 
+		def test_very_low_balance_notify!
+			customer = Minitest::Mock.new(customer(
+				balance: -100,
+				auto_top_up_amount: 15
+			))
+			auto_top_up = LowBalance::AutoTopUp.new(customer)
+
+			tx = PromiseMock.new
+			tx.expect(:insert, EMPromise.resolve(nil))
+			LowBalance::AutoTopUp::Transaction.expect(
+				:sale,
+				tx,
+				[customer, { amount: 110 }]
+			)
+			auto_top_up.notify!
+			assert_mock tx
+		end
+		em :test_very_low_balance_notify!
+
+		def test_border_low_balance_notify!
+			customer = Minitest::Mock.new(customer(
+				balance: -11,
+				auto_top_up_amount: 15
+			))
+			auto_top_up = LowBalance::AutoTopUp.new(customer)
+
+			tx = PromiseMock.new
+			tx.expect(:insert, EMPromise.resolve(nil))
+			LowBalance::AutoTopUp::Transaction.expect(
+				:sale,
+				tx,
+				[customer, { amount: 21 }]
+			)
+			auto_top_up.notify!
+			assert_mock tx
+		end
+		em :test_border_low_balance_notify!
+
 		def test_decline_notify!
 			@customer.expect(
 				:stanza_to,