예제 #1
0
def generate_donation(
    rand,
    *,
    commentstate='APPROVED',
    donor=None,
    donors=None,
    no_donor=False,
    domain=None,
    event=None,
    min_amount=Decimal('0.01'),
    max_amount=Decimal('1000.00'),
    min_time=None,
    max_time=None,
    readstate='READ',
    transactionstate=None,
):
    donation = Donation()
    donation.amount = random_amount(rand,
                                    min_amount=min_amount,
                                    max_amount=max_amount)
    if not event:
        event = pick_random_instance(rand, Event)
    assert event, 'No event provided and none exist'
    donation.event = event
    if domain:
        donation.domain = domain
    else:
        donation.domain = rand.choice(DonationDomainChoices)[0]
    donation.domainId = str(rand.getrandbits(64))
    donation.fee = (donation.amount * Decimal(0.03)).quantize(
        Decimal('0.01'), rounding=decimal.ROUND_UP)
    donation.comment = random_name(rand, 'Comment')
    donation.commentstate = commentstate
    donation.readstate = readstate
    if not min_time:
        min_time = event.datetime
    if not max_time:
        max_time = min_time + datetime.timedelta(seconds=60 * 60 * 24 * 14)
    donation.timereceived = random_time(rand, min_time, max_time)
    donation.currency = 'USD'
    donation.transactionstate = transactionstate or 'COMPLETED'
    if donation.domain == 'LOCAL':
        assert (donation.transactionstate == 'COMPLETED'
                ), 'Local donations must be specified as COMPLETED'

    if not no_donor:
        if not donor:
            if donors:
                donor = rand.choice(donors)
            else:
                donor = pick_random_instance(rand, Donor)
        assert donor, 'No donor provided and none exist'
        donation.donor = donor
    donation.clean()
    return donation
예제 #2
0
def generate_donation(
    rand,
    *,
    donor=None,
    domain=None,
    event=None,
    min_amount=Decimal('0.01'),
    max_amount=Decimal('1000.00'),
    min_time=None,
    max_time=None,
    donors=None,
    transactionstate=None,
):
    donation = Donation()
    donation.amount = random_amount(rand,
                                    min_amount=min_amount,
                                    max_amount=max_amount)
    if event:
        donation.event = event
    else:
        donation.event = pick_random_instance(rand, Event)
    if domain:
        donation.domain = domain
    else:
        donation.domain = pick_random_element(rand, DonationDomainChoices)[0]
    donation.domainId = str(rand.getrandbits(64))
    donation.fee = (donation.amount * Decimal(0.03)).quantize(
        Decimal('0.01'), rounding=decimal.ROUND_UP)
    donation.comment = random_name(rand, 'Comment')
    donation.commentstate = 'APPROVED'
    donation.readstate = 'READ'
    if not min_time:
        min_time = event.datetime
    if not max_time:
        max_time = min_time + datetime.timedelta(seconds=60 * 60 * 24 * 14)
    donation.timereceived = random_time(rand, min_time, max_time)
    donation.currency = 'USD'
    donation.transactionstate = transactionstate or 'COMPLETED'
    if donation.domain == 'LOCAL':
        assert donation.transactionstate == 'COMPLETED'

    if not donor:
        if donors:
            donor = pick_random_element(rand, donors)
        else:
            donor = pick_random_instance(rand, Donor)
    if not donor:  # no provided donors at all
        donor = generate_donor(rand)
        donor.save()
    donation.donor = donor
    donation.clean()
    return donation
