upgrades: factor out Stripe integration.

Factor out the Stripe code from the UserUpgrade class. Introduce a new
PaymentTransaction abstract class that represents a payment with some
payment processor, and a PaymentTransaction::Stripe class that
implements transactions with Stripe.

Note that we can't completely eliminate Stripe even though we no longer
accept payments with it because we still need to be able to look up old
payments in Stripe.
This commit is contained in:
evazion
2022-05-06 22:26:52 -05:00
parent 0d4c8baed8
commit 449fd6c49c
9 changed files with 293 additions and 214 deletions

View File

@@ -8,7 +8,7 @@ class WebhooksController < ApplicationController
def receive
case params[:source]
when "stripe"
UserUpgrade.receive_webhook(request)
PaymentTransaction::Stripe.receive_webhook(request)
head 200
when "discord"
json = DiscordSlashCommand.receive_webhook(request)

View File

@@ -0,0 +1,55 @@
# frozen_string_literal: true
# A PaymentTransaction represents a payment in some payment processor's backend API.
#
# @see app/logical/payment_transaction/stripe.rb
class PaymentTransaction
attr_reader :user_upgrade
delegate :recipient, :purchaser, :upgrade_type, :pending?, :stripe_id, to: :user_upgrade
def initialize(user_upgrade)
@user_upgrade = user_upgrade
end
# Initiate a new payment. Normally this sets up a checkout page with the payment processor, which
# we redirect the user to. When the payment succeeds, the user is redirected to a success page and
# the processor sends us a webhook, which we catch to finalize the upgrade. If the payment fails,
# the user is redirected to an error page and the upgrade doesn't go through.
#
# Normally this returns a processor-specific transaction object containing an ID or URL, which is
# used to redirect to the checkout page.
def create!(country: "US", allow_promotion_codes: false)
raise NotImplementedError
end
# Refund a completed payment to the purchaser.
def refund!
raise NotImplementedError
end
# Handle a webhook from the payment processor. Normally the payment processor sends us a webhook
# to notify us of successful payments, which we listen for to complete the upgrade.
def receive_webhook!(request)
raise NotImplementedError
end
# A public link to the payment processor's receipt for the transaction.
def receipt_url
nil
end
# A private link to the transaction in the payment processor's admin area.
def payment_url
nil
end
# The amount of money paid in the transaction.
def amount
nil
end
# The currency used in the transaction.
def currency
nil
end
end

View File

@@ -0,0 +1,190 @@
# frozen_string_literal: true
class PaymentTransaction::Stripe < PaymentTransaction
delegate :stripe_id, to: :user_upgrade
def self.enabled?
Danbooru.config.stripe_secret_key.present? && Danbooru.config.stripe_publishable_key.present? && Danbooru.config.stripe_webhook_secret.present?
end
def create!(country: "US", allow_promotion_codes: false)
checkout_session = ::Stripe::Checkout::Session.create(
mode: "payment",
success_url: Routes.user_upgrade_url(user_upgrade),
cancel_url: Routes.new_user_upgrade_url(user_id: recipient.id),
client_reference_id: "user_upgrade_#{user_upgrade.id}",
customer_email: purchaser.email_address&.address,
payment_method_types: payment_method_types(country),
allow_promotion_codes: allow_promotion_codes.presence,
line_items: [{
price: upgrade_price_id(country),
quantity: 1,
}],
discounts: [{
coupon: promotion_discount_id,
}],
metadata: {
user_upgrade_id: user_upgrade.id,
purchaser_id: purchaser.id,
recipient_id: recipient.id,
purchaser_name: purchaser.name,
recipient_name: recipient.name,
upgrade_type: upgrade_type,
country: country,
is_gift: user_upgrade.is_gift?,
level: user_upgrade.level,
}
)
user_upgrade.update!(stripe_id: checkout_session.id)
checkout_session
end
def refund!(reason = nil)
::Stripe::Refund.create(payment_intent: payment_intent.id, reason: reason)
end
concerning :WebhookMethods do
class_methods do
def receive_webhook(request)
event = build_event(request)
case event.type
when "checkout.session.completed"
checkout_session_completed(event.data.object)
when "charge.dispute.created"
charge_dispute_created(event.data.object)
when "radar.early_fraud_warning.created"
radar_early_fraud_warning_created(event.data.object)
end
end
private def build_event(request)
payload = request.body.read
signature = request.headers["Stripe-Signature"]
::Stripe::Webhook.construct_event(payload, signature, Danbooru.config.stripe_webhook_secret)
end
private def checkout_session_completed(checkout)
user_upgrade = UserUpgrade.find(checkout.metadata.user_upgrade_id)
user_upgrade.process_upgrade!(checkout.payment_status)
end
private def charge_dispute_created(dispute)
Dmail.create_automated(to: User.owner, title: "Stripe Dispute", body: <<~EOS)
Dispute: https://stripe.com/payments/#{dispute.charge}
EOS
end
private def radar_early_fraud_warning_created(fraud_warning)
Dmail.create_automated(to: User.owner, title: "Stripe Early Fraud Warning", body: <<~EOS)
Charge: https://stripe.com/payments/#{fraud_warning.charge}
EOS
end
private def register_webhook
webhook = ::Stripe::WebhookEndpoint.create({
url: Routes.webhook_user_upgrade_url(source: "stripe"),
enabled_events: [
"checkout.session.completed",
"checkout.session.async_payment_failed",
"checkout.session.async_payment_succeeded",
"charge.dispute.created",
"radar.early_fraud_warning.created",
],
})
webhook.secret
end
end
end
def receipt_url
return nil if pending? || stripe_id.nil?
charge.receipt_url
end
def payment_url
return nil if pending? || stripe_id.nil?
"https://dashboard.stripe.com/payments/#{payment_intent.id}"
end
def amount
payment_intent.amount
end
def currency
payment_intent.currency
end
private def checkout_session
return nil if stripe_id.nil?
@checkout_session ||= ::Stripe::Checkout::Session.retrieve(stripe_id)
end
private def payment_intent
return nil if checkout_session.nil?
@payment_intent ||= ::Stripe::PaymentIntent.retrieve(checkout_session.payment_intent)
end
private def charge
payment_intent.charges.data.first
end
private def payment_method_types(country)
case country.to_s.upcase
# Austria, https://stripe.com/docs/payments/bancontact
when "AT"
["card", "eps"]
# Belgium, https://stripe.com/docs/payments/eps
when "BE"
["card", "bancontact"]
# Germany, https://stripe.com/docs/payments/giropay
when "DE"
["card", "giropay"]
# Netherlands, https://stripe.com/docs/payments/ideal
when "NL"
["card", "ideal"]
# Poland, https://stripe.com/docs/payments/p24
when "PL"
["card", "p24"]
else
["card"]
end
end
private def preferred_currency(country)
case country.to_s.upcase
# Austria, Belgium, Germany, Netherlands, Poland
when "AT", "BE", "DE", "NL", "PL"
"eur"
else
"usd"
end
end
private def upgrade_price_id(country)
case [upgrade_type, preferred_currency(country)]
when ["gold", "usd"]
Danbooru.config.stripe_gold_usd_price_id
when ["gold", "eur"]
Danbooru.config.stripe_gold_eur_price_id
when ["platinum", "usd"]
Danbooru.config.stripe_platinum_usd_price_id
when ["platinum", "eur"]
Danbooru.config.stripe_platinum_eur_price_id
when ["gold_to_platinum", "usd"]
Danbooru.config.stripe_gold_to_platinum_usd_price_id
when ["gold_to_platinum", "eur"]
Danbooru.config.stripe_gold_to_platinum_eur_price_id
else
raise NotImplementedError
end
end
private def promotion_discount_id
if Danbooru.config.is_promotion?
Danbooru.config.stripe_promotion_discount_id
end
end
end

