spree_stripe 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.md +14 -0
- data/README.md +132 -0
- data/Rakefile +21 -0
- data/app/assets/config/spree_stripe_manifest.js +3 -0
- data/app/controllers/spree/api/v2/storefront/stripe/base_controller.rb +21 -0
- data/app/controllers/spree/api/v2/storefront/stripe/payment_intents_controller.rb +61 -0
- data/app/controllers/spree/api/v2/storefront/stripe/setup_intents_controller.rb +19 -0
- data/app/controllers/spree_stripe/apple_pay_domain_verification_controller.rb +11 -0
- data/app/controllers/spree_stripe/payment_intents_controller.rb +61 -0
- data/app/controllers/spree_stripe/store_controller_decorator.rb +9 -0
- data/app/controllers/stripe_event/webhook_controller_decorator.rb +17 -0
- data/app/helpers/spree_stripe/base_helper.rb +13 -0
- data/app/javascript/spree_stripe/application.js +18 -0
- data/app/javascript/spree_stripe/controllers/stripe_button_controller.js +452 -0
- data/app/javascript/spree_stripe/controllers/stripe_controller.js +311 -0
- data/app/jobs/spree_stripe/base_job.rb +5 -0
- data/app/jobs/spree_stripe/complete_order_job.rb +8 -0
- data/app/jobs/spree_stripe/create_webhook_endpoint_job.rb +7 -0
- data/app/jobs/spree_stripe/register_domain_job.rb +20 -0
- data/app/models/spree_stripe/base.rb +6 -0
- data/app/models/spree_stripe/credit_card_decorator.rb +13 -0
- data/app/models/spree_stripe/custom_domain_decorator.rb +18 -0
- data/app/models/spree_stripe/gateway.rb +366 -0
- data/app/models/spree_stripe/order_decorator.rb +19 -0
- data/app/models/spree_stripe/payment_decorator.rb +46 -0
- data/app/models/spree_stripe/payment_intent.rb +66 -0
- data/app/models/spree_stripe/payment_method_decorator.rb +18 -0
- data/app/models/spree_stripe/payment_methods_webhook_key.rb +8 -0
- data/app/models/spree_stripe/payment_source_decorator.rb +9 -0
- data/app/models/spree_stripe/payment_sources/affirm.rb +9 -0
- data/app/models/spree_stripe/payment_sources/after_pay.rb +13 -0
- data/app/models/spree_stripe/payment_sources/alipay.rb +9 -0
- data/app/models/spree_stripe/payment_sources/ideal.rb +15 -0
- data/app/models/spree_stripe/payment_sources/klarna.rb +9 -0
- data/app/models/spree_stripe/payment_sources/link.rb +13 -0
- data/app/models/spree_stripe/payment_sources/przelewy24.rb +11 -0
- data/app/models/spree_stripe/payment_sources/sepa_debit.rb +13 -0
- data/app/models/spree_stripe/store_decorator.rb +24 -0
- data/app/models/spree_stripe/webhook_key.rb +14 -0
- data/app/presenters/spree_stripe/customer_presenter.rb +35 -0
- data/app/presenters/spree_stripe/payment_intent_presenter.rb +103 -0
- data/app/serializers/spree/api/v2/platform/affirm_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/after_pay_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/alipay_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/ideal_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/klarna_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/link_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/przelewy24_serializer.rb +9 -0
- data/app/serializers/spree/api/v2/platform/sepa_debit_serializer.rb +9 -0
- data/app/serializers/spree/v2/storefront/affirm_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/after_pay_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/alipay_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/ideal_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/klarna_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/link_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/payment_intent_serializer.rb +11 -0
- data/app/serializers/spree/v2/storefront/przelewy24_serializer.rb +7 -0
- data/app/serializers/spree/v2/storefront/sepa_debit_serializer.rb +7 -0
- data/app/services/spree_stripe/complete_order.rb +99 -0
- data/app/services/spree_stripe/create_gateway_webhooks.rb +55 -0
- data/app/services/spree_stripe/create_payment.rb +43 -0
- data/app/services/spree_stripe/create_payment_intent.rb +40 -0
- data/app/services/spree_stripe/create_setup_intent.rb +20 -0
- data/app/services/spree_stripe/create_source.rb +87 -0
- data/app/services/spree_stripe/register_domain.rb +22 -0
- data/app/services/spree_stripe/webhook_handlers/payment_intent_payment_failed.rb +18 -0
- data/app/services/spree_stripe/webhook_handlers/payment_intent_succeeded.rb +13 -0
- data/app/services/spree_stripe/webhook_handlers/setup_intent_succeeded.rb +34 -0
- data/app/views/spree/admin/payment_methods/configuration_guides/_spree_stripe.html.erb +0 -0
- data/app/views/spree/admin/payment_methods/custom_form_fields/_spree_stripe.html.erb +47 -0
- data/app/views/spree/admin/payment_methods/descriptions/_spree_stripe.html.erb +15 -0
- data/app/views/spree/checkout/payment/_spree_stripe.html.erb +63 -0
- data/app/views/spree_stripe/_head.html.erb +2 -0
- data/app/views/spree_stripe/_quick_checkout.html.erb +34 -0
- data/config/importmap.rb +8 -0
- data/config/initializers/spree.rb +8 -0
- data/config/initializers/stripe.rb +14 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +24 -0
- data/db/migrate/20250310152812_setup_spree_stripe_models.rb +41 -0
- data/lib/generators/spree_stripe/install/install_generator.rb +20 -0
- data/lib/spree_stripe/configuration.rb +5 -0
- data/lib/spree_stripe/engine.rb +36 -0
- data/lib/spree_stripe/factories.rb +3 -0
- data/lib/spree_stripe/testing_support/factories/after_pay_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/alipay_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/gateway_factory.rb +23 -0
- data/lib/spree_stripe/testing_support/factories/ideal_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/klarna_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/link_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/payment_intent_factory.rb +24 -0
- data/lib/spree_stripe/testing_support/factories/payment_source_factory.rb +8 -0
- data/lib/spree_stripe/testing_support/factories/przelewy24_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/sepa_debit_payment_source_factory.rb +6 -0
- data/lib/spree_stripe/testing_support/factories/webhook_key_factory.rb +23 -0
- data/lib/spree_stripe/version.rb +7 -0
- data/lib/spree_stripe.rb +14 -0
- data/vendor/javascript/@stripe--stripe-js--dist--pure.esm.js.js +4 -0
- metadata +295 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CustomerPresenter
|
3
|
+
def initialize(address: nil, email: nil, name: nil)
|
4
|
+
@email = email
|
5
|
+
@name = name
|
6
|
+
@address = address
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
hash = {}
|
11
|
+
hash[:address] = address_payload if address.present?
|
12
|
+
hash[:email] = email if email.present?
|
13
|
+
hash[:name] = name if name.present?
|
14
|
+
|
15
|
+
hash
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :email, :name, :address
|
21
|
+
|
22
|
+
def address_payload
|
23
|
+
return {} unless address
|
24
|
+
|
25
|
+
{
|
26
|
+
city: address.city,
|
27
|
+
line1: address.address1,
|
28
|
+
line2: address.address2,
|
29
|
+
postal_code: address.zipcode,
|
30
|
+
country: address.country_name,
|
31
|
+
state: address.state_name
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class PaymentIntentPresenter
|
3
|
+
SETUP_FUTURE_USAGE = 'off_session'
|
4
|
+
STATEMENT_DESCRIPTOR_MAX_CHARACTERS = 22
|
5
|
+
|
6
|
+
def initialize(amount:, order:, customer: nil, payment_method_id: nil, off_session: false)
|
7
|
+
@amount = amount
|
8
|
+
@order = order
|
9
|
+
@customer = customer
|
10
|
+
@ship_address = order.ship_address
|
11
|
+
@payment_method_id = payment_method_id
|
12
|
+
@off_session = off_session
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
payload = if payment_method_id.present?
|
17
|
+
saved_payment_method_payload
|
18
|
+
else
|
19
|
+
new_payment_method_payload
|
20
|
+
end
|
21
|
+
|
22
|
+
payload = payload.deep_merge(basic_payload)
|
23
|
+
|
24
|
+
return payload unless ship_address
|
25
|
+
|
26
|
+
# we don't validate address1, but it's required by Stripe
|
27
|
+
if ship_address.invalid? || ship_address.address1.blank?
|
28
|
+
ship_address.errors.clear
|
29
|
+
return payload
|
30
|
+
end
|
31
|
+
|
32
|
+
payload.merge(ship_address_payload)
|
33
|
+
end
|
34
|
+
|
35
|
+
def ship_address_payload
|
36
|
+
{
|
37
|
+
shipping: {
|
38
|
+
address: {
|
39
|
+
city: ship_address.city,
|
40
|
+
country: ship_address.country_iso,
|
41
|
+
line1: ship_address.address1,
|
42
|
+
line2: ship_address.address2,
|
43
|
+
postal_code: ship_address.zipcode,
|
44
|
+
state: ship_address.state_abbr
|
45
|
+
},
|
46
|
+
name: ship_address.full_name
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def basic_payload
|
54
|
+
{
|
55
|
+
amount: amount,
|
56
|
+
customer: customer,
|
57
|
+
currency: order.currency,
|
58
|
+
statement_descriptor_suffix: statement_descriptor,
|
59
|
+
automatic_payment_methods: {
|
60
|
+
enabled: true
|
61
|
+
},
|
62
|
+
transfer_group: order.number,
|
63
|
+
metadata: {
|
64
|
+
spree_order_id: order.id
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def statement_descriptor
|
70
|
+
billing_name = order.store.billing_name
|
71
|
+
descriptor = "#{order.number} #{billing_name}".strip
|
72
|
+
|
73
|
+
if descriptor.length > STATEMENT_DESCRIPTOR_MAX_CHARACTERS
|
74
|
+
additional_char_count = descriptor.length - STATEMENT_DESCRIPTOR_MAX_CHARACTERS + 1
|
75
|
+
short_billing_name = billing_name[0...-additional_char_count]
|
76
|
+
|
77
|
+
descriptor = "#{order.number} #{short_billing_name}".strip
|
78
|
+
end
|
79
|
+
|
80
|
+
descriptor
|
81
|
+
end
|
82
|
+
|
83
|
+
def new_payment_method_payload
|
84
|
+
{
|
85
|
+
payment_method_options: {
|
86
|
+
card: {
|
87
|
+
setup_future_usage: SETUP_FUTURE_USAGE
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def saved_payment_method_payload
|
94
|
+
{
|
95
|
+
payment_method: payment_method_id,
|
96
|
+
off_session: @off_session,
|
97
|
+
confirm: @off_session # confirm is required for off_session payments
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
attr_reader :order, :amount, :customer, :ship_address, :payment_method_id
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Spree
|
2
|
+
module V2
|
3
|
+
module Storefront
|
4
|
+
class PaymentIntentSerializer < BaseSerializer
|
5
|
+
set_type :payment_intent
|
6
|
+
|
7
|
+
attributes :stripe_id, :client_secret, :ephemeral_key_secret, :customer_id, :amount, :stripe_payment_method_id
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CompleteOrder
|
3
|
+
def initialize(payment_intent:)
|
4
|
+
@payment_intent = payment_intent
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :payment_intent
|
8
|
+
|
9
|
+
def call
|
10
|
+
order = payment_intent.order
|
11
|
+
|
12
|
+
return order if order.completed? || order.canceled?
|
13
|
+
|
14
|
+
charge = payment_intent.stripe_charge
|
15
|
+
|
16
|
+
order.with_lock do
|
17
|
+
# needed for quick checkout orders
|
18
|
+
order = add_customer_information(order, charge)
|
19
|
+
|
20
|
+
# find or create the payment
|
21
|
+
payment = payment_intent.find_or_create_payment!
|
22
|
+
|
23
|
+
# process the payment
|
24
|
+
payment.process!
|
25
|
+
|
26
|
+
# complete the order
|
27
|
+
Spree::Dependencies.checkout_complete_service.constantize.call(order: order)
|
28
|
+
end
|
29
|
+
|
30
|
+
order.reload
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# we need to perform this for quick checkout orders which do not have these fields filled
|
36
|
+
def add_customer_information(order, charge)
|
37
|
+
billing_details = charge.billing_details
|
38
|
+
address = billing_details.address
|
39
|
+
|
40
|
+
order.email ||= billing_details.email
|
41
|
+
order.save! if order.email_changed?
|
42
|
+
|
43
|
+
# we don't need to perform this if we already have the billing address filled
|
44
|
+
return order if order.bill_address.present? && order.bill_address.valid?
|
45
|
+
|
46
|
+
# determine country...
|
47
|
+
country_iso = address.country
|
48
|
+
country = Spree::Country.find_by(iso: country_iso) || Spree::Country.default
|
49
|
+
|
50
|
+
# assign new address if we don't have one
|
51
|
+
order.bill_address ||= Spree::Address.new(country: country, user: order.user)
|
52
|
+
|
53
|
+
# assign attributes
|
54
|
+
order.bill_address.quick_checkout = true # skipping some validations
|
55
|
+
|
56
|
+
# sometimes google pay doesn't provide name (geez)
|
57
|
+
first_name = billing_details.name&.split(' ')&.first || order.ship_address&.first_name || order.user&.first_name
|
58
|
+
last_name = billing_details.name&.split(' ')&.last || order.ship_address&.last_name || order.user&.last_name
|
59
|
+
|
60
|
+
order.bill_address.first_name ||= first_name
|
61
|
+
order.bill_address.last_name ||= last_name
|
62
|
+
order.bill_address.phone ||= billing_details.phone
|
63
|
+
order.bill_address.address1 ||= address.line1
|
64
|
+
order.bill_address.address2 ||= address.line2
|
65
|
+
order.bill_address.city ||= address.city
|
66
|
+
order.bill_address.zipcode ||= address.postal_code
|
67
|
+
|
68
|
+
state_name = address.state
|
69
|
+
if country.states_required?
|
70
|
+
order.bill_address.state = country.states.find_all_by_name_or_abbr(state_name)&.first if country.states_required?
|
71
|
+
else
|
72
|
+
order.bill_address.state_name = state_name
|
73
|
+
end
|
74
|
+
|
75
|
+
order.bill_address.state_name ||= state_name
|
76
|
+
|
77
|
+
if order.bill_address.invalid?
|
78
|
+
order.bill_address = order.ship_address
|
79
|
+
else
|
80
|
+
order.bill_address.save!
|
81
|
+
end
|
82
|
+
|
83
|
+
order.save!
|
84
|
+
|
85
|
+
copy_bill_info_to_user(order) if order.user.present?
|
86
|
+
|
87
|
+
order
|
88
|
+
end
|
89
|
+
|
90
|
+
def copy_bill_info_to_user(order)
|
91
|
+
user = order.user
|
92
|
+
user.first_name ||= order.bill_address.first_name
|
93
|
+
user.last_name ||= order.bill_address.last_name
|
94
|
+
user.phone ||= order.bill_address.phone
|
95
|
+
user.bill_address_id ||= order.bill_address.id
|
96
|
+
user.save! if user.changed?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CreateGatewayWebhooks
|
3
|
+
def call(payment_method:, events: SpreeStripe::Config[:supported_webhook_events], connect: false)
|
4
|
+
webhook_list = Stripe::WebhookEndpoint.list({}, { api_key: payment_method.preferred_secret_key })
|
5
|
+
webhook = find_webhook(webhook_list[:data], events)
|
6
|
+
|
7
|
+
ensure_webhook(payment_method, webhook, connect, events)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def find_webhook(webhooks_data, enabled_events)
|
13
|
+
webhook_url = SpreeStripe::Gateway.webhook_url
|
14
|
+
|
15
|
+
webhooks_data.find do |webhook|
|
16
|
+
webhook[:url] == webhook_url && webhook[:enabled_events].sort == enabled_events.sort
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def ensure_webhook(payment_method, stripe_webhook, connect, events)
|
21
|
+
if stripe_webhook.nil?
|
22
|
+
create_webhook_endpoint(payment_method, connect, events)
|
23
|
+
else
|
24
|
+
webhook_key = WebhookKey.find_by(stripe_id: stripe_webhook[:id])
|
25
|
+
|
26
|
+
if webhook_key.present?
|
27
|
+
webhook_key.payment_methods << payment_method if webhook_key.payment_methods.exclude?(payment_method)
|
28
|
+
else
|
29
|
+
create_webhook_endpoint(payment_method, connect, events)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_webhook_endpoint(payment_method, connect, events)
|
35
|
+
params = build_webhook_params(connect, events)
|
36
|
+
stripe_webhook = Stripe::WebhookEndpoint.create(params, { api_key: payment_method.preferred_secret_key })
|
37
|
+
|
38
|
+
SpreeStripe::WebhookKey.create!(
|
39
|
+
stripe_id: stripe_webhook[:id],
|
40
|
+
signing_secret: stripe_webhook[:secret],
|
41
|
+
payment_methods: [payment_method]
|
42
|
+
)
|
43
|
+
|
44
|
+
Rails.cache.delete('stripe_webhook_signing_keys')
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_webhook_params(connect, events)
|
48
|
+
{
|
49
|
+
url: SpreeStripe::Gateway.webhook_url,
|
50
|
+
enabled_events: events,
|
51
|
+
connect: connect
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CreatePayment
|
3
|
+
def initialize(order:, payment_intent:, gateway: nil, tax_transaction: nil, amount: nil)
|
4
|
+
@order = order
|
5
|
+
@gateway = gateway || order.store.stripe_gateway
|
6
|
+
@payment_intent = payment_intent
|
7
|
+
@tax_transaction = tax_transaction
|
8
|
+
@amount = amount || order.total_minus_store_credits
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
stripe_charge = payment_intent.stripe_charge
|
13
|
+
|
14
|
+
if stripe_charge.present?
|
15
|
+
source = SpreeStripe::CreateSource.new(
|
16
|
+
order: order,
|
17
|
+
stripe_payment_method_details: stripe_charge.payment_method_details,
|
18
|
+
stripe_payment_method_id: stripe_charge.payment_method,
|
19
|
+
stripe_billing_details: stripe_charge.billing_details,
|
20
|
+
gateway: gateway
|
21
|
+
).call
|
22
|
+
end
|
23
|
+
|
24
|
+
# sometimes a job is re-tried and creates a double payment record so we need to avoid it!
|
25
|
+
payment = order.payments.find_or_initialize_by(
|
26
|
+
payment_method_id: gateway.id,
|
27
|
+
response_code: payment_intent.stripe_id,
|
28
|
+
amount: amount
|
29
|
+
)
|
30
|
+
|
31
|
+
payment.source = source if source.present?
|
32
|
+
payment.stripe_tax_transaction_id = tax_transaction
|
33
|
+
payment.stripe_charge_id = stripe_charge&.id
|
34
|
+
|
35
|
+
payment.save!
|
36
|
+
payment
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :order, :gateway, :payment_intent, :tax_transaction, :source, :amount
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CreatePaymentIntent
|
3
|
+
def call(order, gateway, stripe_payment_method_id: nil, off_session: false)
|
4
|
+
total = order.total_minus_store_credits
|
5
|
+
amount = Spree::Money.new(total).cents
|
6
|
+
|
7
|
+
return nil if amount.zero?
|
8
|
+
|
9
|
+
# lookup in database for existing payment intent
|
10
|
+
payment_intent = SpreeStripe::PaymentIntent.find_by(order: order, payment_method: gateway)
|
11
|
+
|
12
|
+
return payment_intent if payment_intent.present?
|
13
|
+
|
14
|
+
# response is an ActiveMerchant::Billing::Response object
|
15
|
+
# https://github.com/activemerchant/active_merchant/blob/master/lib/active_merchant/billing/response.rb
|
16
|
+
response = gateway.create_payment_intent(
|
17
|
+
amount,
|
18
|
+
order,
|
19
|
+
payment_method_id: stripe_payment_method_id,
|
20
|
+
off_session: off_session
|
21
|
+
)
|
22
|
+
|
23
|
+
# we should only create a customer if the order was placed by a user
|
24
|
+
customer = gateway.fetch_or_create_customer(user: order.user) if order.user.present?
|
25
|
+
ephemeral_key_response = gateway.create_ephemeral_key(customer.profile_id) if customer.present?
|
26
|
+
ephemeral_key_secret = ephemeral_key_response&.params['secret'] if ephemeral_key_response.present?
|
27
|
+
|
28
|
+
# persist the payment intent
|
29
|
+
SpreeStripe::PaymentIntent.create!(
|
30
|
+
order: order,
|
31
|
+
payment_method: gateway,
|
32
|
+
amount: total,
|
33
|
+
stripe_id: response.authorization,
|
34
|
+
client_secret: response.params['client_secret'],
|
35
|
+
customer_id: customer&.profile_id,
|
36
|
+
ephemeral_key_secret: ephemeral_key_secret
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CreateSetupIntent
|
3
|
+
prepend Spree::ServiceModule::Base
|
4
|
+
|
5
|
+
def call(gateway:, user:)
|
6
|
+
customer = gateway.fetch_or_create_customer(user: user)
|
7
|
+
|
8
|
+
ephemeral_key_response = gateway.create_ephemeral_key(customer.profile_id)
|
9
|
+
setup_intent = gateway.create_setup_intent(customer.profile_id)
|
10
|
+
|
11
|
+
success(
|
12
|
+
{
|
13
|
+
customer_id: customer.profile_id,
|
14
|
+
ephemeral_key_secret: ephemeral_key_response.params['secret'],
|
15
|
+
setup_intent_client_secret: setup_intent.params['client_secret']
|
16
|
+
}
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class CreateSource
|
3
|
+
def initialize(stripe_payment_method_details:, stripe_payment_method_id:, gateway:, stripe_billing_details:, order: nil, user: nil)
|
4
|
+
@stripe_payment_method_details = stripe_payment_method_details
|
5
|
+
@stripe_payment_method_id = stripe_payment_method_id
|
6
|
+
@gateway = gateway
|
7
|
+
@user = user || order&.user
|
8
|
+
@stripe_billing_details = stripe_billing_details
|
9
|
+
@order = order
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
case stripe_payment_method_details.type
|
14
|
+
when 'card'
|
15
|
+
find_or_create_credit_card
|
16
|
+
when 'klarna'
|
17
|
+
SpreeStripe::PaymentSources::Klarna.create!(source_params)
|
18
|
+
when 'afterpay_clearpay'
|
19
|
+
SpreeStripe::PaymentSources::AfterPay.create!(source_params)
|
20
|
+
when 'sepa_debit'
|
21
|
+
SpreeStripe::PaymentSources::SepaDebit.create!(source_params)
|
22
|
+
when 'p24'
|
23
|
+
SpreeStripe::PaymentSources::Przelewy24.create!(source_params.merge(bank: stripe_payment_method_details.p24.bank))
|
24
|
+
when 'ideal'
|
25
|
+
SpreeStripe::PaymentSources::Ideal.create!(
|
26
|
+
source_params.merge(
|
27
|
+
bank: stripe_payment_method_details.ideal.bank,
|
28
|
+
last4: stripe_payment_method_details.ideal.iban_last4
|
29
|
+
)
|
30
|
+
)
|
31
|
+
when 'alipay'
|
32
|
+
SpreeStripe::PaymentSources::Alipay.create!(source_params)
|
33
|
+
when 'link'
|
34
|
+
SpreeStripe::PaymentSources::Link.create!(source_params)
|
35
|
+
when 'affirm'
|
36
|
+
SpreeStripe::PaymentSources::Affirm.create!(source_params)
|
37
|
+
else
|
38
|
+
raise "[STRIPE] Unknown payment method #{stripe_payment_method_details.type}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :gateway, :user, :stripe_payment_method_details, :stripe_payment_method_id, :stripe_billing_details, :order
|
45
|
+
|
46
|
+
def find_or_create_credit_card
|
47
|
+
if user
|
48
|
+
source = user.credit_cards.find_by(gateway_payment_profile_id: stripe_payment_method_id)
|
49
|
+
|
50
|
+
return source if source
|
51
|
+
end
|
52
|
+
|
53
|
+
Spree::CreditCard.create!(credit_card_params)
|
54
|
+
end
|
55
|
+
|
56
|
+
def credit_card_params
|
57
|
+
card_details = stripe_payment_method_details.card
|
58
|
+
customer = gateway.fetch_or_create_customer(user: user, order: order)
|
59
|
+
|
60
|
+
{
|
61
|
+
user: user,
|
62
|
+
gateway_customer: customer,
|
63
|
+
payment_method: gateway,
|
64
|
+
gateway_customer_profile_id: customer&.profile_id,
|
65
|
+
gateway_payment_profile_id: stripe_payment_method_id,
|
66
|
+
name: stripe_billing_details.name,
|
67
|
+
month: card_details.exp_month,
|
68
|
+
year: card_details.exp_year,
|
69
|
+
last_digits: card_details.last4,
|
70
|
+
brand: card_details.brand,
|
71
|
+
private_metadata: {
|
72
|
+
checks: stripe_payment_method_details.card&.checks,
|
73
|
+
wallet: {
|
74
|
+
type: stripe_payment_method_details.card&.wallet&.type
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def source_params
|
81
|
+
{
|
82
|
+
gateway_payment_profile_id: stripe_payment_method_id,
|
83
|
+
payment_method: gateway
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class RegisterDomain
|
3
|
+
def call(model:)
|
4
|
+
gateway = model.is_a?(Spree::Store) ? model.stripe_gateway : model.store.stripe_gateway
|
5
|
+
|
6
|
+
payment_method_domain = gateway.send_request { Stripe::PaymentMethodDomain.create({ domain_name: model.url }) }
|
7
|
+
|
8
|
+
attributes_to_update = { stripe_apple_pay_domain_id: payment_method_domain.id }
|
9
|
+
|
10
|
+
tld_length = model.url.split('.').length
|
11
|
+
if tld_length > 2 && model.is_a?(Spree::CustomDomain)
|
12
|
+
top_level_domain_name = model.url.split('.').last(tld_length - 1).join('.')
|
13
|
+
top_level_domain = gateway.send_request { Stripe::PaymentMethodDomain.create({ domain_name: top_level_domain_name }) }
|
14
|
+
attributes_to_update[:stripe_top_level_domain_id] = top_level_domain.id
|
15
|
+
end
|
16
|
+
|
17
|
+
model.update!(**attributes_to_update)
|
18
|
+
|
19
|
+
payment_method_domain
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|