예제 #3
0
def initialize_paypal_donation(ipnObj):
    countrycode = (
        ipnObj.residence_country
        if not ipnObj.address_country_code
        else ipnObj.address_country_code
    )
    defaults = {
        'email': ipnObj.payer_email.lower(),
        'firstname': ipnObj.first_name,
        'lastname': ipnObj.last_name,
        'addressstreet': ipnObj.address_street,
        'addresscity': ipnObj.address_city,
        'addresscountry': Country.objects.get(alpha2=countrycode),
        'addressstate': ipnObj.address_state,
        'addresszip': ipnObj.address_zip,
        'visibility': 'ANON',
    }
    donor, created = Donor.objects.get_or_create(
        paypalemail=ipnObj.payer_email.lower(), defaults=defaults
    )

    fill_donor_address(donor, ipnObj)

    donation = get_ipn_donation(ipnObj)

    if donation:
        if donation.requestedvisibility != 'CURR':
            donor.visibility = donation.requestedvisibility
        if donation.requestedalias and (
            not donor.alias or donation.requestedalias.lower() != donor.alias.lower()
        ):
            foundAResult = False
            currentAlias = donation.requestedalias
            while not foundAResult:
                results = Donor.objects.filter(alias__iexact=currentAlias)
                if results.exists():
                    currentAlias = donation.requestedalias + str(random.getrandbits(8))
                else:
                    foundAResult = True
            donor.alias = currentAlias
        if (
            donation.requestedemail
            and donation.requestedemail != donor.email
            and not Donor.objects.filter(email=donation.requestedemail).exists()
        ):
            donor.email = donation.requestedemail
        if donation.requestedsolicitemail != 'CURR':
            donor.solicitemail = donation.requestedsolicitemail
        donor.save()
    else:
        donation = Donation()
        donation.modcomment = '*Donation for ipn was not found, creating new*'
        donation.event = Event.objects.latest()

    donation.domain = 'PAYPAL'
    donation.domainId = ipnObj.txn_id
    donation.donor = donor
    donation.amount = Decimal(ipnObj.mc_gross)
    donation.currency = ipnObj.mc_currency
    if not donation.timereceived:
        donation.timereceived = datetime.utcnow()
    donation.testdonation = ipnObj.test_ipn
    donation.fee = Decimal(ipnObj.mc_fee or 0)

    # if the user attempted to tamper with the donation amount, remove all bids
    if donation.amount != ipnObj.mc_gross:
        donation.modcomment += (
            '\n*Tampered donation amount from '
            + str(donation.amount)
            + ' to '
            + str(ipnObj.mc_gross)
            + ', removed all bids*'
        )
        donation.amount = ipnObj.mc_gross
        donation.bids.clear()
        viewutil.tracker_log(
            'paypal',
            'Tampered amount detected in donation {0} (${1} -> ${2})'.format(
                donation.id, donation.amount, ipnObj.mc_gross
            ),
            event=donation.event,
        )

    paymentStatus = ipnObj.payment_status.lower()

    if not ipnObj.flag:
        if paymentStatus == 'pending':
            donation.transactionstate = 'PENDING'
        elif (
            paymentStatus == 'completed'
            or paymentStatus == 'canceled_reversal'
            or paymentStatus == 'processed'
        ):
            donation.transactionstate = 'COMPLETED'
        elif (
            paymentStatus == 'refunded'
            or paymentStatus == 'reversed'
            or paymentStatus == 'failed'
            or paymentStatus == 'voided'
            or paymentStatus == 'denied'
        ):
            donation.transactionstate = 'CANCELLED'
        else:
            donation.transactionstate = 'FLAGGED'
            viewutil.tracker_log(
                'paypal',
                'Unknown payment status in donation {0} ({1})'.format(
                    donation.id, paymentStatus
                ),
                event=donation.event,
            )
    else:
        donation.transactionstate = 'FLAGGED'
        viewutil.tracker_log(
            'paypal',
            'IPN object flagged for donation {0} ({1})'.format(
                donation.id, ipnObj.txn_id
            ),
            event=donation.event,
        )

    # Automatically approve anonymous, no-comment donations if an auto-approve
    # threshold is set.
    auto_min = donation.event.auto_approve_threshold
    if auto_min:
        donation.approve_if_anonymous_and_no_comment(auto_min)

    donation.save()
    # I think we only care if the _donation_ was freshly created
    return donation
예제 #4
0
def sync_event_donations(event):
    """Sync donations from a Tiltify campaign with an event in our system.

    :param event: Event record to merge.
    :type event: tracker.models.Event
    :return: Number of donations updated.
    :rtype: int
    """
    if not event.tiltify_api_key:
        raise ValidationError("API key not set")

    # Get campaign data to update start date for event.
    user = get_user_data()
    t_campaign = get_campaign_data(event.tiltify_api_key, user)

    start = datetime.datetime.fromtimestamp(t_campaign['startsAt'] / 1000,
                                            datetime.timezone.utc)
    if start:
        event.datetime = start

    event.save()

    # Get donations from Tiltify API.
    t_donations = get_donation_data(t_campaign)
    num_donations = 0

    for t_donation in t_donations:
        # Get donor based on alias.
        donor = None
        if t_donation['name'] and t_donation['name'] != 'Anonymous':
            try:
                donor = Donor.objects.get(alias__iexact=t_donation['name'])
            except Donor.DoesNotExist:
                donor = Donor(email=t_donation['name'],
                              alias=t_donation['name'])
                donor.save()

        # Get donation based on payment reference.
        try:
            donation = Donation.objects.select_for_update().get(
                domain='TILTIFY', domainId=t_donation['id'])
        except Donation.DoesNotExist:
            donation = Donation(event=event,
                                domain='TILTIFY',
                                domainId=t_donation['id'],
                                readstate='PENDING',
                                commentstate='PENDING',
                                donor=donor)

        # Make sure this donation wasn't already imported for a different event.
        if donation.event != event:
            raise ValidationError(
                "Donation {!r} already exists for a different event".format(
                    donation.domainId))

        donation.transactionstate = 'COMPLETED'
        donation.amount = t_donation['amount']
        donation.currency = event.paypalcurrency
        donation.timereceived = datetime.datetime.fromtimestamp(
            t_donation['completedAt'] / 1000, datetime.timezone.utc)
        donation.testdonation = event.usepaypalsandbox

        # Comment might be null from Tiltify, but can't be null on our end.
        if t_donation['comment']:
            donation.comment = t_donation['comment']
        else:
            donation.comment = ''

        donation.save()
        num_donations += 1

    return num_donations