View File

@@ -4,6 +4,8 @@ class UserUpgrade < ApplicationRecord
belongs_to :recipient, class_name: "User"
belongs_to :purchaser, class_name: "User"
delegate :payment_url, :receipt_url, to: :transaction
enum upgrade_type: {
gold: 0,
platinum: 10,
@@ -21,19 +23,7 @@ class UserUpgrade < ApplicationRecord
scope :self_upgrade, -> { where("recipient_id = purchaser_id") }
def self.enabled?
stripe_secret_key.present? && stripe_publishable_key.present? && stripe_webhook_secret.present?
end
def self.stripe_secret_key
Danbooru.config.stripe_secret_key
end
def self.stripe_publishable_key
Danbooru.config.stripe_publishable_key
end
def self.stripe_webhook_secret
Danbooru.config.stripe_webhook_secret
Danbooru.config.user_upgrades_enabled?
end
def self.gold_price
@@ -147,74 +137,23 @@ class UserUpgrade < ApplicationRecord
end
end
concerning :StripeMethods do
concerning :TransactionMethods do
def create_checkout!(country: "US", allow_promotion_codes: false)
methods = payment_method_types(country)
currency = preferred_currency(country)
price_id = upgrade_price_id(currency)
checkout = Stripe::Checkout::Session.create(
mode: "payment",
success_url: Routes.user_upgrade_url(self),
cancel_url: Routes.new_user_upgrade_url(user_id: recipient.id),
client_reference_id: "user_upgrade_#{id}",
customer_email: purchaser.email_address&.address,
payment_method_types: methods,
allow_promotion_codes: allow_promotion_codes.presence,
line_items: [{
price: price_id,
quantity: 1,
}],
discounts: [{
coupon: promotion_discount_id,
}],
metadata: {
user_upgrade_id: id,
purchaser_id: purchaser.id,
recipient_id: recipient.id,
purchaser_name: purchaser.name,
recipient_name: recipient.name,
upgrade_type: upgrade_type,
country: country,
is_gift: is_gift?,
level: level,
}
)
update!(stripe_id: checkout.id)
checkout
transaction.create!(country: country, allow_promotion_codes: allow_promotion_codes)
end
def refund!(reason: nil)
with_lock do
return if refunded?
Stripe::Refund.create(payment_intent: payment_intent.id, reason: reason)
transaction.refund!(reason)
recipient.update!(level: previous_level)
update!(status: "refunded")
end
end
def receipt_url
return nil if pending? || stripe_id.nil?
charge.receipt_url
end
def payment_url
return nil if pending? || stripe_id.nil?
"https://dashboard.stripe.com/payments/#{payment_intent.id}"
end
def checkout_session
@checkout_session ||= Stripe::Checkout::Session.retrieve(stripe_id)
end
def payment_intent
@payment_intent ||= Stripe::PaymentIntent.retrieve(checkout_session.payment_intent)
end
def charge
payment_intent.charges.data.first
def transaction
PaymentTransaction::Stripe.new(self)
end
def has_receipt?
@@ -224,115 +163,5 @@ class UserUpgrade < ApplicationRecord
def has_payment?
!pending?
end
def promotion_discount_id
if Danbooru.config.is_promotion?
Danbooru.config.stripe_promotion_discount_id
end
end
def upgrade_price_id(currency)
case [upgrade_type, currency]
when ["gold", "usd"]
Danbooru.config.stripe_gold_usd_price_id
when ["gold", "eur"]
Danbooru.config.stripe_gold_eur_price_id
when ["platinum", "usd"]
Danbooru.config.stripe_platinum_usd_price_id
when ["platinum", "eur"]
Danbooru.config.stripe_platinum_eur_price_id
when ["gold_to_platinum", "usd"]
Danbooru.config.stripe_gold_to_platinum_usd_price_id
when ["gold_to_platinum", "eur"]
Danbooru.config.stripe_gold_to_platinum_eur_price_id
else
raise NotImplementedError
end
end
def payment_method_types(country)
case country.to_s.upcase
# Austria, https://stripe.com/docs/payments/bancontact
when "AT"
["card", "eps"]
# Belgium, https://stripe.com/docs/payments/eps
when "BE"
["card", "bancontact"]
# Germany, https://stripe.com/docs/payments/giropay
when "DE"
["card", "giropay"]
# Netherlands, https://stripe.com/docs/payments/ideal
when "NL"
["card", "ideal"]
# Poland, https://stripe.com/docs/payments/p24
when "PL"
["card", "p24"]
else
["card"]
end
end
def preferred_currency(country)
case country.to_s.upcase
# Austria, Belgium, Germany, Netherlands, Poland
when "AT", "BE", "DE", "NL", "PL"
"eur"
else
"usd"
end
end
class_methods do
def register_webhook
webhook = Stripe::WebhookEndpoint.create({
url: Routes.webhook_user_upgrade_url(source: "stripe"),
enabled_events: [
"checkout.session.completed",
"checkout.session.async_payment_failed",
"checkout.session.async_payment_succeeded",
"charge.dispute.created",
"radar.early_fraud_warning.created",
],
})
webhook.secret
end
def receive_webhook(request)
event = build_event(request)
case event.type
when "checkout.session.completed"
checkout_session_completed(event.data.object)
when "charge.dispute.created"
charge_dispute_created(event.data.object)
when "radar.early_fraud_warning.created"
radar_early_fraud_warning_created(event.data.object)
end
end
def build_event(request)
payload = request.body.read
signature = request.headers["Stripe-Signature"]
Stripe::Webhook.construct_event(payload, signature, stripe_webhook_secret)
end
def checkout_session_completed(checkout)
user_upgrade = UserUpgrade.find(checkout.metadata.user_upgrade_id)
user_upgrade.process_upgrade!(checkout.payment_status)
end
def charge_dispute_created(dispute)
Dmail.create_automated(to: User.owner, title: "Stripe Dispute", body: <<~EOS)
Dispute: https://stripe.com/payments/#{dispute.charge}
EOS
end
def radar_early_fraud_warning_created(fraud_warning)
Dmail.create_automated(to: User.owner, title: "Stripe Early Fraud Warning", body: <<~EOS)
Charge: https://stripe.com/payments/#{fraud_warning.charge}
EOS
end
end
end
end

View File

@@ -1,2 +1,2 @@
var stripe = Stripe("<%= j UserUpgrade.stripe_publishable_key %>");
var stripe = Stripe("<%= j Danbooru.config.stripe_publishable_key %>");
stripe.redirectToCheckout({ sessionId: "<%= j @checkout.id %>" });

View File

@@ -363,6 +363,11 @@ module Danbooru
resolution_mismatch source_larger source_smaller]
end
# Whether the Gold account upgrade page should be enabled.
def user_upgrades_enabled?
true
end
def stripe_secret_key
end

View File

@@ -9,8 +9,8 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
StripeMock.stop
end
def post_webhook(*args, metadata: {}, payment_status: "paid")
skip unless UserUpgrade.enabled?
def post_stripe_webhook(*args, metadata: {}, payment_status: "paid")
skip unless PaymentTransaction::Stripe.enabled?
event = StripeMock.mock_webhook_event(*args, payment_status: payment_status, metadata: metadata)
signature = generate_stripe_signature(event)
headers = { "Stripe-Signature": signature }
@@ -22,7 +22,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
# https://stripe.com/docs/webhooks/signatures
def generate_stripe_signature(event)
time = Time.now
secret = UserUpgrade.stripe_webhook_secret
secret = Danbooru.config.stripe_webhook_secret
signature = Stripe::Webhook::Signature.compute_signature(time, event.to_json, secret)
Stripe::Webhook::Signature.generate_header(time, signature, scheme: Stripe::Webhook::Signature::EXPECTED_SCHEME)
end
@@ -58,7 +58,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "for a payment_intent.created event" do
should "work" do
post_webhook("payment_intent.created")
post_stripe_webhook("payment_intent.created")
assert_response 200
end
@@ -68,7 +68,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "for completed event with an unpaid payment status" do
should "not upgrade the user" do
@user_upgrade = create(:self_gold_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id }, payment_status: "unpaid")
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id }, payment_status: "unpaid")
assert_response 200
assert_equal("processing", @user_upgrade.reload.status)
@@ -80,7 +80,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "to Gold" do
should "upgrade the user" do
@user_upgrade = create(:self_gold_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
assert_response 200
assert_equal("complete", @user_upgrade.reload.status)
@@ -91,7 +91,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "to Platinum" do
should "upgrade the user" do
@user_upgrade = create(:self_platinum_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
assert_response 200
assert_equal("complete", @user_upgrade.reload.status)
@@ -102,7 +102,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "from Gold to Platinum" do
should "upgrade the user" do
@user_upgrade = create(:self_gold_to_platinum_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
assert_response 200
assert_equal("complete", @user_upgrade.reload.status)
@@ -115,7 +115,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "to Gold" do
should "upgrade the user" do
@user_upgrade = create(:gift_gold_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
assert_response 200
assert_equal("complete", @user_upgrade.reload.status)
@@ -126,7 +126,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "to Platinum" do
should "upgrade the user" do
@user_upgrade = create(:gift_platinum_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
assert_response 200
assert_equal("complete", @user_upgrade.reload.status)
@@ -137,7 +137,7 @@ class WebhooksControllerTest < ActionDispatch::IntegrationTest
context "from Gold to Platinum" do
should "upgrade the user" do
@user_upgrade = create(:gift_gold_to_platinum_upgrade)
post_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
post_stripe_webhook("checkout.session.completed", metadata: { user_upgrade_id: @user_upgrade.id })
assert_response 200
assert_equal("complete", @user_upgrade.reload.status)

View File

@@ -3,11 +3,11 @@ StripeMock.webhook_fixture_path = "test/fixtures/stripe-webhooks"
module StripeTestHelper
def mock_stripe!
setup do
StripeMock.start unless UserUpgrade.enabled?
StripeMock.start unless PaymentTransaction::Stripe.enabled?
end
teardown do
StripeMock.stop unless UserUpgrade.enabled?
StripeMock.stop unless PaymentTransaction::Stripe.enabled?
end
end
end

View File

@@ -44,7 +44,7 @@ class UserUpgradeTest < ActiveSupport::TestCase
context "for a gifted upgrade" do
context "to Gold" do
should "prefill the Stripe checkout page with the purchaser's email address" do
skip "Stripe API keys not configured" unless UserUpgrade.enabled?
skip "Stripe API keys not configured" unless PaymentTransaction::Stripe.enabled?
@user = create(:user, email_address: build(:email_address))
@user_upgrade = create(:gift_gold_upgrade, purchaser: @user)
@@ -64,48 +64,48 @@ class UserUpgradeTest < ActiveSupport::TestCase
@user_upgrade = create(:self_gold_upgrade)
@checkout = @user_upgrade.create_checkout!(country: "US")
assert_equal(UserUpgrade.gold_price, @user_upgrade.payment_intent.amount)
assert_equal("usd", @user_upgrade.payment_intent.currency)
assert_equal(UserUpgrade.gold_price, @user_upgrade.transaction.amount)
assert_equal("usd", @user_upgrade.transaction.currency)
end
should "choose the right price in USD for a platinum upgrade" do
@user_upgrade = create(:self_platinum_upgrade)
@checkout = @user_upgrade.create_checkout!(country: "US")
assert_equal(UserUpgrade.platinum_price, @user_upgrade.payment_intent.amount)
assert_equal("usd", @user_upgrade.payment_intent.currency)
assert_equal(UserUpgrade.platinum_price, @user_upgrade.transaction.amount)
assert_equal("usd", @user_upgrade.transaction.currency)
end
should "choose the right price in USD for a gold to platinum upgrade" do
@user_upgrade = create(:self_gold_to_platinum_upgrade)
@checkout = @user_upgrade.create_checkout!(country: "US")
assert_equal(UserUpgrade.gold_to_platinum_price, @user_upgrade.payment_intent.amount)
assert_equal("usd", @user_upgrade.payment_intent.currency)
assert_equal(UserUpgrade.gold_to_platinum_price, @user_upgrade.transaction.amount)
assert_equal("usd", @user_upgrade.transaction.currency)
end
should "choose the right price in EUR for a gold upgrade" do
@user_upgrade = create(:self_gold_upgrade)
@checkout = @user_upgrade.create_checkout!(country: "DE")
assert_equal(0.8 * UserUpgrade.gold_price, @user_upgrade.payment_intent.amount)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal(0.8 * UserUpgrade.gold_price, @user_upgrade.transaction.amount)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right price in EUR for a platinum upgrade" do
@user_upgrade = create(:self_platinum_upgrade)
@checkout = @user_upgrade.create_checkout!(country: "DE")
assert_equal(0.8 * UserUpgrade.platinum_price, @user_upgrade.payment_intent.amount)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal(0.8 * UserUpgrade.platinum_price, @user_upgrade.transaction.amount)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right price in EUR for a gold to platinum upgrade" do
@user_upgrade = create(:self_gold_to_platinum_upgrade)
@checkout = @user_upgrade.create_checkout!(country: "DE")
assert_equal(0.8 * UserUpgrade.gold_to_platinum_price, @user_upgrade.payment_intent.amount)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal(0.8 * UserUpgrade.gold_to_platinum_price, @user_upgrade.transaction.amount)
assert_equal("eur", @user_upgrade.transaction.currency)
end
end
@@ -119,49 +119,49 @@ class UserUpgradeTest < ActiveSupport::TestCase
@checkout = @user_upgrade.create_checkout!(country: "US")
assert_equal(["card"], @checkout.payment_method_types)
assert_equal("usd", @user_upgrade.payment_intent.currency)
assert_equal("usd", @user_upgrade.transaction.currency)
end
should "choose the right payment methods for AT" do
@checkout = @user_upgrade.create_checkout!(country: "AT")
assert_equal(["card", "eps"], @checkout.payment_method_types)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right payment methods for BE" do
@checkout = @user_upgrade.create_checkout!(country: "BE")
assert_equal(["card", "bancontact"], @checkout.payment_method_types)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right payment methods for DE" do
@checkout = @user_upgrade.create_checkout!(country: "DE")
assert_equal(["card", "giropay"], @checkout.payment_method_types)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right payment methods for NL" do
@checkout = @user_upgrade.create_checkout!(country: "NL")
assert_equal(["card", "ideal"], @checkout.payment_method_types)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right payment methods for PL" do
@checkout = @user_upgrade.create_checkout!(country: "PL")
assert_equal(["card", "p24"], @checkout.payment_method_types)
assert_equal("eur", @user_upgrade.payment_intent.currency)
assert_equal("eur", @user_upgrade.transaction.currency)
end
should "choose the right payment methods for an unsupported country" do
@checkout = @user_upgrade.create_checkout!(country: "MX")
assert_equal(["card"], @checkout.payment_method_types)
assert_equal("usd", @user_upgrade.payment_intent.currency)
assert_equal("usd", @user_upgrade.transaction.currency)
end
end
end