def after_model_change(self, form, new_donation, is_created): if is_created: send_receipt( email=new_donation.email, date=new_donation.payment_date, amount=new_donation.amount, name='%s %s' % (new_donation.first_name, new_donation.last_name), is_donation=new_donation.is_donation, editor_name=new_donation.editor_name, )
def log_stripe_charge(cls, charge): """Log successful Stripe charge. Args: charge: The charge object from Stripe. More information about it is available at https://stripe.com/docs/api/python#charge_object. """ logging.debug('Processing Stripe charge...') bt = stripe.BalanceTransaction.retrieve(charge.balance_transaction) if bt.currency.lower() not in SUPPORTED_CURRENCIES: logging.warning("Unsupported currency: ", bt.currency) return new_donation = cls( first_name=charge.source.name, last_name='', amount=bt.net / 100, # cents should be converted fee=bt.fee / 100, # cents should be converted currency=bt.currency.lower(), transaction_id=charge.id, payment_method=PAYMENT_METHOD_STRIPE, is_donation=charge.metadata.is_donation, email=charge.metadata.email, address_street=charge.source.address_line1, address_city=charge.source.address_city, address_state=charge.source.address_state, address_postcode=charge.source.address_zip, address_country=charge.source.address_country, ) if charge.metadata.is_donation is True or charge.metadata.is_donation == "True": new_donation.can_contact = charge.metadata.can_contact == u'True' new_donation.anonymous = charge.metadata.anonymous == u'True' if 'editor' in charge.metadata: new_donation.editor_name = charge.metadata.editor else: # Organization payment new_donation.invoice_number = charge.metadata.invoice_number db.session.add(new_donation) db.session.commit() logging.info('Stripe: Payment added. ID: %s.', new_donation.id) send_receipt( email=new_donation.email, date=new_donation.payment_date, amount=new_donation.amount, name=new_donation.first_name, # Last name is not used with Stripe is_donation=new_donation.is_donation, editor_name=new_donation.editor_name, )
def log_stripe_charge(cls, charge): """Log successful Stripe charge. Args: charge: The charge object from Stripe. More information about it is available at https://stripe.com/docs/api/python#charge_object. """ logging.debug('Processing Stripe charge...') bt = stripe.BalanceTransaction.retrieve(charge.balance_transaction) new_donation = cls( first_name=charge.source.name, last_name='', amount=bt.net / 100, # cents should be converted fee=bt.fee / 100, # cents should be converted transaction_id=charge.id, payment_method=PAYMENT_METHOD_STRIPE, is_donation=charge.metadata.is_donation, email=charge.metadata.email, address_street=charge.source.address_line1, address_city=charge.source.address_city, address_state=charge.source.address_state, address_postcode=charge.source.address_zip, address_country=charge.source.address_country, ) if charge.metadata.is_donation is True or charge.metadata.is_donation == "True": new_donation.can_contact = charge.metadata.can_contact == u'True' new_donation.anonymous = charge.metadata.anonymous == u'True' if 'editor' in charge.metadata: new_donation.editor_name = charge.metadata.editor else: # Organization payment new_donation.invoice_number = charge.metadata.invoice_number db.session.add(new_donation) db.session.commit() logging.info('Stripe: Payment added. ID: %s.', new_donation.id) send_receipt( email=new_donation.email, date=new_donation.payment_date, amount=new_donation.amount, name=new_donation.first_name, # Last name is not used with Stripe is_donation=new_donation.is_donation, editor_name=new_donation.editor_name, )
def verify_and_log_wepay_checkout(cls, checkout_id, is_donation, editor=None, anonymous=None, can_contact=None, invoice_number=None): logging.debug('Processing WePay checkout...') # Looking up updated information about the object wepay = WePay(production=current_app.config['PAYMENT_PRODUCTION'], access_token=current_app.config['WEPAY_ACCESS_TOKEN']) details = wepay.call('/checkout', {'checkout_id': checkout_id}) if 'error' in details: logging.warning('WePay: Error: %s', details['error_description']) return False if 'gross' not in details: logging.warning('WePay: The total dollar amount paid is missing') return False if details['gross'] < 0.50: # Tiny donation logging.info('WePay: Tiny payment ($%s).', details['gross']) return True if details['state'] in ['settled', 'captured']: # Payment has been received # Checking that txn_id has not been previously processed if cls.get_by_transaction_id(details['checkout_id']) is not None: logging.info('WePay: Transaction ID %s has been used before.', details['checkout_id']) return new_payment = cls( is_donation=is_donation, first_name=details['payer_name'], last_name='', email=details['payer_email'], amount=details['gross'] - details['fee'], fee=details['fee'], transaction_id=checkout_id, payment_method=PAYMENT_METHOD_WEPAY, ) if is_donation: new_payment.editor_name = editor new_payment.can_contact = can_contact new_payment.anonymous = anonymous else: new_payment.invoice_number = invoice_number if 'shipping_address' in details: address = details['shipping_address'] new_payment.address_street = "%s\n%s" % (address['address1'], address['address2']) new_payment.address_city = address['city'] if 'state' in address: # US address new_payment.address_state = address['state'] else: new_payment.address_state = address['region'] if 'zip' in address: # US address new_payment.address_postcode = address['zip'] else: new_payment.address_postcode = address['postcode'] db.session.add(new_payment) db.session.commit() logging.info('WePay: Payment added. ID: %s.', new_payment.id) send_receipt( email=new_payment.email, date=new_payment.payment_date, amount=new_payment.amount, name='%s %s' % (new_payment.first_name, new_payment.last_name), is_donation=new_payment.is_donation, editor_name=new_payment.editor_name, ) elif details['state'] in ['authorized', 'reserved']: # Payment is pending logging.info('WePay: Payment is pending. State: "%s".', details['state']) pass elif details['state'] in [ 'expired', 'cancelled', 'failed', 'refunded', 'chargeback' ]: # Payment has failed logging.warning('WePay: Payment has failed. State: "%s".', details['state']) pass else: # Unknown status logging.warning('WePay: Unknown status.') return False return True
def process_paypal_ipn(cls, form): """Processor for PayPal IPNs (Instant Payment Notifications). Should be used only after IPN request is verified. See PayPal documentation for more info about the process. Args: form: The form parameters from IPN request that contains IPN variables. See https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNandPDTVariables/ for more info about them. """ logging.debug('Processing PayPal IPN...') # Only processing completed donations if form['payment_status'] != 'Completed': logging.info('PayPal: Payment not completed. Status: "%s".', form['payment_status']) return # We shouldn't process transactions to address for payments # TODO: Clarify what this address is if form['business'] == current_app.config['PAYPAL_BUSINESS']: logging.info('PayPal: Recieved payment to address for payments.') return if form['receiver_email'] != current_app.config['PAYPAL_PRIMARY_EMAIL']: logging.warning('PayPal: Not primary email. Got "%s".', form['receiver_email']) return if float(form['mc_gross']) < 0.50: # Tiny donation logging.info('PayPal: Tiny donation ($%s).', form['mc_gross']) return # Checking that txn_id has not been previously processed if cls.get_by_transaction_id(form['txn_id']) is not None: logging.info('PayPal: Transaction ID %s has been used before.', form['txn_id']) return if 'option_name3' in form and form['option_name3'] == "is_donation" \ and form['option_selection3'] != 'yes': is_donation = False else: # If third option (whether it is donation or not) is not specified, assuming # that it is donation. This is done to support old IPN messages. is_donation = True new_payment = cls( is_donation=is_donation, first_name=form['first_name'], last_name=form['last_name'], email=form['payer_email'], address_street=form.get('address_street'), address_city=form.get('address_city'), address_state=form.get('address_state'), address_postcode=form.get('address_zip'), address_country=form.get('address_country'), amount=float(form['mc_gross']) - float(form['mc_fee']), fee=float(form['mc_fee']), transaction_id=form['txn_id'], payment_method=PAYMENT_METHOD_PAYPAL, ) if is_donation: new_payment.editor_name = form.get('custom') if 'option_name1' in form and 'option_name2' in form: if (form['option_name1'] == 'anonymous' and form['option_selection1'] == 'yes') or \ (form['option_name2'] == 'anonymous' and form['option_selection2'] == 'yes') or \ form['option_name2'] == 'yes': new_payment.anonymous = True if (form['option_name1'] == 'contact' and form['option_selection1'] == 'yes') or \ (form['option_name2'] == 'contact' and form['option_selection2'] == 'yes') or \ form['option_name2'] == 'yes': new_payment.can_contact = True else: if 'option_name4' in form and form[ 'option_name4'] == 'invoice_number': new_payment.invoice_number = int(form.get("option_selection4")) else: logging.warning( "PayPal: Can't find invoice number if organization payment." ) db.session.add(new_payment) db.session.commit() logging.info('PayPal: Payment added. ID: %s.', new_payment.id) send_receipt( email=new_payment.email, date=new_payment.payment_date, amount=new_payment.amount, name='%s %s' % (new_payment.first_name, new_payment.last_name), is_donation=new_payment.is_donation, editor_name=new_payment.editor_name, )
def verify_and_log_wepay_checkout(cls, checkout_id, is_donation, editor=None, anonymous=None, can_contact=None, invoice_number=None): logging.debug('Processing WePay checkout...') # Looking up updated information about the object wepay = WePay(production=current_app.config['PAYMENT_PRODUCTION'], access_token=current_app.config['WEPAY_ACCESS_TOKEN']) details = wepay.call('/checkout', {'checkout_id': checkout_id}) if 'error' in details: logging.warning('WePay: Error: %s', details['error_description']) return False if 'gross' not in details: logging.warning('WePay: The total dollar amount paid is missing') return False if details['gross'] < 0.50: # Tiny donation logging.info('WePay: Tiny payment ($%s).', details['gross']) return True if details['state'] in ['settled', 'captured']: # Payment has been received # Checking that txn_id has not been previously processed if cls.get_by_transaction_id(details['checkout_id']) is not None: logging.info('WePay: Transaction ID %s has been used before.', details['checkout_id']) return new_payment = cls( is_donation=is_donation, first_name=details['payer_name'], last_name='', email=details['payer_email'], amount=details['gross'] - details['fee'], fee=details['fee'], transaction_id=checkout_id, payment_method=PAYMENT_METHOD_WEPAY, ) if is_donation: new_payment.editor_name = editor new_payment.can_contact = can_contact new_payment.anonymous = anonymous else: new_payment.invoice_number = invoice_number if 'shipping_address' in details: address = details['shipping_address'] new_payment.address_street = "%s\n%s" % (address['address1'], address['address2']) new_payment.address_city = address['city'] if 'state' in address: # US address new_payment.address_state = address['state'] else: new_payment.address_state = address['region'] if 'zip' in address: # US address new_payment.address_postcode = address['zip'] else: new_payment.address_postcode = address['postcode'] db.session.add(new_payment) db.session.commit() logging.info('WePay: Payment added. ID: %s.', new_payment.id) send_receipt( email=new_payment.email, date=new_payment.payment_date, amount=new_payment.amount, name='%s %s' % (new_payment.first_name, new_payment.last_name), is_donation=new_payment.is_donation, editor_name=new_payment.editor_name, ) elif details['state'] in ['authorized', 'reserved']: # Payment is pending logging.info('WePay: Payment is pending. State: "%s".', details['state']) pass elif details['state'] in ['expired', 'cancelled', 'failed', 'refunded', 'chargeback']: # Payment has failed logging.warning('WePay: Payment has failed. State: "%s".', details['state']) pass else: # Unknown status logging.warning('WePay: Unknown status.') return False return True
def process_paypal_ipn(cls, form): """Processor for PayPal IPNs (Instant Payment Notifications). Should be used only after IPN request is verified. See PayPal documentation for more info about the process. Args: form: The form parameters from IPN request that contains IPN variables. See https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNandPDTVariables/ for more info about them. """ logging.debug('Processing PayPal IPN...') # Only processing completed donations if form['payment_status'] != 'Completed': logging.info('PayPal: Payment not completed. Status: "%s".', form['payment_status']) return # We shouldn't process transactions to address for payments # TODO: Clarify what this address is if form['business'] == current_app.config['PAYPAL_BUSINESS']: logging.info('PayPal: Recieved payment to address for payments.') return if form['receiver_email'] != current_app.config['PAYPAL_PRIMARY_EMAIL']: logging.warning('PayPal: Not primary email. Got "%s".', form['receiver_email']) return if float(form['mc_gross']) < 0.50: # Tiny donation logging.info('PayPal: Tiny donation ($%s).', form['mc_gross']) return # Checking that txn_id has not been previously processed if cls.get_by_transaction_id(form['txn_id']) is not None: logging.info('PayPal: Transaction ID %s has been used before.', form['txn_id']) return if 'option_name3' in form and form['option_name3'] == "is_donation" \ and form['option_selection3'] != 'yes': is_donation = False else: # If third option (whether it is donation or not) is not specified, assuming # that it is donation. This is done to support old IPN messages. is_donation = True new_payment = cls( is_donation=is_donation, first_name=form['first_name'], last_name=form['last_name'], email=form['payer_email'], address_street=form.get('address_street'), address_city=form.get('address_city'), address_state=form.get('address_state'), address_postcode=form.get('address_zip'), address_country=form.get('address_country'), amount=float(form['mc_gross']) - float(form['mc_fee']), fee=float(form['mc_fee']), transaction_id=form['txn_id'], payment_method=PAYMENT_METHOD_PAYPAL, ) if is_donation: new_payment.editor_name = form.get('custom') if 'option_name1' in form and 'option_name2' in form: if (form['option_name1'] == 'anonymous' and form['option_selection1'] == 'yes') or \ (form['option_name2'] == 'anonymous' and form['option_selection2'] == 'yes') or \ form['option_name2'] == 'yes': new_payment.anonymous = True if (form['option_name1'] == 'contact' and form['option_selection1'] == 'yes') or \ (form['option_name2'] == 'contact' and form['option_selection2'] == 'yes') or \ form['option_name2'] == 'yes': new_payment.can_contact = True else: if 'option_name4' in form and form['option_name4'] == 'invoice_number': new_payment.invoice_number = int(form.get("option_selection4")) else: logging.warning("PayPal: Can't find invoice number if organization payment.") db.session.add(new_payment) db.session.commit() logging.info('PayPal: Payment added. ID: %s.', new_payment.id) send_receipt( email=new_payment.email, date=new_payment.payment_date, amount=new_payment.amount, name='%s %s' % (new_payment.first_name, new_payment.last_name), is_donation=new_payment.is_donation, editor_name=new_payment.editor_name, )
def process_paypal_ipn(cls, form): """Processor for PayPal IPNs (Instant Payment Notifications). Should be used only after IPN request is verified. See PayPal documentation for more info about the process. Args: form: The form parameters from IPN request that contains IPN variables. See https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNandPDTVariables/ for more info about them. """ logging.debug('Processing PayPal IPN...') # Only processing completed donations if form['payment_status'] != 'Completed': # TODO(roman): Convert to regular `logging.info` call when such detailed logs # are no longer necessary to capture. get_sentry_client().captureMessage( "PayPal: Payment is not completed", level=logging.INFO, extra={"ipn_content": form}) return account_ids = current_app.config[ 'PAYPAL_ACCOUNT_IDS'] # "currency => account" mapping if form['mc_currency'].lower() not in SUPPORTED_CURRENCIES: logging.warning("PayPal IPN: Unsupported currency", extra={"ipn_content": form}) return # We shouldn't process transactions to address for payments # TODO: Clarify what this address is if form['business'] == current_app.config['PAYPAL_BUSINESS']: logging.info('PayPal: Received payment to address for payments.', extra={"ipn_content": form}) return # Checking if payment was sent to the right account depending on the currency if form['mc_currency'].upper() in account_ids: receiver_email_expected = current_app.config['PAYPAL_ACCOUNT_IDS'][ form['mc_currency'].upper()] if receiver_email_expected != form['receiver_email']: logging.warning("Received payment to an unexpected address", extra={ "currency": form['mc_currency'], "received_to_address": form['receiver_email'], "expected_address": receiver_email_expected, "ipn_content": form, }) if form['receiver_email'] not in account_ids.values(): logging.warning('PayPal: Unexpected receiver email', extra={ "received_to_address": form['receiver_email'], "ipn_content": form, }) if float(form['mc_gross']) < 0.50: # Tiny donation logging.info('PayPal: Tiny donation', extra={"ipn_content": form}) return # Checking that txn_id has not been previously processed if cls.get_by_transaction_id(form['txn_id']) is not None: logging.info('PayPal: Transaction ID has been used before', extra={ "transaction_id": form['txn_id'], "ipn_content": form, }) return options = cls._extract_paypal_ipn_options(form) # If donation option (whether it is donation or not) is not specified, assuming # that this payment is donation. This is done to support old IPN messages. is_donation = options.get("is_donation", "yes") == "yes" new_payment = cls( is_donation=is_donation, first_name=form['first_name'], last_name=form['last_name'], email=form['payer_email'], address_street=form.get('address_street'), address_city=form.get('address_city'), address_state=form.get('address_state'), address_postcode=form.get('address_zip'), address_country=form.get('address_country'), amount=float(form['mc_gross']) - float(form['mc_fee']), fee=float(form['mc_fee']), transaction_id=form['txn_id'], currency=form['mc_currency'].lower(), payment_method=PAYMENT_METHOD_PAYPAL, ) if is_donation: new_payment.editor_name = form.get('custom') anonymous_opt = options.get("anonymous") if anonymous_opt is None: logging.warning("PayPal: Anonymity option is missing", extra={"ipn_content": form}) else: new_payment.anonymous = anonymous_opt == "yes" contact_opt = options.get("contact") if contact_opt is None: logging.warning("PayPal: Contact option is missing", extra={"ipn_content": form}) else: new_payment.can_contact = contact_opt == "yes" else: invoice_num_opt = options.get("invoice_number") if invoice_num_opt is None: logging.warning( "PayPal: Invoice number is missing from org payment", extra={"ipn_content": form}) else: new_payment.invoice_number = int(invoice_num_opt) db.session.add(new_payment) db.session.commit() logging.info('PayPal: Payment added. ID: %s.', new_payment.id) send_receipt( email=new_payment.email, date=new_payment.payment_date, amount=new_payment.amount, name='%s %s' % (new_payment.first_name, new_payment.last_name), is_donation=new_payment.is_donation, editor_name=new_payment.editor_name, )