Exemple #1
0
def refund_payin(db, exchange, amount, participant):
    """Refund a specific payin.
    """
    assert participant.id == exchange.participant

    # Record the refund attempt
    fee = vat = amount.zero()
    with db.get_cursor() as cursor:
        cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
        bundles = cursor.all(
            """
            SELECT b.id
              FROM cash_bundles b
             WHERE b.owner = %s
        """, (participant.id, ))
        e_refund = cursor.one(
            """
            INSERT INTO exchanges
                        (participant, amount, fee, vat, route, status, refund_ref, wallet_id)
                 VALUES (%s, %s, %s, %s, %s, 'pre', %s, %s)
              RETURNING *
        """, (participant.id, -amount, fee, vat, exchange.route, exchange.id,
              exchange.wallet_id))
        cursor.run(
            """
            INSERT INTO exchange_events
                        (timestamp, exchange, status, wallet_delta)
                 VALUES (%s, %s, 'pre', %s)
        """, (e_refund.timestamp, e_refund.id, e_refund.amount - e_refund.fee))
        propagate_exchange(cursor,
                           participant,
                           e_refund,
                           None,
                           e_refund.amount,
                           bundles=bundles)

    # Submit the refund
    wallet = db.one("SELECT * FROM wallets WHERE remote_id = %s",
                    (exchange.wallet_id, ))
    m_refund = PayInRefund(payin_id=exchange.remote_id)
    m_refund.AuthorId = wallet.remote_owner_id
    m_refund.Tag = str(e_refund.id)
    m_refund.DebitedFunds = amount.int()
    m_refund.Fees = -fee.int()
    try:
        m_refund.save()
    except Exception as e:
        error = repr_exception(e)
        e_refund = record_exchange_result(db, e_refund.id, '', 'failed', error,
                                          participant)
        return 'exception', e_refund
    e_refund = record_exchange_result(db, e_refund.id, m_refund.Id,
                                      m_refund.Status.lower(),
                                      repr_error(m_refund), participant)
    return e_refund.status, e_refund
def refund_payin(db, exchange, amount, participant):
    """Refund a specific payin.
    """
    assert participant.id == exchange.participant

    # Record the refund attempt
    fee = vat = amount.zero()
    with db.get_cursor() as cursor:
        cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
        bundles = cursor.all("""
            SELECT b.id
              FROM cash_bundles b
             WHERE b.owner = %s
        """, (participant.id,))
        e_refund = cursor.one("""
            INSERT INTO exchanges
                        (participant, amount, fee, vat, route, status, refund_ref, wallet_id)
                 VALUES (%s, %s, %s, %s, %s, 'pre', %s, %s)
              RETURNING *
        """, (participant.id, -amount, fee, vat, exchange.route, exchange.id, exchange.wallet_id))
        cursor.run("""
            INSERT INTO exchange_events
                        (timestamp, exchange, status, wallet_delta)
                 VALUES (%s, %s, 'pre', %s)
        """, (e_refund.timestamp, e_refund.id, e_refund.amount - e_refund.fee))
        propagate_exchange(cursor, participant, e_refund, None, e_refund.amount, bundles=bundles)

    # Submit the refund
    wallet = db.one("SELECT * FROM wallets WHERE remote_id = %s", (exchange.wallet_id,))
    m_refund = PayInRefund(payin_id=exchange.remote_id)
    m_refund.AuthorId = wallet.remote_owner_id
    m_refund.Tag = str(e_refund.id)
    m_refund.DebitedFunds = Money_to_cents(amount)
    m_refund.Fees = -Money_to_cents(fee)
    try:
        m_refund.save()
    except Exception as e:
        error = repr_exception(e)
        e_refund = record_exchange_result(db, e_refund.id, '', 'failed', error, participant)
        return 'exception', e_refund
    e_refund = record_exchange_result(
        db, e_refund.id, m_refund.Id, m_refund.Status.lower(), repr_error(m_refund), participant
    )
    return e_refund.status, e_refund
