Esempio n. 1
0
        def genparticipants(for_payday):
            """Closure generator to yield participants with tips and total.

            We re-fetch participants each time, because the second time through
            we want to use the total obligations they have for next week, and
            if we pass a non-False for_payday to get_tips_and_total then we
            only get unfulfilled tips from prior to that timestamp, which is
            none of them by definition.

            If someone changes tips after payout starts, and we crash during
            payout, then their new tips_and_total will be used on the re-run.
            That's okay.

            Note that we take ts_start from the outer scope when we pass it to
            get_participants, but we pass in for_payday, because we might want
            it to be False (per the definition of git_tips_and_total).

            """
            for participant in self.get_participants(ts_start):
                tips, total = get_tips_and_total( participant['id']
                                                , for_payday=for_payday
                                                , db=self.db
                                                 )
                typecheck(total, Decimal)
                yield(participant, tips, total)
Esempio n. 2
0
        def genparticipants(ts_start):
            """Closure generator to yield participants with tips and total.

            We re-fetch participants each time, because the second time through
            we want to use the total obligations they have for next week, and
            if we pass a non-False ts_start to get_tips_and_total then we only
            get unfulfilled tips from prior to that timestamp, which is none of
            them by definition.

            """
            for participant in self.get_participants():
                tips, total = get_tips_and_total( participant['id']
                                                , for_payday=ts_start
                                                , db=self.db
                                                 )
                typecheck(total, Decimal)
                yield(participant, tips, total)
Esempio n. 3
0
def payday_one(payday_start, participant):
    """Given one participant record, pay their day.

    Charge each participants' credit card if needed before transfering money
    between Gittip accounts.
 
    """
    tips, total = get_tips_and_total( participant['id']
                                    , for_payday=payday_start
                                     )
    typecheck(total, decimal.Decimal)
    short = total - participant['balance']
    if short > 0:
        # The participant's Gittip account is short the amount needed to fund
        # all their tips. Let's try pulling in money from their credit card. If
        # their credit card fails we'll forge ahead, in case they have a
        # positive Gittip balance already that can be used to fund at least
        # *some* tips. The charge method will have set last_bill_result to a
        # non-empty string if the card did fail.

        charge(participant['id'], participant['balanced_account_uri'], short)
 
    successful_tips = 0
    for tip in tips:
        result = log_tip(participant, tip, payday_start)
        if result >= 0:
            successful_tips += result
        else:
            break

    # Update stats.
    # =============

    STATS = """\

        UPDATE paydays 
           SET nparticipants = nparticipants + 1
             , ntippers = ntippers + %s
             , ntips = ntips + %s
         WHERE ts_end='1970-01-01T00:00:00+00'::timestamptz
     RETURNING id

    """
    assert_one_payday(db.fetchone(STATS,
        (1 if successful_tips > 0 else 0, successful_tips)))
Esempio n. 4
0
def payday_one(payday_start, participant):
    """Given one participant record, pay their day.

    Charge each participants' credit card if needed before transfering money
    between Gittip accounts.
 
    """
    tips, total = get_tips_and_total( participant['id']
                                    , for_payday=payday_start
                                     )
    typecheck(total, decimal.Decimal)
    short = total - participant['balance']
    if short > 0:
        charge(participant['id'], participant['pmt'], short)
 
    ntips = 0 
    for tip in tips:
        if tip['amount'] == 0:
            continue
        if not transfer(participant['id'], tip['tippee'], tip['amount']):
            # The transfer failed due to a lack of funds for the 
            # participant. Don't try any further transfers.
            log("FAILURE: $%s from %s to %s." % (tip['amount'], participant['id'], tip['tippee']))
            break
        log("SUCCESS: $%s from %s to %s." % (tip['amount'], participant['id'], tip['tippee']))
        ntips += 1


    # Update stats.
    # =============

    STATS = """\

        UPDATE paydays 
           SET nparticipants = nparticipants + 1
             , ntippers = ntippers + %s
             , ntips = ntips + %s
         WHERE ts_end='1970-01-01T00:00:00+00'::timestamptz
     RETURNING id

    """
    assert_one_payday(db.fetchone(STATS, (1 if ntips > 0 else 0, ntips)))
