~singpolyma/sgx-jmp

d1f8b6acad86682198b42e074962df3aa732ed56 — Stephen Paul Weber 2 years ago c3795a6
New signup: go to web to choose credit card

This step, if chosen, directs the user to the jmp-pay webapp to add a credit
card.  It includes an OOB element for use by user agents that can handle
that (possibly for webview embed, etc) with a note-based fallback as per XEP.
Once the user chooses "next" the code checks if they have actually added a card,
and if so continues to a yet-unimplemented step and if not repeats the
instruction to go to the web app.
M config.dhall.sample => config.dhall.sample +2 -0
@@ 24,4 24,6 @@
		}
	},
	plans = ./plans.dhall
	credit_card_url = \(jid: Text) -> \(customer_id: Text) ->
		"https://pay.jmp.chat/${jid}/credit_cards?customer_id=${customer_id}"
}

M lib/customer.rb => lib/customer.rb +1 -0
@@ 1,5 1,6 @@
# frozen_string_literal: true

require_relative "./ibr"
require_relative "./payment_methods"
require_relative "./plan"


M lib/payment_methods.rb => lib/payment_methods.rb +3 -1
@@ 19,7 19,7 @@ class PaymentMethods
	end

	def default_payment_method
		@methods.index(&:default?).to_s
		@methods.index(&:default?)&.to_s
	end

	def to_options


@@ 43,6 43,8 @@ class PaymentMethods
	end

	class Empty
		def default_payment_method; end

		def to_list_single(*)
			raise "No payment methods available"
		end

M lib/registration.rb => lib/registration.rb +49 -1
@@ 1,5 1,7 @@
# frozen_string_literal: true

require_relative "./oob"

class Registration
	def self.for(iq, customer, web_register_manager)
		raise "TODO" if customer&.active?


@@ 108,7 110,7 @@ class Registration
			when "bitcoin"
				Bitcoin.new(iq, customer, tel)
			when "credit_card"
				raise "TODO"
				CreditCard.for(iq, customer, tel)
			when "code"
				raise "TODO"
			else


@@ 165,5 167,51 @@ class Registration
				end
			end
		end

		class CreditCard
			def self.for(iq, customer, tel)
				customer.payment_methods.then do |payment_methods|
					if payment_methods.default_payment_method
						Activate.new(iq, customer, tel)
					else
						new(iq, customer, tel)
					end
				end
			end

			def initialize(iq, customer, tel)
				@customer = customer
				@tel = tel

				@reply = iq.reply
				@reply.allowed_actions = [:next]
				@reply.note_type = :info
				@reply.note_text = "#{oob.desc}: #{oob.url}"
			end

			attr_reader :reply

			def oob
				oob = OOB.find_or_create(@reply.command)
				oob.url = CONFIG[:credit_card_url].call(
					@reply.to.stripped.to_s,
					@customer.customer_id
				)
				oob.desc = "Add credit card, then return here and choose next"
				oob
			end

			def write
				COMMAND_MANAGER.write(@reply).then do |riq|
					CreditCard.for(riq, @customer, @tel)
				end
			end

			class Activate
				def initialize(_iq, _customer, _tel)
					raise "TODO"
				end
			end
		end
	end
end

M sgx_jmp.rb => sgx_jmp.rb +1 -2
@@ 13,7 13,6 @@ require_relative "lib/buy_account_credit_form"
require_relative "lib/customer"
require_relative "lib/electrum"
require_relative "lib/em"
require_relative "lib/existing_registration"
require_relative "lib/payment_methods"
require_relative "lib/registration"
require_relative "lib/transaction"


@@ 21,7 20,7 @@ require_relative "lib/web_register_manager"

CONFIG =
	Dhall::Coder
	.new(safe: Dhall::Coder::JSON_LIKE + [Symbol])
	.new(safe: Dhall::Coder::JSON_LIKE + [Symbol, Proc])
	.load(ARGV[0], transform_keys: ->(k) { k&.to_sym })

ELECTRUM = Electrum.new(**CONFIG[:electrum])

M test/test_buy_account_credit_form.rb => test/test_buy_account_credit_form.rb +0 -1
@@ 42,7 42,6 @@ class BuyAccountCreditFormTest < Minitest::Test
					type: "list-single",
					var: "payment_method",
					label: "Credit card to pay with",
					value: "",
					required: true,
					options: [{ label: "Test 1234", value: "0" }]
				),

M test/test_helper.rb => test/test_helper.rb +2 -1
@@ 52,7 52,8 @@ CONFIG = {
		merchant_accounts: {
			USD: "merchant_usd"
		}
	}
	},
	credit_card_url: ->(*) { "http://creditcard.example.com" }
}.freeze

BLATHER = Class.new {

M test/test_payment_methods.rb => test/test_payment_methods.rb +1 -1
@@ 52,7 52,7 @@ class PaymentMethodsTest < Minitest::Test
				type: "list-single",
				label: "Credit card to pay with",
				required: true,
				value: "",
				value: nil,
				options: [
					{ value: "0", label: "Test 1234" }
				]

M test/test_registration.rb => test/test_registration.rb +39 -2
@@ 61,6 61,7 @@ class RegistrationTest < Minitest::Test
	end

	class PaymentTest < Minitest::Test
		Customer::BRAINTREE = Minitest::Mock.new
		Registration::Payment::Bitcoin::ELECTRUM = Minitest::Mock.new

		def test_for_bitcoin


@@ 79,15 80,30 @@ class RegistrationTest < Minitest::Test
		end

		def test_for_credit_card
			skip "CreditCard not implemented yet"
			braintree_customer = Minitest::Mock.new
			Customer::BRAINTREE.expect(
				:customer,
				braintree_customer
			)
			braintree_customer.expect(
				:find,
				EMPromise.resolve(OpenStruct.new(payment_methods: [])),
				["test"]
			)
			iq = Blather::Stanza::Iq::Command.new
			iq.from = "test@example.com"
			iq.form.fields = [
				{ var: "activation_method", value: "credit_card" },
				{ var: "plan_name", value: "test_usd" }
			]
			result = Registration::Payment.for(iq, "test", "+15555550000")
			result = Registration::Payment.for(
				iq,
				Customer.new("test"),
				"+15555550000"
			).sync
			assert_kind_of Registration::Payment::CreditCard, result
		end
		em :test_for_credit_card

		def test_for_code
			skip "Code not implemented yet"


@@ 150,5 166,26 @@ class RegistrationTest < Minitest::Test
			end
			em :test_write
		end

		class CreditCardTest < Minitest::Test
			def setup
				iq = Blather::Stanza::Iq::Command.new
				iq.from = "test@example.com"
				@credit_card = Registration::Payment::CreditCard.new(
					iq,
					Customer.new("test"),
					"+15555550000"
				)
			end

			def test_reply
				assert_equal [:execute, :next], @credit_card.reply.allowed_actions
				assert_equal(
					"Add credit card, then return here and choose next: " \
					"http://creditcard.example.com",
					@credit_card.reply.note.content
				)
			end
		end
	end
end