def refund_payin(db, exchange, create_debts=False, refund_fee=False, dry_run=False):
    """Refund a specific payin.
    """
    assert exchange.status == 'succeeded' and exchange.remote_id, exchange
    e_refund = db.one("SELECT e.* FROM exchanges e WHERE e.refund_ref = %s", (exchange.id,))
    if e_refund and e_refund.status == 'succeeded':
        return 'already done', e_refund

    # Lock the bundles and try to swap them
    with db.get_cursor() as cursor:
        cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
        bundles = [NS(d._asdict()) for d in cursor.all("""
            UPDATE cash_bundles
               SET disputed = true
             WHERE origin = %s
         RETURNING *
        """, (exchange.id,))]
        bundles_sum = sum(b.amount for b in bundles)
        assert bundles_sum == exchange.amount
        original_owner = exchange.participant
        for b in bundles:
            if b.owner == original_owner:
                continue
            try_to_swap_bundle(cursor, b, original_owner)

    # Move the funds back to the original wallet
    LiberapayOrg = Participant.from_username('LiberapayOrg')
    assert LiberapayOrg
    return_payin_bundles_to_origin(db, exchange, LiberapayOrg, create_debts)

    # Add a debt for the fee
    if create_debts and refund_fee:
        create_debt(db, original_owner, LiberapayOrg.id, exchange.fee, exchange.id)

    # Compute and check the amount
    wallet = db.one("SELECT * FROM wallets WHERE remote_id = %s", (exchange.wallet_id,))
    if e_refund and e_refund.status == 'pre':
        amount = -e_refund.amount
    else:
        amount = min(wallet.balance, exchange.amount)
        if amount <= 0:
            return ('not enough money: wallet balance = %s' % wallet.balance), None

    # Stop here if this is a dry run
    zero = exchange.fee.zero()
    fee, vat = (exchange.fee, exchange.vat) if refund_fee else (zero, zero)
    if dry_run:
        msg = (
            '[dry run] full refund of payin #%s (liberapay id %s): amount = %s, fee = %s' %
            (exchange.remote_id, exchange.id, exchange.amount, exchange.fee)
        ) if amount + fee == exchange.amount + exchange.fee else (
            '[dry run] partial refund of payin #%s (liberapay id %s): %s of %s, fee %s of %s' %
            (exchange.remote_id, exchange.id, amount, exchange.amount, fee, exchange.fee)
        )
        return msg, None

    # Record the refund attempt
    participant = Participant.from_id(exchange.participant)
    if not (e_refund and e_refund.status == 'pre'):
        with db.get_cursor() as cursor:
            cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
            bundles = [NS(d._asdict()) for d in cursor.all("""
                SELECT *
                  FROM cash_bundles
                 WHERE origin = %s
                   AND wallet_id = %s
                   AND disputed = true
            """, (exchange.id, exchange.wallet_id))]
            e_refund = cursor.one("""
                INSERT INTO exchanges
                            (participant, amount, fee, vat, route, status, refund_ref, wallet_id)
                     VALUES (%s, %s, %s, %s, %s, 'pre', %s, %s)
                  RETURNING *
            """, (participant.id, -amount, -fee, -vat, exchange.route, exchange.id, exchange.wallet_id))
            propagate_exchange(cursor, participant, e_refund, None, e_refund.amount, bundles=bundles)

    # Submit the refund
    m_refund = PayInRefund(payin_id=exchange.remote_id)
    m_refund.AuthorId = wallet.remote_owner_id
    m_refund.Tag = str(e_refund.id)
    m_refund.DebitedFunds = amount.int()
    m_refund.Fees = -fee.int()
    try:
        m_refund.save()
    except Exception as e:
        error = repr_exception(e)
        e_refund = record_exchange_result(db, e_refund.id, '', 'failed', error, participant)
        return 'exception', e_refund
    e_refund = record_exchange_result(
        db, e_refund.id, m_refund.Id, m_refund.Status.lower(), repr_error(m_refund), participant
    )
    return e_refund.status, e_refund
