def ipn(): """Endpoint that receives Instant Payment Notifications (IPNs) from PayPal. Specifications are available at https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/. """ request.parameter_storage_class = ImmutableOrderedMultiDict # Checking if data is legit paypal_url = PAYPAL_URL_PRIMARY if current_app.config[ 'PAYMENT_PRODUCTION'] else PAYPAL_URL_SANDBOX verify_args = chain(IPN_VERIFY_EXTRA_PARAMS, request.form.iteritems()) verify_string = u'&'.join( (u'%s=%s' % (param, value) for param, value in verify_args)) verification_response = requests.post(paypal_url, data=verify_string.encode('utf-8')) # Some payment options don't return payment_status value. if 'payment_status' not in request.form: logging.warn('PayPal IPN: payment_status is missing.') return '', 200 if verification_response.text == 'VERIFIED': Donation.process_paypal_ipn(request.form) return '', 200
def test_verify_and_log_wepay_checkout(self): self.assertTrue( Donation.verify_and_log_wepay_checkout(12345, 'Tester', False, True)) # Donation should be in the DB now self.assertEqual(Donation.query.all()[0].transaction_id, str(12345))
def ipn(): """Endpoint that receives Instant Payment Notifications (IPNs) from PayPal. Specifications are available at https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/. """ request.parameter_storage_class = ImmutableOrderedMultiDict # Checking if data is legit paypal_url = PAYPAL_URL_PRIMARY if current_app.config['PAYMENT_PRODUCTION'] else PAYPAL_URL_SANDBOX verify_args = chain(IPN_VERIFY_EXTRA_PARAMS, request.form.iteritems()) verify_string = u'&'.join((u'%s=%s' % (param, value) for param, value in verify_args)) verification_response = requests.post(paypal_url, data=verify_string.encode('utf-8')) if verification_response.text == 'VERIFIED': Donation.process_paypal_ipn(request.form) return '', 200
def test_get_by_transaction_id(self): new = Donation() new.first_name = u'Tester' new.last_name = u'Testing' new.email = u'*****@*****.**' new.transaction_id = u'TEST' new.amount = 42.50 db.session.add(new) db.session.commit() result = Donation.get_by_transaction_id(u'TEST') self.assertIsNotNone(result) bad_result = Donation.get_by_transaction_id(u'MISSING') self.assertIsNone(bad_result)
def test_process_paypal_ipn(self): # This is not a complete list: good_form = { 'first_name': u'Tester', 'last_name': u'Testing', 'custom': u'tester', # MusicBrainz username 'payer_email': u'*****@*****.**', 'receiver_email': current_app.config['PAYPAL_PRIMARY_EMAIL'], 'business': u'*****@*****.**', 'address_street': u'1 Main St', 'address_city': u'San Jose', 'address_state': u'CA', 'address_country': u'United States', 'address_zip': u'95131', 'mc_gross': u'42.50', 'mc_fee': u'1', 'txn_id': u'TEST1', 'payment_status': u'Completed', # Additional variables: 'option_name1': u'anonymous', 'option_selection1': u'yes', 'option_name2': u'contact', 'option_selection2': u'yes', } Donation.process_paypal_ipn(good_form) # Donation should be in the DB now self.assertEqual(len(Donation.query.all()), 1) self.assertEqual(Donation.query.all()[0].transaction_id, 'TEST1') relatively_bad_form = good_form relatively_bad_form['txn_id'] = 'TEST2' relatively_bad_form['mc_gross'] = '0.49' Donation.process_paypal_ipn(relatively_bad_form) # There should still be one recorded donation self.assertEqual(len(Donation.query.all()), 1) bad_form = good_form relatively_bad_form['txn_id'] = 'TEST3' bad_form['business'] = current_app.config['PAYPAL_BUSINESS'] Donation.process_paypal_ipn(bad_form) # There should still be one recorded donation self.assertEqual(len(Donation.query.all()), 1) super_bad_form = good_form relatively_bad_form['txn_id'] = 'TEST4' super_bad_form[ 'payment_status'] = 'Refunded' # What kind of monster would do that?! Donation.process_paypal_ipn(super_bad_form) # There should still be one recorded donation self.assertEqual(len(Donation.query.all()), 1)
def donors(): page = int(request.args.get('page', default=1)) if page < 1: return redirect(url_for('.donors')) limit = 30 offset = (page - 1) * limit order = request.args.get('order', default='date') if order == 'date': count, donations = Donation.get_recent_donations(limit=limit, offset=offset) elif order == 'amount': count, donations = Donation.get_biggest_donations(limit=limit, offset=offset) else: return redirect(url_for('.donors')) last_page = int(ceil(count / limit)) if last_page != 0 and page > last_page: return redirect(url_for('.donors', page=last_page)) return render_template('donations/donors.html', donations=donations, page=page, last_page=last_page, order=order)
def test_process_paypal_ipn(self): # This is not a complete list: good_form = { 'first_name': u'Tester', 'last_name': u'Testing', 'custom': u'tester', # MusicBrainz username 'payer_email': u'*****@*****.**', 'receiver_email': current_app.config['PAYPAL_PRIMARY_EMAIL'], 'business': u'*****@*****.**', 'address_street': '1 Main St', 'address_city': u'San Jose', 'address_state': u'CA', 'address_country': u'United States', 'address_zip': u'95131', 'mc_gross': u'42.50', 'mc_fee': u'1', 'txn_id': u'TEST1', 'payment_status': u'Completed', # Additional variables: 'option_name1': u'anonymous', 'option_selection1': u'yes', 'option_name2': u'contact', 'option_selection2': u'yes', } Donation.process_paypal_ipn(good_form) # Donation should be in the DB now self.assertEqual(len(Donation.query.all()), 1) self.assertEqual(Donation.query.all()[0].transaction_id, 'TEST1') relatively_bad_form = good_form relatively_bad_form['txn_id'] = 'TEST2' relatively_bad_form['mc_gross'] = '0.49' Donation.process_paypal_ipn(relatively_bad_form) # There should still be one recorded donation self.assertEqual(len(Donation.query.all()), 1) bad_form = good_form relatively_bad_form['txn_id'] = 'TEST3' bad_form['business'] = current_app.config['PAYPAL_BUSINESS'] Donation.process_paypal_ipn(bad_form) # There should still be one recorded donation self.assertEqual(len(Donation.query.all()), 1) super_bad_form = good_form relatively_bad_form['txn_id'] = 'TEST4' super_bad_form['payment_status'] = 'Refunded' # What kind of monster would do that?! Donation.process_paypal_ipn(super_bad_form) # There should still be one recorded donation self.assertEqual(len(Donation.query.all()), 1)
def test_get_by_transaction_id(self): new = Donation() new.first_name = 'Tester' new.last_name = 'Testing' new.email = '*****@*****.**' new.transaction_id = 'TEST' new.amount = 42.50 db.session.add(new) db.session.commit() result = Donation.get_by_transaction_id('TEST') self.assertIsNotNone(result) bad_result = Donation.get_by_transaction_id('MISSING') self.assertIsNone(bad_result)
def donate(): """Donation page for Stripe. Stripe API reference for Python can be found at https://stripe.com/docs/api/python. """ form = DonationForm() if not form.validate(): return redirect(url_for('donations.error')) if current_app.config['PAYMENT_PRODUCTION']: stripe.api_key = current_app.config['STRIPE_KEYS']['SECRET'] else: stripe.api_key = current_app.config['STRIPE_TEST_KEYS']['SECRET'] # Get the credit card details submitted by the form token = request.form['stripeToken'] # Create the charge on Stripe's servers - this will charge the donor's card try: charge = stripe.Charge.create( amount=int(form.amount.data * 100), # amount in cents currency='USD', card=token, description='Donation to MetaBrainz Foundation', metadata={ 'email': request.form['stripeEmail'], 'editor': form.editor.data, 'anonymous': form.anonymous.data, 'can_contact': form.can_contact.data, }, ) except stripe.CardError: # The card has been declined return redirect(url_for('donations.error')) Donation.log_stripe_charge(charge) return redirect(url_for('donations.complete'))
def ipn(): """Endpoint that receives Instant Payment Notifications (IPNs) from WePay. More info is available at https://www.wepay.com/developer/reference/ipn. """ # Checking the type of object (should be `checkout`) if 'checkout_id' in request.form: checkout_id = request.form['checkout_id'] else: # No need to return any errors in this case # TODO: Add logging there. return 'Invalid object_id.', 200 # Getting additional info that was passed with callback_uri during payment creation editor = request.args['editor'] anonymous = request.args['anonymous'] can_contact = request.args['can_contact'] result = Donation.verify_and_log_wepay_checkout(checkout_id, editor, anonymous, can_contact) if result is True: return "Recorded." return '', 200
def nag_check(editor): a, b = Donation.get_nag_days(editor) return '%s,%s\n' % (a, b)
def test_log_stripe_charge(self): # Function should execute without any exceptions charge = convert_to_stripe_object( { "id": u"ch_15AjX1F21qH57QtHT6avvqrM", "object": u"charge", "created": 1418829367, "livemode": False, "paid": True, "status": u"succeeded", "amount": 99999900, "currency": u"usd", "refunded": False, "source": { "id": u"card_15AjWxF21qH57QtHHVNgaHOP", "object": u"card", "last4": u"4242", "brand": u"Visa", "funding": u"credit", "exp_month": 11, "exp_year": 2016, "country": u"US", "name": u"Uh Oh", "address_line1": u"test 12", "address_line2": None, "address_city": u"Schenectady", "address_state": u"NY", "address_zip": u"12345", "address_country": u"United States", "cvc_check": u"pass", "address_line1_check": u"pass", "address_zip_check": u"pass", "dynamic_last4": None, "metadata": {}, "customer": None }, "captured": True, "balance_transaction": u"txn_159qthF21qH57QtHBksXX3tN", "failure_message": None, "failure_code": None, "amount_refunded": 0, "customer": None, "invoice": None, "description": u"Donation to MetaBrainz Foundation", "dispute": None, "metadata": { "anonymous": u"True", # passed as a string "can_contact": u"False", # passed as a string "email": u"*****@*****.**", "editor": u"null" }, "statement_descriptor": None, "fraud_details": {}, "receipt_email": None, "receipt_number": None, "shipping": None, "application_fee": None, "refunds": { "object": "list", "total_count": 0, "has_more": False, "url": "/v1/charges/ch_15AjX1F21qH57QtHT6avvqrM/refunds", "data": [] } }, api_key=None, account=None ) Donation.log_stripe_charge(charge)
def test_verify_and_log_wepay_checkout(self): self.assertTrue(Donation.verify_and_log_wepay_checkout(12345, 'Tester', False, True)) # Donation should be in the DB now self.assertEqual(Donation.query.all()[0].transaction_id, str(12345))
def test_log_stripe_charge(self): # Function should execute without any exceptions charge = convert_to_stripe_object( { "id": u"ch_15AjX1F21qH57QtHT6avvqrM", "object": u"charge", "created": 1418829367, "livemode": False, "paid": True, "status": u"succeeded", "amount": 99999900, "currency": u"usd", "refunded": False, "source": { "id": u"card_15AjWxF21qH57QtHHVNgaHOP", "object": u"card", "last4": u"4242", "brand": u"Visa", "funding": u"credit", "exp_month": 11, "exp_year": 2016, "country": u"US", "name": u"Uh Oh", "address_line1": u"test 12", "address_line2": None, "address_city": u"Schenectady", "address_state": u"NY", "address_zip": u"12345", "address_country": u"United States", "cvc_check": u"pass", "address_line1_check": u"pass", "address_zip_check": u"pass", "dynamic_last4": None, "metadata": {}, "customer": None }, "captured": True, "balance_transaction": u"txn_159qthF21qH57QtHBksXX3tN", "failure_message": None, "failure_code": None, "amount_refunded": 0, "customer": None, "invoice": None, "description": u"Donation to MetaBrainz Foundation", "dispute": None, "metadata": { "anonymous": u"True", # passed as a string "can_contact": u"False", # passed as a string "email": u"*****@*****.**", "editor": u"null" }, "statement_descriptor": None, "fraud_details": {}, "receipt_email": None, "receipt_number": None, "shipping": None, "application_fee": None, "refunds": { "object": "list", "total_count": 0, "has_more": False, "url": "/v1/charges/ch_15AjX1F21qH57QtHT6avvqrM/refunds", "data": [] } }, api_key=None, account=None) Donation.log_stripe_charge(charge)