def ipn(request): ipnObj = None if request.method == 'GET' or len(request.POST) == 0: return views_common.tracker_response(request, "tracker/badobject.html", {}) try: ipnObj = paypalutil.create_ipn(request) ipnObj.save() donation = paypalutil.initialize_paypal_donation(ipnObj) donation.save() if donation.transactionstate == 'PENDING': reasonExplanation, ourFault = paypalutil.get_pending_reason_details( ipnObj.pending_reason) if donation.event.pendingdonationemailtemplate: formatContext = { 'event': donation.event, 'donation': donation, 'donor': donation.donor, 'pending_reason': ipnObj.pending_reason, 'reason_info': reasonExplanation if not ourFault else '', } post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender, template=donation.event.pendingdonationemailtemplate, context=formatContext) # some pending reasons can be a problem with the receiver account, we should keep track of them if ourFault: paypalutil.log_ipn(ipnObj, 'Unhandled pending error') elif donation.transactionstate == 'COMPLETED': if donation.event.donationemailtemplate != None: formatContext = { 'donation': donation, 'donor': donation.donor, 'event': donation.event, 'prizes': viewutil.get_donation_prize_info(donation), } post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender, template=donation.event.donationemailtemplate, context=formatContext) eventutil.post_donation_to_postbacks(donation) elif donation.transactionstate == 'CANCELLED': # eventually we may want to send out e-mail for some of the possible cases # such as payment reversal due to double-transactions (this has happened before) paypalutil.log_ipn(ipnObj, 'Cancelled/reversed payment') except Exception as inst: # just to make sure we have a record of it somewhere print("ERROR IN IPN RESPONSE, FIX IT") if ipnObj: paypalutil.log_ipn(ipnObj, "{0} \n {1}. POST data : {2}".format( inst, traceback.format_exc(inst), request.POST)) else: viewutil.tracker_log('paypal', 'IPN creation failed: {0} \n {1}. POST data : {2}'.format( inst, traceback.format_exc(inst), request.POST)) return HttpResponse("OKAY")
def test_unicode_decode_error_caught(self): donation = Donation.objects.create( timereceived=datetime.datetime(2018, 1, 1), comment='é', amount=Decimal(1.5), domain='PAYPAL', donor=self.donor, event=self.event, ) eventutil.post_donation_to_postbacks(donation) log = Log.objects.filter(category='postback_url', event=self.event).last() assert "UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)" in log.message
def test_unicode_decode_error_caught(self): donation = Donation.objects.create( timereceived=datetime.datetime(2018, 1, 1), comment='é', amount=Decimal(1.5), domain='PAYPAL', donor=self.donor, event=self.event, ) eventutil.post_donation_to_postbacks(donation) log = Log.objects.filter( category='postback_url', event=self.event).last() assert "UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)" in log.message
def test_request_made(self): responses.add(responses.GET, 'https://example.com', status=200) donation = Donation.objects.create( timereceived=datetime.datetime(2018, 1, 1), comment='', amount=Decimal(1.5), domain='PAYPAL', donor=self.donor, event=self.event, ) eventutil.post_donation_to_postbacks(donation) assert len(responses.calls) == 1 assert responses.calls[0].request.url == 'https://example.com/?comment=&amount=1.5&timereceived=2018-01-01+00%3A00%3A00&donor__visibility=FIRST&domain=PAYPAL&id=1&donor__visiblename=%28No+Name%29' assert responses.calls[0].response.status_code == 200
def test_request_made(self): responses.add(responses.GET, 'https://example.com', status=200) donation = Donation.objects.create( timereceived=datetime.datetime(2018, 1, 1), comment='', amount=Decimal(1.5), domain='PAYPAL', donor=self.donor, event=self.event, ) eventutil.post_donation_to_postbacks(donation) assert len(responses.calls) == 1 assert responses.calls[ 0].request.url == 'https://example.com/?comment=&amount=1.5&timereceived=2018-01-01+00%3A00%3A00&donor__visibility=FIRST&domain=PAYPAL&id=1&donor__visiblename=%28No+Name%29' assert responses.calls[0].response.status_code == 200
def commit_scraptf_donation(self, donation): ''' From a ScrapTF donation, create a Donor and Donation. If incentives are present, create all DonationBids and BidSuggestions as well. We try very hard to ensure everything is valid for insertion. If anything doesn't look right, we fail the entire transaction. ''' # Create the Donor user = donation['user'] email = donation.get('email') if not email: raise Exception('Donation is missing an email.') validate_email(email) alias = user.get('name', '')[:DONOR_ALIAS_MAX_LENGTH] donor = Donor(email=email, alias=alias, visibility='ALIAS') # The only unique constraint on Donors is paypalemail, which is # not a concern here, so forget about IntegrityError. donor.full_clean() donor.save() # Create the Donation domain_id = donation['id'] amount = Decimal(str(donation['cash_value'])) time = datetime.fromtimestamp(donation['confirmed_time'], tz=pytz.utc) comment = donation.get('message') commentstate = 'PENDING' if comment else 'ABSENT' steamid = user.get('steamid') d = Donation(donor=donor, domain='SCRAPTF', domainId=domain_id, transactionstate='COMPLETED', amount=amount, timereceived=time, currency='USD', comment=comment, commentstate=commentstate, requestedalias=alias, requestedemail=email, steamid=steamid) try: d.full_clean() d.save() except IntegrityError: raise Exception('Donation already exists') # Only proceed if incentives are present incentives = donation.get('incentives') if not incentives: return log.info('Donation has incentives, creating them now.', incentives_total=len(incentives)) # Ensure the incentives don't exceed the total donation amount inc_amounts = [Decimal(inc['amount']) for inc in incentives] inc_total = sum(inc_amounts) if inc_total > amount: raise Exception('sum of incentive amounts exceeds donation amount') for inc in incentives: # First grab the bid to make sure it exists bid = Bid.objects.get(pk=inc['incentive']) dbid = DonationBid(donation=d, bid=bid, amount=Decimal(inc['amount'])) dbid.full_clean() dbid.save() # If the incentive has a custom value, create a BidSuggestion suggestion = inc.get('custom') if suggestion: s = BidSuggestion(bid=bid, name=suggestion) s.full_clean() s.save() eventutil.post_donation_to_postbacks(d)