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
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
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
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