Beispiel #1
0
def propagate_exchange(cursor, participant, exchange, route, error, amount):
    """Propagates an exchange's result to the participant's balance and the
    route's status.
    """
    route.update_error(error or '')

    new_balance = cursor.one(
        """
        UPDATE participants
           SET balance=(balance + %s)
         WHERE id=%s
     RETURNING balance
    """, (amount, participant.id))

    if amount < 0 and new_balance < 0:
        raise NegativeBalance

    if amount < 0:
        bundles = cursor.all(
            """
            LOCK TABLE cash_bundles IN EXCLUSIVE MODE;
            SELECT *
              FROM cash_bundles
             WHERE owner = %s
               AND ts < now() - INTERVAL %s
          ORDER BY ts
        """, (participant.id, QUARANTINE))
        withdrawable = sum(b.amount for b in bundles)
        x = -amount
        if x > withdrawable:
            raise NotEnoughWithdrawableMoney(Money(withdrawable, 'EUR'))
        for b in bundles:
            if x >= b.amount:
                cursor.run("DELETE FROM cash_bundles WHERE id = %s", (b.id, ))
                x -= b.amount
                if x == 0:
                    break
            else:
                assert x > 0
                cursor.run(
                    """
                    UPDATE cash_bundles
                       SET amount = (amount - %s)
                     WHERE id = %s
                """, (x, b.id))
                break
    elif amount > 0:
        cursor.run(
            """
            INSERT INTO cash_bundles
                        (owner, origin, amount, ts)
                 VALUES (%s, %s, %s, %s)
        """, (participant.id, exchange.id, amount, exchange.timestamp))

    participant.set_attributes(balance=new_balance)

    if amount != 0:
        participant.update_giving_and_tippees(cursor)
def propagate_exchange(cursor, participant, exchange, error, amount, bundles=None):
    """Propagates an exchange's result to the participant's balance.
    """
    wallet_id = exchange.wallet_id
    new_balance = cursor.one("""
        UPDATE wallets
           SET balance = (balance + %s)
         WHERE remote_id = %s
           AND (balance + %s) >= 0
     RETURNING balance
    """, (amount, wallet_id, amount))

    if new_balance is None:
        raise NegativeBalance

    if amount < 0:
        bundles = bundles or cursor.all("""
            LOCK TABLE cash_bundles IN EXCLUSIVE MODE;
            SELECT b.*
              FROM cash_bundles b
              JOIN exchanges e ON e.id = b.origin
             WHERE b.owner = %s
               AND b.ts < now() - INTERVAL %s
               AND b.disputed IS NOT TRUE
               AND b.locked_for IS NULL
               AND b.amount::currency = %s
          ORDER BY b.owner = e.participant DESC, b.ts
        """, (participant.id, QUARANTINE, amount.currency))
        withdrawable = sum(b.amount for b in bundles)
        x = -amount
        if x > withdrawable:
            raise NotEnoughWithdrawableMoney(withdrawable)
        for b in bundles:
            if x >= b.amount:
                cursor.run("""
                    UPDATE cash_bundles
                       SET owner = NULL
                         , withdrawal = %s
                         , wallet_id = NULL
                     WHERE id = %s
                """, (exchange.id, b.id))
                x -= b.amount
                if x == 0:
                    break
            else:
                assert x > 0
                cursor.run("""
                    INSERT INTO cash_bundles
                                (owner, origin, ts, amount, withdrawal, wallet_id)
                         VALUES (NULL, %s, %s, %s, %s, NULL)
                """, (b.origin, b.ts, x, exchange.id))
                cursor.run("""
                    UPDATE cash_bundles
                       SET amount = (amount - %s)
                     WHERE id = %s
                """, (x, b.id))
                break
    elif amount > 0 and (exchange.amount < 0 or exchange.refund_ref):
        # failed withdrawal
        orig_exchange_id = exchange.refund_ref or exchange.id
        cursor.run("""
            UPDATE cash_bundles b
               SET owner = %(p_id)s
                 , withdrawal = NULL
                 , wallet_id = %(wallet_id)s
             WHERE withdrawal = %(e_id)s
        """, dict(p_id=participant.id, e_id=orig_exchange_id, wallet_id=wallet_id))
    elif amount > 0:
        cursor.run("""
            INSERT INTO cash_bundles
                        (owner, origin, amount, ts, wallet_id)
                 VALUES (%s, %s, %s, %s, %s)
        """, (participant.id, exchange.id, amount, exchange.timestamp, wallet_id))

    new_balance = cursor.one("SELECT recompute_balance(%s)", (participant.id,))
    participant.set_attributes(balance=new_balance)

    if amount != 0:
        merge_cash_bundles(cursor, participant.id)
        participant.update_giving_and_tippees(cursor)
Beispiel #3
0
def propagate_exchange(cursor, participant, exchange, route, error, amount):
    """Propagates an exchange's result to the participant's balance and the
    route's status.
    """
    route.update_error(error or '')

    new_balance = cursor.one(
        """
        UPDATE participants
           SET balance=(balance + %s)
         WHERE id=%s
     RETURNING balance
    """, (amount, participant.id))

    if amount < 0 and new_balance < 0:
        raise NegativeBalance

    if amount < 0:
        bundles = cursor.all(
            """
            LOCK TABLE cash_bundles IN EXCLUSIVE MODE;
            SELECT b.*
              FROM cash_bundles b
              JOIN exchanges e ON e.id = b.origin
             WHERE b.owner = %s
               AND b.ts < now() - INTERVAL %s
          ORDER BY b.owner = e.participant DESC, b.ts
        """, (participant.id, QUARANTINE))
        withdrawable = sum(b.amount for b in bundles)
        x = -amount
        if x > withdrawable:
            raise NotEnoughWithdrawableMoney(Money(withdrawable, 'EUR'))
        for b in bundles:
            if x >= b.amount:
                cursor.run(
                    """
                    INSERT INTO e2e_transfers
                                (origin, withdrawal, amount)
                         VALUES (%s, %s, %s)
                """, (b.origin, exchange.id, b.amount))
                cursor.run("DELETE FROM cash_bundles WHERE id = %s", (b.id, ))
                x -= b.amount
                if x == 0:
                    break
            else:
                assert x > 0
                cursor.run(
                    """
                    INSERT INTO e2e_transfers
                                (origin, withdrawal, amount)
                         VALUES (%s, %s, %s)
                """, (b.origin, exchange.id, x))
                cursor.run(
                    """
                    UPDATE cash_bundles
                       SET amount = (amount - %s)
                     WHERE id = %s
                """, (x, b.id))
                break
    elif amount > 0 and exchange.amount < 0:
        cursor.run(
            """
            LOCK TABLE cash_bundles IN EXCLUSIVE MODE;
            INSERT INTO cash_bundles
                        (owner, origin, amount, ts)
                 SELECT %(p_id)s, t.origin, t.amount, e.timestamp
                   FROM e2e_transfers t
                   JOIN exchanges e ON e.id = t.origin
                  WHERE t.withdrawal = %(e_id)s;
            DELETE FROM e2e_transfers WHERE withdrawal = %(e_id)s;
        """, dict(p_id=participant.id, e_id=exchange.id))
    elif amount > 0:
        cursor.run(
            """
            INSERT INTO cash_bundles
                        (owner, origin, amount, ts)
                 VALUES (%s, %s, %s, %s)
        """, (participant.id, exchange.id, amount, exchange.timestamp))

    participant.set_attributes(balance=new_balance)

    if amount != 0:
        participant.update_giving_and_tippees(cursor)
        merge_cash_bundles(cursor, participant.id)