def refund_disputed_payin(db, exchange, create_debts=False, refund_fee=False, dry_run=False):
    """Refund a specific disputed payin.
    """
    assert exchange.status == 'succeeded' and exchange.remote_id, exchange
    e_refund = db.one("SELECT e.* FROM exchanges e WHERE e.refund_ref = %s", (exchange.id,))
    if e_refund and e_refund.status == 'succeeded':
        return 'already done', e_refund

    # Lock the bundles and try to swap them
    with db.get_cursor() as cursor:
        cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
        bundles = [NS(d._asdict()) for d in cursor.all("""
            UPDATE cash_bundles
               SET disputed = true
             WHERE origin = %s
         RETURNING *
        """, (exchange.id,))]
        bundles_sum = sum(b.amount for b in bundles)
        assert bundles_sum == exchange.amount
        original_owner = exchange.participant
        for b in bundles:
            if b.owner == original_owner:
                continue
            try_to_swap_bundle(cursor, b, original_owner)

    # Move the funds back to the original wallet
    LiberapayOrg = Participant.from_username('LiberapayOrg')
    assert LiberapayOrg
    return_payin_bundles_to_origin(db, exchange, LiberapayOrg, create_debts)

    # Add a debt for the fee
    if create_debts and refund_fee:
        create_debt(db, original_owner, LiberapayOrg.id, exchange.fee, exchange.id)

    # Compute and check the amount
    wallet = db.one("SELECT * FROM wallets WHERE remote_id = %s", (exchange.wallet_id,))
    if e_refund and e_refund.status == 'pre':
        amount = -e_refund.amount
    else:
        amount = min(wallet.balance, exchange.amount)
        if amount <= 0:
            return ('not enough money: wallet balance = %s' % wallet.balance), None

    # Stop here if this is a dry run
    zero = exchange.fee.zero()
    fee, vat = (exchange.fee, exchange.vat) if refund_fee else (zero, zero)
    if dry_run:
        msg = (
            '[dry run] full refund of payin #%s (liberapay id %s): amount = %s, fee = %s' %
            (exchange.remote_id, exchange.id, exchange.amount, exchange.fee)
        ) if amount + fee == exchange.amount + exchange.fee else (
            '[dry run] partial refund of payin #%s (liberapay id %s): %s of %s, fee %s of %s' %
            (exchange.remote_id, exchange.id, amount, exchange.amount, fee, exchange.fee)
        )
        return msg, None

    # Record the refund attempt
    participant = Participant.from_id(exchange.participant)
    if not (e_refund and e_refund.status == 'pre'):
        with db.get_cursor() as cursor:
            cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
            bundles = cursor.all("""
                SELECT id
                  FROM cash_bundles
                 WHERE origin = %s
                   AND wallet_id = %s
                   AND disputed = true
            """, (exchange.id, exchange.wallet_id))
            e_refund = cursor.one("""
                INSERT INTO exchanges
                            (participant, amount, fee, vat, route, status, refund_ref, wallet_id)
                     VALUES (%s, %s, %s, %s, %s, 'pre', %s, %s)
                  RETURNING *
            """, (participant.id, -amount, -fee, -vat, exchange.route, exchange.id, exchange.wallet_id))
            cursor.run("""
                INSERT INTO exchange_events
                            (timestamp, exchange, status, wallet_delta)
                     VALUES (%s, %s, 'pre', %s)
            """, (e_refund.timestamp, e_refund.id, e_refund.amount - e_refund.fee))
            propagate_exchange(cursor, participant, e_refund, None, e_refund.amount, bundles=bundles)

    # Submit the refund
    m_refund = PayInRefund(payin_id=exchange.remote_id)
    m_refund.AuthorId = wallet.remote_owner_id
    m_refund.Tag = str(e_refund.id)
    m_refund.DebitedFunds = Money_to_cents(amount)
    m_refund.Fees = -Money_to_cents(fee)
    try:
        m_refund.save()
    except Exception as e:
        error = repr_exception(e)
        e_refund = record_exchange_result(db, e_refund.id, '', 'failed', error, participant)
        return 'exception', e_refund
    e_refund = record_exchange_result(
        db, e_refund.id, m_refund.Id, m_refund.Status.lower(), repr_error(m_refund), participant
    )
    return e_refund.status, e_refund