From d1f8b6acad86682198b42e074962df3aa732ed56 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 28 Apr 2021 20:00:27 -0500 Subject: [PATCH] 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. --- config.dhall.sample | 2 ++ lib/customer.rb | 1 + lib/payment_methods.rb | 4 ++- lib/registration.rb | 50 +++++++++++++++++++++++++++- sgx_jmp.rb | 3 +- test/test_buy_account_credit_form.rb | 1 - test/test_helper.rb | 3 +- test/test_payment_methods.rb | 2 +- test/test_registration.rb | 41 +++++++++++++++++++++-- 9 files changed, 98 insertions(+), 9 deletions(-) diff --git a/config.dhall.sample b/config.dhall.sample index b9a1645..843a466 100644 --- a/config.dhall.sample +++ b/config.dhall.sample @@ -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}" } diff --git a/lib/customer.rb b/lib/customer.rb index a2dc6e0..90eed16 100644 --- a/lib/customer.rb +++ b/lib/customer.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative "./ibr" require_relative "./payment_methods" require_relative "./plan" diff --git a/lib/payment_methods.rb b/lib/payment_methods.rb index 374c698..1297abf 100644 --- a/lib/payment_methods.rb +++ b/lib/payment_methods.rb @@ -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 diff --git a/lib/registration.rb b/lib/registration.rb index 2938716..da1611a 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -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 diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 42df30d..48eb9ac 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -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]) diff --git a/test/test_buy_account_credit_form.rb b/test/test_buy_account_credit_form.rb index da4d6d3..b92d41c 100644 --- a/test/test_buy_account_credit_form.rb +++ b/test/test_buy_account_credit_form.rb @@ -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" }] ), diff --git a/test/test_helper.rb b/test/test_helper.rb index c2da5f7..6a4edb4 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -52,7 +52,8 @@ CONFIG = { merchant_accounts: { USD: "merchant_usd" } - } + }, + credit_card_url: ->(*) { "http://creditcard.example.com" } }.freeze BLATHER = Class.new { diff --git a/test/test_payment_methods.rb b/test/test_payment_methods.rb index 22698b9..573ed35 100644 --- a/test/test_payment_methods.rb +++ b/test/test_payment_methods.rb @@ -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" } ] diff --git a/test/test_registration.rb b/test/test_registration.rb index 41b73a9..a945e82 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -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 -- 2.38.5