Add btc_addresses to Customer

Stephen Paul Weber created

And use that in registration instead of implementing it inline

Change summary

lib/customer.rb           | 12 ++++++++++++
lib/registration.rb       | 16 ++++++++++------
test/test_customer.rb     | 27 +++++++++++++++++++++++++++
test/test_registration.rb | 16 +++++++++++++---
4 files changed, 62 insertions(+), 9 deletions(-)

Detailed changes

lib/customer.rb 🔗

@@ -114,5 +114,17 @@ class Customer
 		end
 	end
 
+	def btc_addresses
+		REDIS.smembers("jmp_customer_btc_addresses-#{customer_id}")
+	end
+
+	def add_btc_address
+		ELECTRUM.createnewaddress.then do |addr|
+			REDIS.sadd("jmp_customer_btc_addresses-#{customer_id}", addr).then do
+				addr
+			end
+		end
+	end
+
 	protected def_delegator :@plan, :expires_at
 end

lib/registration.rb 🔗

@@ -170,7 +170,6 @@ class Registration
 				@customer = customer
 				@customer_id = customer.customer_id
 				@tel = tel
-				@addr = ELECTRUM.createnewaddress
 			end
 
 			attr_reader :reply, :customer_id, :tel
@@ -189,10 +188,7 @@ class Registration
 					REDIS.mset(
 						"pending_tel_for-#{customer_id}", tel,
 						"pending_plan_for-#{customer_id}", @customer.plan_name
-					),
-					@addr.then do |addr|
-						REDIS.sadd("jmp_customer_btc_addresses-#{customer_id}", addr)
-					end
+					)
 				])
 			end
 
@@ -207,7 +203,7 @@ class Registration
 
 			def write
 				EMPromise.all([
-					@addr,
+					addr,
 					save,
 					BTC_SELL_PRICES.public_send(@customer.currency.to_s.downcase)
 				]).then do |(addr, _, rate)|
@@ -217,6 +213,14 @@ class Registration
 					nil
 				end
 			end
+
+		protected
+
+			def addr
+				@addr ||= @customer.btc_addresses.then do |addrs|
+					addrs.first || @customer.add_btc_address
+				end
+			end
 		end
 
 		class CreditCard

test/test_customer.rb 🔗

@@ -282,4 +282,31 @@ class CustomerTest < Minitest::Test
 		end
 	end
 	em :test_sip_account_error
+
+	def test_btc_addresses
+		Customer::REDIS.expect(
+			:smembers,
+			EMPromise.resolve(["testaddr"]),
+			["jmp_customer_btc_addresses-test"]
+		)
+		assert_equal ["testaddr"], Customer.new("test").btc_addresses.sync
+		assert_mock Customer::REDIS
+	end
+	em :test_btc_addresses
+
+	def test_add_btc_address
+		Customer::ELECTRUM.expect(
+			:createnewaddress,
+			EMPromise.resolve("testaddr")
+		)
+		Customer::REDIS.expect(
+			:sadd,
+			EMPromise.resolve(nil),
+			["jmp_customer_btc_addresses-test", "testaddr"]
+		)
+		assert_equal "testaddr", Customer.new("test").add_btc_address.sync
+		assert_mock Customer::ELECTRUM
+		assert_mock Customer::REDIS
+	end
+	em :test_add_btc_address
 end

test/test_registration.rb 🔗

@@ -161,13 +161,13 @@ class RegistrationTest < Minitest::Test
 		end
 
 		class BitcoinTest < Minitest::Test
-			Registration::Payment::Bitcoin::ELECTRUM = Minitest::Mock.new
-			Registration::Payment::Bitcoin::REDIS = Minitest::Mock.new
 			Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new
 			Registration::Payment::Bitcoin::BLATHER = Minitest::Mock.new
+			Customer::REDIS = Minitest::Mock.new
+			Customer::ELECTRUM = Minitest::Mock.new
 
 			def setup
-				Registration::Payment::Bitcoin::ELECTRUM.expect(
+				Customer::ELECTRUM.expect(
 					:createnewaddress,
 					EMPromise.resolve("testaddr")
 				)
@@ -180,6 +180,16 @@ class RegistrationTest < Minitest::Test
 			end
 
 			def test_write
+				Customer::REDIS.expect(
+					:smembers,
+					EMPromise.resolve([]),
+					["jmp_customer_btc_addresses-test"]
+				)
+				Customer::REDIS.expect(
+					:sadd,
+					EMPromise.resolve(1),
+					["jmp_customer_btc_addresses-test", "testaddr"]
+				)
 				reply_text = <<~NOTE
 					Activate your account by sending at least 1.000000 BTC to
 					testaddr