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}"
}
Stephen Paul Weber created
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(-)
@@ -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}"
}
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+require_relative "./ibr"
require_relative "./payment_methods"
require_relative "./plan"
@@ -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
@@ -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
@@ -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])
@@ -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" }]
),
@@ -52,7 +52,8 @@ CONFIG = {
merchant_accounts: {
USD: "merchant_usd"
}
- }
+ },
+ credit_card_url: ->(*) { "http://creditcard.example.com" }
}.freeze
BLATHER = Class.new {
@@ -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" }
]
@@ -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