Esempio n. 5
0
def payday_one(payday_start, participant):
    """Given one participant record, pay their day.

    Charge each participants' credit card if needed before transfering money
    between Gittip accounts.
 
    """
    tips, total = get_tips_and_total(participant['id'],
                                     for_payday=payday_start)
    typecheck(total, decimal.Decimal)
    short = total - participant['balance']
    if short > 0:
        charge(participant['id'], participant['pmt'], short)

    ntips = 0
    for tip in tips:
        if tip['amount'] == 0:
            continue
        if not transfer(participant['id'], tip['tippee'], tip['amount']):
            # The transfer failed due to a lack of funds for the
            # participant. Don't try any further transfers.
            log("FAILURE: $%s from %s to %s." %
                (tip['amount'], participant['id'], tip['tippee']))
            break
        log("SUCCESS: $%s from %s to %s." %
            (tip['amount'], participant['id'], tip['tippee']))
        ntips += 1

    # Update stats.
    # =============

    STATS = """\

        UPDATE paydays 
           SET nparticipants = nparticipants + 1
             , ntippers = ntippers + %s
             , ntips = ntips + %s
         WHERE ts_end='1970-01-01T00:00:00+00'::timestamptz
     RETURNING id

    """
    assert_one_payday(db.fetchone(STATS, (1 if ntips > 0 else 0, ntips)))
Esempio n. 6
0
    def genparticipants(self, ts_start, for_payday):
        """Generator to yield participants with tips and total.

        We re-fetch participants each time, because the second time through
        we want to use the total obligations they have for next week, and
        if we pass a non-False for_payday to get_tips_and_total then we
        only get unfulfilled tips from prior to that timestamp, which is
        none of them by definition.

        If someone changes tips after payout starts, and we crash during
        payout, then their new tips_and_total will be used on the re-run.
        That's okay.

        """
        for participant in self.get_participants(ts_start):
            tips, total = get_tips_and_total( participant['id']
                                            , for_payday=for_payday
                                            , db=self.db
                                             )
            typecheck(total, Decimal)
            yield(participant, tips, total)
Esempio n. 7
0
    def charge_and_or_transfer(self, ts_start, participant):
        """Given one participant record, pay their day.

        Charge each participants' credit card if needed before transfering
        money between Gittip accounts.

        """
        tips, total = get_tips_and_total( participant['id']
                                        , for_payday=ts_start
                                        , db=self.db
                                         )
        typecheck(total, Decimal)
        short = total - participant['balance']
        if short > 0:

            # The participant's Gittip account is short the amount needed to
            # fund all their tips. Let's try pulling in money from their credit
            # card. If their credit card fails we'll forge ahead, in case they
            # have a positive Gittip balance already that can be used to fund
            # at least *some* tips. The charge method will have set
            # last_bill_result to a non-empty string if the card did fail.

            self.charge( participant['id']
                       , participant['balanced_account_uri']
                       , participant['stripe_customer_id']
                       , short
                        )

        nsuccessful_tips = 0
        for tip in tips:
            result = self.tip(participant, tip, ts_start)
            if result >= 0:
                nsuccessful_tips += result
            else:
                break

        self.mark_participant(nsuccessful_tips)
Esempio n. 8
0
def payday_one(payday_start, participant):
    """Given one participant record, pay their day.

    Charge each participants' credit card if needed before transfering money
    between Gittip accounts.
 
    """
    tips, total = get_tips_and_total( participant['id']
                                    , for_payday=payday_start
                                     )
    typecheck(total, decimal.Decimal)
    short = total - participant['balance']
    if short > 0:

        # The participant's Gittip account is short the amount needed to fund
        # all their tips. Let's try pulling in money from their credit card. If
        # their credit card fails we'll forge ahead, in case they have a
        # positive Gittip balance already that can be used to fund at least
        # *some* tips. The charge method will have set last_bill_result to a
        # non-empty string if the card did fail.

        charge(participant['id'], participant['stripe_customer_id'], short)
 
    ntips = 0 
    for tip in tips:
        msg = "$%s from %s to %s." 
        msg %= (tip['amount'], participant['id'], tip['tippee'])

        if tip['amount'] == 0:

            # The tips table contains a record for every time you click a tip
            # button. So if you click $0.08 then $0.64 then $0.00, that
            # generates three entries. We are looking at the last entry here, 
            # and it's zero.

            continue

        claimed_time = tip['claimed_time']
        if claimed_time is None or claimed_time > payday_start:

            # Gittip is opt-in. We're only going to collect money on a person's
            # behalf if they opted-in by claiming their account before the
            # start of this payday.

            log("SKIPPED: %s" % msg)
            continue

        if not transfer(participant['id'], tip['tippee'], tip['amount']):

            # The transfer failed due to a lack of funds for the participant.
            # Don't try any further transfers.

            log("FAILURE: %s" % msg)
            break
        log("SUCCESS: %s" % msg)
        ntips += 1


    # Update stats.
    # =============

    STATS = """\

        UPDATE paydays 
           SET nparticipants = nparticipants + 1
             , ntippers = ntippers + %s
             , ntips = ntips + %s
         WHERE ts_end='1970-01-01T00:00:00+00'::timestamptz
     RETURNING id

    """
    assert_one_payday(db.fetchone(STATS, (1 if ntips > 0 else 0, ntips)))