diff --git a/liberapay/payin/common.py b/liberapay/payin/common.py index 1eb35d88d..f727f26ac 100644 --- a/liberapay/payin/common.py +++ b/liberapay/payin/common.py @@ -558,6 +558,9 @@ def resolve_amounts( Returns a copy of `base_amounts` with updated values. """ + if available_amount < (minimum_amount or 0): + raise ValueError("available_amount can't be less than minimum_amount or 0") + currency = available_amount.currency zero = Money.ZEROS[currency] inf = Money('inf', currency) diff --git a/liberapay/payin/stripe.py b/liberapay/payin/stripe.py index d7220d177..f42552244 100644 --- a/liberapay/payin/stripe.py +++ b/liberapay/payin/stripe.py @@ -483,7 +483,7 @@ def settle_charge_and_transfers( ORDER BY pt.id """, (payin.id,)) last = len(payin_transfers) - 1 - if amount_settled is not None: + if charge.status == 'succeeded': payer = db.Participant.from_id(payin.payer) undeliverable_amount = amount_settled.zero() for i, pt in enumerate(payin_transfers): @@ -501,7 +501,7 @@ def settle_charge_and_transfers( ) elif pt.status in ('pre', 'pending'): pt = execute_transfer( - db, pt, pt.destination_id, charge.id, + db, pt, charge.id, update_donor=(update_donor and i == last), ) else: @@ -542,7 +542,8 @@ def settle_charge_and_transfers( update_donor=(update_donor and i == last), ) - elif charge.status in ('failed', 'pending'): + else: + assert charge.status in ('failed', 'pending') for i, pt in enumerate(payin_transfers): update_payin_transfer( db, pt.id, None, charge.status, error, @@ -552,12 +553,11 @@ def settle_charge_and_transfers( return payin -def execute_transfer(db, pt, destination, source_transaction, update_donor=True): +def execute_transfer(db, pt, source_transaction, update_donor=True): """Create a Transfer. Args: pt (Record): a row from the `payin_transfers` table - destination (str): the Stripe ID of the destination account source_transaction (str): the ID of the Charge this transfer is linked to Returns: @@ -570,7 +570,7 @@ def execute_transfer(db, pt, destination, source_transaction, update_donor=True) amount=Money_to_int(pt.amount), currency=pt.amount.currency, description=generate_transfer_description(pt), - destination=destination, + destination=pt.destination_id, metadata={'payin_transfer_id': pt.id}, source_transaction=source_transaction, idempotency_key='payin_transfer_%i' % pt.id, @@ -583,9 +583,9 @@ def execute_transfer(db, pt, destination, source_transaction, update_donor=True) SET is_current = null WHERE provider = 'stripe' AND id = %s - """, (destination,)) + """, (pt.destination_id,)) alternate_destination = db.one(""" - SELECT id + SELECT id, pk FROM payment_accounts WHERE participant = %(p_id)s AND provider = 'stripe' @@ -597,7 +597,14 @@ def execute_transfer(db, pt, destination, source_transaction, update_donor=True) LIMIT 1 """, dict(p_id=pt.recipient, SEPA=SEPA, currency=pt.amount.currency)) if alternate_destination: - return execute_transfer(db, pt, alternate_destination, source_transaction) + pt = db.one(""" + UPDATE payin_transfers + SET destination = %s + WHERE id = %s + RETURNING * + """, (alternate_destination.pk, pt.id)) + pt.destination_id = alternate_destination.id + return execute_transfer(db, pt, source_transaction) error = "The recipient's account no longer exists." return update_payin_transfer( db, pt.id, None, 'failed', error, update_donor=update_donor, diff --git a/www/%username/giving/pay/stripe/%payin_id.spt b/www/%username/giving/pay/stripe/%payin_id.spt index 9ed8d036c..59097965c 100644 --- a/www/%username/giving/pay/stripe/%payin_id.spt +++ b/www/%username/giving/pay/stripe/%payin_id.spt @@ -256,7 +256,7 @@ if tippees: if len(tips) == 1: proto_transfers = resolve_tip( website.db, tips[0], tips[0].tippee_p, 'stripe', payer, payer.guessed_country, - tips[0].periodic_amount + tips[0].amount * 52 ) if len(proto_transfers) == 1: if proto_transfers[0].destination.country not in constants.SEPA: