From 5b7f16ad19bab3a03a3cb120b82db7f6c560c391 Mon Sep 17 00:00:00 2001 From: Changaco Date: Mon, 16 Sep 2024 09:34:24 +0200 Subject: [PATCH 1/2] improve `missing_route` notif to reduce confusion --- emails/missing_route.spt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/emails/missing_route.spt b/emails/missing_route.spt index fd28b690a..d46939907 100644 --- a/emails/missing_route.spt +++ b/emails/missing_route.spt @@ -4,6 +4,7 @@ [---] text/html % if len(payins) == 1 % set sp = payins[0] + % set n_transfers = len(sp.transfers)

{{ _( "You have a payment of {amount} scheduled for {payment_date} to renew your donation to {recipient}, but we can't process it because a valid payment instrument is missing.", amount=sp.amount, payment_date=sp.execution_date, recipient=website.tippee_links(sp.transfers)[0] @@ -12,6 +13,7 @@ amount=sp.amount, payment_date=sp.execution_date, recipients=website.tippee_links(sp.transfers) ) }}

% else + % set n_transfers = [0]

{{ ngettext( "", "You have {n} payments scheduled to renew your donations, but we can't process them because a valid payment instrument is missing.", @@ -20,6 +22,7 @@

{{ _("The payment dates, amounts and recipients are:") }}

+ % set n_transfers = n_transfers[0] % endif -

{{ _("Add a payment instrument") }}

+

{{ ngettext( + "Renew this donation", "Renew these donations", n_transfers +) }}

{{ _("Manage your donations") }}

From 736f81850846d8c053bc9aa94c93397dcd06b17f Mon Sep 17 00:00:00 2001 From: Changaco Date: Wed, 18 Sep 2024 11:14:07 +0200 Subject: [PATCH 2/2] fix execution of automatic renewals - don't attempt direct debits when the recipient doesn't have any account in SEPA - restrict direct debit to destinations in SEPA --- liberapay/payin/cron.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/liberapay/payin/cron.py b/liberapay/payin/cron.py index faceb204d..1f545eacb 100644 --- a/liberapay/payin/cron.py +++ b/liberapay/payin/cron.py @@ -6,6 +6,7 @@ from pando import json from ..billing.payday import compute_next_payday_date +from ..constants import SEPA from ..cron import logger from ..exceptions import ( AccountSuspended, BadDonationCurrency, MissingPaymentAccount, NoSelfTipping, @@ -282,7 +283,29 @@ def execute_scheduled_payins(): WHERE r.participant = sp.payer AND r.status = 'chargeable' AND r.network::text LIKE 'stripe-%%' - AND ( sp.amount::currency = 'EUR' OR r.network <> 'stripe-sdd' ) + AND ( r.network <> 'stripe-sdd' OR + sp.amount::currency = 'EUR' AND + ( SELECT count(*) > 0 + FROM json_array_elements(sp.transfers) tr + JOIN LATERAL ( + SELECT 1 + FROM payment_accounts a + WHERE ( a.participant = (tr->>'tippee')::bigint OR + a.participant IN ( + SELECT t.member + FROM current_takes t + WHERE t.team = (tr->>'tippee')::bigint + AND t.amount <> 0 + ) + ) + AND a.is_current IS TRUE + AND a.verified IS TRUE + AND a.charges_enabled IS TRUE + AND a.country IN %(SEPA)s + LIMIT 1 + ) ON true + ) + ) ORDER BY r.is_default_for = sp.amount::currency DESC NULLS LAST , r.is_default DESC NULLS LAST , r.ctime DESC @@ -296,7 +319,7 @@ def execute_scheduled_payins(): AND p.is_suspended IS NOT TRUE GROUP BY p.id ORDER BY p.id - """) + """, dict(SEPA=SEPA,)) for payer, scheduled_payins in rows: scheduled_payins[:] = [Object(**sp) for sp in scheduled_payins] for sp in scheduled_payins: @@ -319,7 +342,7 @@ def unpack(): if transfers: payin_amount = sum(tr['amount'] for tr in transfers) proto_transfers = [] - sepa_only = len(transfers) > 1 + sepa_only = len(transfers) > 1 or route.network == 'stripe-sdd' for tr in list(transfers): try: proto_transfers.extend(resolve_tip(