diff --git a/js/stripe.js b/js/stripe.js
index 60777d81c..f024f583c 100644
--- a/js/stripe.js
+++ b/js/stripe.js
@@ -99,33 +99,59 @@ Liberapay.stripe_form_init = function($form) {
if (local_address.length === 1) {
local_address.push(null);
}
- var pmData = {
- billing_details: {
- address: {
- city: $postal_address_city.val(),
- country: $postal_address_country.val(),
- line1: local_address[0],
- line2: local_address[1],
- postal_code: $postal_address_code.val(),
- state: $postal_address_region.val(),
- },
- email: $form.find('input[name="owner.email"]').val(),
- name: $form.find('input[name="owner.name"]').val(),
- }
- };
- stripe.createPaymentMethod(pmType, element, pmData).then(Liberapay.wrap(function(result) {
- if (result.error) {
- $errorElement.text(result.error.message);
- } else {
- submitting = true;
- $form.find('input[name="route"]').remove();
- $form.find('input[name="stripe_pm_id"]').remove();
- var $hidden_input = $('');
- $hidden_input.val(result.paymentMethod.id);
- $form.append($hidden_input);
- $form.submit();
- }
- }));
+ if (element_type == 'iban') {
+ var tokenData = {
+ currency: 'EUR',
+ account_holder_name: $form.find('input[name="owner.name"]').val(),
+ address_country: $postal_address_country.val(),
+ address_state: $postal_address_region.val(),
+ address_city: $postal_address_city.val(),
+ address_zip: $postal_address_code.val(),
+ address_line1: local_address[0],
+ address_line2: local_address[1],
+ };
+ stripe.createToken(element, tokenData).then(Liberapay.wrap(function(result) {
+ if (result.error) {
+ $errorElement.text(result.error.message);
+ } else {
+ submitting = true;
+ $form.find('input[name="route"]').remove();
+ $form.find('input[name="token"]').remove();
+ var $hidden_input = $('');
+ $hidden_input.val(result.token.id);
+ $form.append($hidden_input);
+ $form.submit();
+ }
+ }));
+ } else {
+ var pmData = {
+ billing_details: {
+ address: {
+ city: $postal_address_city.val(),
+ country: $postal_address_country.val(),
+ line1: local_address[0],
+ line2: local_address[1],
+ postal_code: $postal_address_code.val(),
+ state: $postal_address_region.val(),
+ },
+ email: $form.find('input[name="owner.email"]').val(),
+ name: $form.find('input[name="owner.name"]').val(),
+ }
+ };
+ stripe.createPaymentMethod(pmType, element, pmData).then(Liberapay.wrap(function(result) {
+ if (result.error) {
+ $errorElement.text(result.error.message);
+ } else {
+ submitting = true;
+ $form.find('input[name="route"]').remove();
+ $form.find('input[name="stripe_pm_id"]').remove();
+ var $hidden_input = $('');
+ $hidden_input.val(result.paymentMethod.id);
+ $form.append($hidden_input);
+ $form.submit();
+ }
+ }));
+ }
}));
$form.attr('action', '');
};
diff --git a/liberapay/payin/stripe.py b/liberapay/payin/stripe.py
index 732a6d4c8..0d75fd9cc 100644
--- a/liberapay/payin/stripe.py
+++ b/liberapay/payin/stripe.py
@@ -227,7 +227,7 @@ def try_other_destinations(db, payin, payer, charge, update_donor=True):
def charge_and_transfer(
- db, payin, payer, statement_descriptor, on_behalf_of=None, update_donor=True,
+ db, payin, payer, statement_descriptor, update_donor=True,
):
"""Create a standalone Charge then multiple Transfers.
@@ -243,21 +243,24 @@ def charge_and_transfer(
description = generate_charge_description(payin)
try:
if route.address.startswith('pm_'):
- intent = stripe.PaymentIntent.create(
+ params = dict(
amount=Money_to_int(amount),
confirm=True,
currency=amount.currency.lower(),
customer=route.remote_user_id,
description=description,
+ mandate=route.mandate,
metadata={'payin_id': payin.id},
off_session=payin.off_session,
- on_behalf_of=on_behalf_of,
payment_method=route.address,
+ payment_method_types=['sepa_debit' if route.network == 'stripe-sdd' else 'card'],
return_url=payer.url('giving/pay/stripe/%i' % payin.id),
- setup_future_usage=(None if route.one_off or payin.off_session else 'off_session'),
statement_descriptor=statement_descriptor,
idempotency_key='payin_intent_%i' % payin.id,
)
+ if not route.mandate and not route.one_off and not payin.off_session:
+ params['setup_future_usage'] = 'off_session'
+ intent = stripe.PaymentIntent.create(**params)
else:
charge = stripe.Charge.create(
amount=Money_to_int(amount),
@@ -265,7 +268,6 @@ def charge_and_transfer(
customer=route.remote_user_id,
description=description,
metadata={'payin_id': payin.id},
- on_behalf_of=on_behalf_of,
source=route.address,
statement_descriptor=statement_descriptor,
expand=['balance_transaction'],
@@ -313,22 +315,26 @@ def destination_charge(db, payin, payer, statement_descriptor, update_donor=True
destination = None
try:
if route.address.startswith('pm_'):
- intent = stripe.PaymentIntent.create(
+ params = dict(
amount=Money_to_int(amount),
confirm=True,
currency=amount.currency.lower(),
customer=route.remote_user_id,
description=description,
+ mandate=route.mandate,
metadata={'payin_id': payin.id},
off_session=payin.off_session,
on_behalf_of=destination,
payment_method=route.address,
+ payment_method_types=['sepa_debit' if route.network == 'stripe-sdd' else 'card'],
return_url=payer.url('giving/pay/stripe/%i' % payin.id),
- setup_future_usage=(None if route.one_off or payin.off_session else 'off_session'),
statement_descriptor=statement_descriptor,
transfer_data={'destination': destination} if destination else None,
idempotency_key='payin_intent_%i' % payin.id,
)
+ if not route.mandate and not route.one_off and not payin.off_session:
+ params['setup_future_usage'] = 'off_session'
+ intent = stripe.PaymentIntent.create(**params)
else:
charge = stripe.Charge.create(
amount=Money_to_int(amount),
diff --git a/www/%username/giving/pay/stripe/%payin_id.spt b/www/%username/giving/pay/stripe/%payin_id.spt
index 5e9d02191..53c7d7c1a 100644
--- a/www/%username/giving/pay/stripe/%payin_id.spt
+++ b/www/%username/giving/pay/stripe/%payin_id.spt
@@ -205,6 +205,7 @@ if tippees:
raise response.redirect(payer.path(
'giving/pay?redirect_reason=unaccepted_currency'
))
+ route_address_pattern = 'src_%' if payment_type == 'sdd' and len(tips) == 1 else '%'
routes = website.db.all("""
SELECT r
FROM exchange_routes r
@@ -212,11 +213,12 @@ if tippees:
AND r.status = 'chargeable'
AND r.network::text LIKE %s
AND (r.one_off IS FALSE OR r.ctime > (current_timestamp - interval '6 hours'))
+ AND r.address LIKE %s
ORDER BY r.is_default_for = %s DESC NULLS LAST
, r.is_default DESC NULLS LAST
, r.network = 'stripe-sdd' DESC
, r.id DESC
- """, (payer.id, 'stripe-' + (payment_type or '%'), payment.currency))
+ """, (payer.id, 'stripe-' + (payment_type or '%'), route_address_pattern, payment.currency))
if routes:
route = None
while routes: