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: