def handleOk(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return

        data['title'] = '%s %s - One-time Offline Donation' % (
            data['first_name'],
            data['last_name'])
        data['secret_key'] = build_secret_key()
        data['stage'] = 'Pledged'
        data['products'] = []
        data['campaign_sf_id'] = self.context.sf_object_id
        data['payment_date'] = datetime.date.today()
        data['transaction_id'] = 'offline:' + data['secret_key']
        data['offline'] = True

        # Add a donation in the current context,
        # using the data from the form
        parent_campaign = self.context
        createContentInContainer(
            parent_campaign,
            'collective.salesforce.fundraising.donation',
            checkConstraints=False, **data)

        # Add the donation to the campaign totals
        # self.context.add_donation(data['amount'])

        IStatusMessage(self.request).add(u'Your offline gift was entered and '
                                         'will be counted in your total '
                                         'raised. The gift and donor contact '
                                         'information will appear in '
                                         '"My Donors" shortly.')
        self.request.response.redirect(parent_campaign.absolute_url())
Beispiel #2
0
    def handleOk(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return

        data['title'] = '%s %s - One-time Offline Donation' % (
            data['first_name'], data['last_name'])
        data['secret_key'] = build_secret_key()
        data['stage'] = 'Pledged'
        data['products'] = []
        data['campaign_sf_id'] = self.context.sf_object_id
        data['payment_date'] = datetime.date.today()
        data['transaction_id'] = 'offline:' + data['secret_key']
        data['offline'] = True

        # Add a donation in the current context,
        # using the data from the form
        parent_campaign = self.context
        createContentInContainer(parent_campaign,
                                 'collective.salesforce.fundraising.donation',
                                 checkConstraints=False,
                                 **data)

        # Add the donation to the campaign totals
        # self.context.add_donation(data['amount'])

        IStatusMessage(self.request).add(u'Your offline gift was entered and '
                                         'will be counted in your total '
                                         'raised. The gift and donor contact '
                                         'information will appear in '
                                         '"My Donors" shortly.')
        self.request.response.redirect(parent_campaign.absolute_url())
    def render(self):
        charge_id = self.request.form.get('charge_id')
        page = self.context.get_fundraising_campaign_page()

        if not charge_id:
            logger.warning('collective.salesforce.fundraising: Record Stripe Donation Error: no charge_id passed in request')
            return self.request.response.redirect(page.absolute_url() + '/@@post_donation_error')

        # Check to make sure a donation does not already exist for this transaction.  If it does, redirect to it.
        pc = getToolByName(self.context, 'portal_catalog')
        res = pc.searchResults(
            portal_type='collective.salesforce.fundraising.donation', 
            transaction_id=charge_id, 
            sort_limit=1
        )
        if len(res) == 1:
            # Redirect to the donation or the honorary-memorial form if needed
            donation = res[0].getObject()

            # If this is an honorary or memorial donation, redirect to the form to provide details
            is_honorary = self.request.form.get('is_honorary', None)
            if is_honorary == 'true' and donation.honorary_type is None:
                redirect_url = '%s/honorary-memorial-donation?key=%s' % (donation.absolute_url(), donation.secret_key)
            else:
                redirect_url = '%s?key=%s' % (donation.absolute_url(), donation.secret_key)
    
            return self.request.response.redirect(redirect_url)

        stripe_util = getUtility(IStripeUtility)
        stripe_api = stripe_util.get_stripe_api(page)

        charge = stripe_api.Charge.retrieve(charge_id, expand=['customer.subscription','invoice'])
        # What happens if there is no charge_id passed or no charge was found?
        if not charge:
            logger.warning('collective.salesforce.fundraising: Record Stripe Donation Error: charge_id %s was not found' % charge_id)
            return self.request.response.redirect(page.absolute_url() + '/@@post_donation_error')


        pc = getToolByName(self.context, 'portal_catalog')

        # Handle Donation Product forms
        product = None
        product_id = self.request.form.get('c_product_id', None)
        c_products = self.request.form.get('c_products', None)
        quantity = self.request.form.get('c_quantity', None)
        pricebook_id = None
        if product_id:
            res = pc.searchResults(sf_object_id=product_id, portal_type='collective.salesforce.fundraising.donationproduct')
            if not res:
                raise ValueError('collective.salesforce.fundraising: Stripe Post Payment Error: Product with ID %s not found' % product_id)
            product = res[0].getObject()

        if product_id or c_products:
            sfbc = getToolByName(self.context, 'portal_salesforcebaseconnector')
            pricebook_id = get_standard_pricebook_id(sfbc)

        # Handle Product Forms with multiple products, each with their own quantity
        products = []
        if c_products:
            for item in c_products.split(','):
                item_id, item_quantity = item.split(':')
                product_res = pc.searchResults(sf_object_id = item_id, portal_type='collective.salesforce.fundraising.donationproduct')
                if not product_res:
                    raise ValueError('collective.salesforce.fundraising: Stripe Post Payment Error: Product with ID %s not found' % item_id)
                products.append({'id': item_id, 'quantity': item_quantity, 'product': product_res[0].getObject()})

        settings = get_settings()

        # lowercase all email addresses to avoid lookup errors if typed with different caps
        email = self.request.form.get('email', None)
        if email:
            email = email.lower()

        first_name = self.request.form.get('first_name', None)
        last_name = self.request.form.get('last_name', None)
        email_opt_in = self.request.form.get('email_signup', None) == 'YES'
        phone = self.request.form.get('phone', None)
        address = self.request.form.get('address', None)
        city = self.request.form.get('city', None)
        state = self.request.form.get('state', None)
        zipcode = self.request.form.get('zip', None)
        country = self.request.form.get('country', None)
        amount = int(float(self.request.form.get('x_amount', None)))

        data = {
            'first_name': first_name,
            'last_name': last_name,
            'email': email,
            'email_opt_in': email_opt_in,
            'phone': phone,
            'address_street': address,
            'address_city': city,
            'address_state': state,
            'address_zip': zipcode,
            'address_country': zipcode,
            'secret_key': build_secret_key(),
            'amount': amount,
            'stage': 'Posted',
            'products': [],
            'campaign_sf_id': page.sf_object_id,
            'source_campaign_sf_id': page.get_source_campaign(),
            'source_url': page.get_source_url(),
            'payment_method': 'Stripe',
        }
      
        # Stripe invoices are only used for recurring so if there is an invoice.
        if charge['invoice']:
            invoice = charge['invoice']
            customer = charge['customer']
            subscription = customer['subscription']
            plan = invoice['lines']['data'][0]['plan']
                
            data['stripe_customer_id'] = customer['id']
            data['stripe_plan_id'] = plan['id']
            data['transaction_id'] = charge['id']
            data['is_test'] = charge['livemode'] == False
            data['title'] = '%s %s - $%i per %s' % (first_name, last_name, amount, plan['interval'])
            data['payment_date'] = stripe_timestamp_to_date(subscription['current_period_start'])
            data['next_payment_date'] = stripe_timestamp_to_date(subscription['current_period_end'])
        else:
            # One time donation
            data['payment_date'] = stripe_timestamp_to_date(charge['created'])
            data['transaction_id'] = charge['id']
            data['is_test'] = charge['livemode'] == False
            data['title'] = '%s %s - $%i One Time Donation' % (first_name, last_name, amount)

        if product_id and product is not None:
            # Set a custom name with the product info and quantity
            data['title'] = '%s %s - %s (Qty %s)' % (first_name, last_name, product.title, quantity)

        elif products:
            # Set a custom name with the product info and quantity
            parent_form = products[0]['product'].get_parent_product_form()
            title = 'Donation'
            if parent_form:
                title = parent_form.title
            data['title'] = '%s %s - %s' % (first_name, last_name, title)
            
        if product_id and product is not None:
            data['products'].append('%s|%s|%s' % product.price, quantity, IUUID(product))

        if products:
            for item in products:
                data['products'].append('%s|%s|%s' % (item['product'].price, item['quantity'], IUUID(item['product'])))

        donation = createContentInContainer(
            page,
            'collective.salesforce.fundraising.donation',
            checkConstraints=False,
            **data
        )

        # If this is an honorary or memorial donation, redirect to the form to provide details
        is_honorary = self.request.form.get('is_honorary', None)
        if is_honorary == 'true':
            redirect_url = '%s/honorary-memorial-donation?key=%s' % (donation.absolute_url(), donation.secret_key)
        else:
            redirect_url = '%s?key=%s' % (donation.absolute_url(), donation.secret_key)

        return self.request.response.redirect(redirect_url)
Beispiel #4
0
def make_donation_from_invoice(invoice, container):
    last_donation = get_last_donation_for_invoice(invoice)

    mode = 'live'
    is_test = invoice['livemode'] is False

    if invoice['livemode'] == False:
        mode = 'test'

    line_item = get_subscription_line_item(invoice)
    plan = line_item['plan']

    # Stripe handles amounts as cents
    amount = (plan['amount'] * line_item['quantity']) / 100

    # In theory, there should never be a case where a previous donation
    # for the same customer and plan does not already exist.  In practice,
    # it happens so try to handle the exception by parsing contact data from
    # card info
    if last_donation is not None:
        # Found last donation, get contact data from it
        data = {
            'title':
            '%s %s - $%i per %s' % (
                last_donation.first_name,
                last_donation.last_name,
                amount,
                plan['interval'],
            ),
            'first_name':
            last_donation.first_name,
            'last_name':
            last_donation.last_name,
            'email':
            last_donation.email,
            'email_opt_in':
            last_donation.email_opt_in,
            'phone':
            last_donation.phone,
            'address_street':
            last_donation.address_street,
            'address_city':
            last_donation.address_city,
            'address_state':
            last_donation.address_state,
            'address_zip':
            last_donation.address_zip,
            'address_country':
            last_donation.address_country,
            'source_url':
            last_donation.source_url,
            'source_campaign_sf_id':
            last_donation.source_campaign_sf_id,
        }
    else:
        # No last donation found, fetch charge data and attempt to parse
        stripe_util = getUtility(IStripeUtility)
        stripe_api = stripe_util.get_stripe_api(mode=mode)
        charge = stripe_api.Charge.retrieve(invoice['charge'],
                                            expand=['card', 'customer'])
        customer = charge['customer']
        card = charge['card']

        description_parts = customer['description'].split('|')
        first_name = ''
        last_name = ''
        campaign_sf_id = None
        if len(description_parts) >= 1:
            first_name = description_parts[0]
        if len(description_parts) >= 2:
            last_name = description_parts[1]
        if len(description_parts) >= 3:
            campaign_sf_id = description_parts[2]

        address_parts = []
        if card['address_line1']:
            address_parts.append(card['address_line1'])
        if card['address_line2']:
            address_parts.append(card['address_line2'])

        data = {
            'title':
            '%s %s - $%i per %s' % (
                first_name,
                last_name,
                amount,
                plan['interval'],
            ),
            'first_name':
            first_name,
            'last_name':
            last_name,
            'email':
            customer.email,
            'address_street':
            '\n'.join(address_parts),
            'address_city':
            card['address_city'],
            'address_state':
            card['address_state'],
            'address_zip':
            card['address_zip'],
            'address_country':
            card['address_country'],
        }

    # Stripe amounts are in cents
    data['amount'] = amount
    data['stripe_customer_id'] = invoice['customer']
    data['stripe_plan_id'] = plan['id']
    data['transaction_id'] = invoice['charge']
    data['is_test'] = is_test
    data['campaign_sf_id'] = container.sf_object_id
    data['secret_key'] = build_secret_key()
    data['stage'] = 'Posted'
    data['payment_method'] = 'Stripe'
    data['payment_date'] = stripe_timestamp_to_date(invoice['date'])

    # Suppress sending an email receipt
    data['is_receipt_sent'] = True

    # Suppress sending a notification of the donation to a personal fundraiser
    data['is_notification_sent'] = True

    donation = createContentInContainer(
        container,
        'collective.salesforce.fundraising.donation',
        checkConstraints=False,
        **data)

    # Send the Stripe monthly email receipt
    donation.send_email_recurring_receipt()

    return donation
    def render(self):
        charge_id = self.request.form.get("charge_id")
        page = self.context.get_fundraising_campaign_page()

        if not charge_id:
            logger.warning(
                "collective.salesforce.fundraising: Record Stripe Donation " "Error: no charge_id passed in request"
            )
            url = page.absolute_url() + "/@@post_donation_error"
            return self.request.response.redirect(url)

        # Check to make sure a donation does not already exist for this
        # transaction.  If it does, redirect to it.
        pc = getToolByName(self.context, "portal_catalog")
        res = pc.searchResults(
            portal_type="collective.salesforce.fundraising.donation", transaction_id=charge_id, sort_limit=1
        )
        if len(res) == 1:
            # Redirect to the donation or the honorary-memorial form if needed
            donation = res[0].getObject()

            # If this is an honorary or memorial donation, redirect to the
            # form to provide details
            is_honorary = self.request.form.get("is_honorary", None)
            if is_honorary == "true" and donation.honorary_type is None:
                redirect_url = "%s/honorary-memorial-donation?key=%s" % (donation.absolute_url(), donation.secret_key)
            else:
                redirect_url = "%s?key=%s" % (donation.absolute_url(), donation.secret_key)

            return self.request.response.redirect(redirect_url)

        stripe_util = getUtility(IStripeUtility)
        stripe_api = stripe_util.get_stripe_api(page)

        charge = stripe_api.Charge.retrieve(charge_id, expand=["customer.subscriptions", "invoice"])
        # What happens if there is no charge_id passed or no charge was found?
        if not charge:
            logger.warning(
                "collective.salesforce.fundraising: Record Stripe Donation "
                "Error: charge_id %s was not found" % charge_id
            )
            url = page.absolute_url() + "/@@post_donation_error"
            return self.request.response.redirect(url)

        pc = getToolByName(self.context, "portal_catalog")

        # Handle Donation Product forms
        product = None
        product_id = self.request.form.get("c_product_id", None)
        c_products = self.request.form.get("c_products", None)
        quantity = self.request.form.get("c_quantity", None)
        pricebook_id = None
        type_name = "collective.salesforce.fundraising.donationproduct"
        msg = "collective.salesforce.fundraising: Stripe Post Payment Error: " "Product with ID %s not found"
        if product_id:
            res = pc.searchResults(sf_object_id=product_id, portal_type=type_name)
            if not res:
                raise ValueError(msg % product_id)
            product = res[0].getObject()

        if product_id or c_products:
            sfbc = getToolByName(self.context, "portal_salesforcebaseconnector")
            pricebook_id = get_standard_pricebook_id(sfbc)

        # Handle Product Forms with multiple products, each with their own
        # quantity
        products = []
        if c_products:
            for item in c_products.split(","):
                item_id, item_quantity = item.split(":")
                product_res = pc.searchResults(sf_object_id=item_id, portal_type=type_name)
                if not product_res:
                    raise ValueError(msg % item_id)
                products.append({"id": item_id, "quantity": item_quantity, "product": product_res[0].getObject()})

        # lowercase all email addresses to avoid lookup errors if typed with
        # different caps
        email = self.request.form.get("email", None)
        if email:
            email = email.lower()

        first_name = uencode(self.request.form.get("first_name", None))
        last_name = uencode(self.request.form.get("last_name", None))
        email_opt_in = self.request.form.get("email_signup", None) == "YES"
        phone = uencode(self.request.form.get("phone", None))
        address = uencode(self.request.form.get("address", None))
        city = uencode(self.request.form.get("city", None))
        state = uencode(self.request.form.get("state", None))
        zipcode = uencode(self.request.form.get("zip", None))
        country = uencode(self.request.form.get("country", None))
        amount = int(float(self.request.form.get("x_amount", None)))
        source_url = self.request.form.get("source_url", "")

        data = {
            "first_name": first_name,
            "last_name": last_name,
            "email": email,
            "email_opt_in": email_opt_in,
            "phone": phone,
            "address_street": address,
            "address_city": city,
            "address_state": state,
            "address_zip": zipcode,
            "address_country": country,
            "secret_key": build_secret_key(),
            "amount": amount,
            "stage": "Posted",
            "products": [],
            "campaign_sf_id": page.sf_object_id,
            "source_campaign_sf_id": page.get_source_campaign(),
            "source_url": source_url,
            "payment_method": "Stripe",
        }

        # Stripe invoices are only used for recurring so if there is an
        # invoice.
        if charge["invoice"]:
            invoice = charge["invoice"]
            customer = charge["customer"]
            subscriptions = customer["subscriptions"]
            plan = invoice["lines"]["data"][0]["plan"]
            period = invoice["lines"]["data"][0]["period"]

            data["stripe_customer_id"] = customer["id"]
            data["stripe_plan_id"] = plan["id"]
            data["transaction_id"] = charge["id"]
            data["is_test"] = charge["livemode"] == False
            data["title"] = "%s %s - $%i per %s" % (first_name, last_name, amount, plan["interval"])
            data["payment_date"] = stripe_timestamp_to_date(charge["created"])
            data["next_payment_date"] = stripe_timestamp_to_date(period["end"])
        else:
            # One time donation
            data["payment_date"] = stripe_timestamp_to_date(charge["created"])
            data["transaction_id"] = charge["id"]
            data["is_test"] = charge["livemode"] == False
            data["title"] = "%s %s - $%i One Time Donation" % (first_name, last_name, amount)

        if product_id and product is not None:
            # Set a custom name with the product info and quantity
            data["title"] = "%s %s - %s (Qty %s)" % (first_name, last_name, product.title, quantity)

        elif products:
            # Set a custom name with the product info and quantity
            parent_form = products[0]["product"].get_parent_product_form()
            title = "Donation"
            if parent_form:
                title = parent_form.title
            data["title"] = "%s %s - %s" % (first_name, last_name, title)

        if product_id and product is not None:
            data["products"].append("%s|%s|%s" % product.price, quantity, IUUID(product))

        if products:
            for item in products:
                data["products"].append("%s|%s|%s" % (item["product"].price, item["quantity"], IUUID(item["product"])))

        # title must be unicode for dexterity
        if data.get("title", None) and not isinstance(data["title"], unicode):
            data["title"] = unicode(data["title"])

        donation = createContentInContainer(
            page, "collective.salesforce.fundraising.donation", checkConstraints=False, **data
        )

        # If this is an honorary or memorial donation, redirect to the form to provide details
        is_honorary = self.request.form.get("is_honorary", None)
        if is_honorary == "true":
            redirect_url = "%s/honorary-memorial-donation?key=%s" % (donation.absolute_url(), donation.secret_key)
        else:
            redirect_url = "%s?key=%s" % (donation.absolute_url(), donation.secret_key)

        return self.request.response.redirect(redirect_url)
def make_donation_from_invoice(invoice, container):
    last_donation = get_last_donation_for_invoice(invoice)

    mode = 'live'
    is_test = invoice['livemode'] is False

    if invoice['livemode'] == False:
        mode = 'test'

    line_item = get_subscription_line_item(invoice)
    plan = line_item['plan']

    # Stripe handles amounts as cents
    amount = (plan['amount'] * line_item['quantity']) / 100


    # In theory, there should never be a case where a previous donation
    # for the same customer and plan does not already exist.  In practice,
    # it happens so try to handle the exception by parsing contact data from
    # card info
    if last_donation is not None:
        # Found last donation, get contact data from it
        data = {
            'title': '%s %s - $%i per %s' % (
                last_donation.first_name,
                last_donation.last_name,
                amount,
                plan['interval'],
            ),
            'first_name': last_donation.first_name,
            'last_name': last_donation.last_name,
            'email': last_donation.email,
            'email_opt_in': last_donation.email_opt_in,
            'phone': last_donation.phone,
            'address_street': last_donation.address_street,
            'address_city': last_donation.address_city,
            'address_state': last_donation.address_state,
            'address_zip': last_donation.address_zip,
            'address_country': last_donation.address_country,
            'source_url': last_donation.source_url,
            'source_campaign_sf_id': last_donation.source_campaign_sf_id,
        }
    else:
        # No last donation found, fetch charge data and attempt to parse
        stripe_util = getUtility(IStripeUtility)
        stripe_api = stripe_util.get_stripe_api(mode=mode)
        charge = stripe_api.Charge.retrieve(invoice['charge'], expand=['card','customer'])
        customer = charge['customer']
        card = charge['card']

        description_parts = customer['description'].split('|')
        first_name = ''
        last_name = ''
        campaign_sf_id = None
        if len(description_parts) >= 1:
            first_name = description_parts[0]
        if len(description_parts) >= 2:
            last_name = description_parts[1]
        if len(description_parts) >= 3:
            campaign_sf_id = description_parts[2]

        address_parts = []
        if card['address_line1']:
            address_parts.append(card['address_line1'])
        if card['address_line2']:
            address_parts.append(card['address_line2'])

        data = {
            'title': '%s %s - $%i per %s' % (
                first_name,
                last_name,
                amount,
                plan['interval'],
            ),
            'first_name': first_name,
            'last_name': last_name,
            'email': customer.email,
            'address_street': '\n'.join(address_parts),
            'address_city': card['address_city'],
            'address_state': card['address_state'],
            'address_zip': card['address_zip'],
            'address_country': card['address_country'],
        }

    # Stripe amounts are in cents
    data['amount'] = amount
    data['stripe_customer_id'] = invoice['customer']
    data['stripe_plan_id'] = plan['id']
    data['transaction_id'] = invoice['charge']
    data['is_test'] = is_test
    data['campaign_sf_id'] = container.sf_object_id
    data['secret_key'] = build_secret_key()
    data['stage'] = 'Posted'
    data['payment_method'] = 'Stripe'
    data['payment_date'] = stripe_timestamp_to_date(invoice['date'])

    # Suppress sending an email receipt
    data['is_receipt_sent'] = True

    # Suppress sending a notification of the donation to a personal fundraiser
    data['is_notification_sent'] = True

    donation = createContentInContainer(
        container,
        'collective.salesforce.fundraising.donation',
        checkConstraints=False,
        **data
    )

    # Send the Stripe monthly email receipt
    donation.send_email_recurring_receipt()

    return donation
    def render(self):
        charge_id = self.request.form.get('charge_id')
        page = self.context.get_fundraising_campaign_page()

        if not charge_id:
            logger.warning(
                'collective.salesforce.fundraising: Record Stripe Donation '
                'Error: no charge_id passed in request')
            url = page.absolute_url() + '/@@post_donation_error'
            return self.request.response.redirect(url)

        # Check to make sure a donation does not already exist for this
        # transaction.  If it does, redirect to it.
        pc = getToolByName(self.context, 'portal_catalog')
        res = pc.searchResults(
            portal_type='collective.salesforce.fundraising.donation',
            transaction_id=charge_id,
            sort_limit=1)
        if len(res) == 1:
            # Redirect to the donation or the honorary-memorial form if needed
            donation = res[0].getObject()

            # If this is an honorary or memorial donation, redirect to the
            # form to provide details
            is_honorary = self.request.form.get('is_honorary', None)
            if is_honorary == 'true' and donation.honorary_type is None:
                redirect_url = '%s/honorary-memorial-donation?key=%s' % (
                    donation.absolute_url(), donation.secret_key)
            else:
                redirect_url = '%s?key=%s' % (donation.absolute_url(),
                                              donation.secret_key)

            return self.request.response.redirect(redirect_url)

        stripe_util = getUtility(IStripeUtility)
        stripe_api = stripe_util.get_stripe_api(page)

        charge = stripe_api.Charge.retrieve(
            charge_id, expand=['customer.subscriptions', 'invoice'])
        # What happens if there is no charge_id passed or no charge was found?
        if not charge:
            logger.warning(
                'collective.salesforce.fundraising: Record Stripe Donation '
                'Error: charge_id %s was not found' % charge_id)
            url = page.absolute_url() + '/@@post_donation_error'
            return self.request.response.redirect(url)

        pc = getToolByName(self.context, 'portal_catalog')

        # Handle Donation Product forms
        product = None
        product_id = self.request.form.get('c_product_id', None)
        c_products = self.request.form.get('c_products', None)
        quantity = self.request.form.get('c_quantity', None)
        pricebook_id = None
        type_name = 'collective.salesforce.fundraising.donationproduct'
        msg = ('collective.salesforce.fundraising: Stripe Post Payment Error: '
               'Product with ID %s not found')
        if product_id:
            res = pc.searchResults(sf_object_id=product_id,
                                   portal_type=type_name)
            if not res:
                raise ValueError(msg % product_id)
            product = res[0].getObject()

        if product_id or c_products:
            sfbc = getToolByName(self.context,
                                 'portal_salesforcebaseconnector')
            pricebook_id = get_standard_pricebook_id(sfbc)

        # Handle Product Forms with multiple products, each with their own
        # quantity
        products = []
        if c_products:
            for item in c_products.split(','):
                item_id, item_quantity = item.split(':')
                product_res = pc.searchResults(sf_object_id=item_id,
                                               portal_type=type_name)
                if not product_res:
                    raise ValueError(msg % item_id)
                products.append({
                    'id': item_id,
                    'quantity': item_quantity,
                    'product': product_res[0].getObject()
                })

        # lowercase all email addresses to avoid lookup errors if typed with
        # different caps
        email = self.request.form.get('email', None)
        if email:
            email = email.lower()

        first_name = uencode(self.request.form.get('first_name', None))
        last_name = uencode(self.request.form.get('last_name', None))
        email_opt_in = self.request.form.get('email_signup', None) == 'YES'
        phone = uencode(self.request.form.get('phone', None))
        address = uencode(self.request.form.get('address', None))
        city = uencode(self.request.form.get('city', None))
        state = uencode(self.request.form.get('state', None))
        zipcode = uencode(self.request.form.get('zip', None))
        country = uencode(self.request.form.get('country', None))
        amount = int(float(self.request.form.get('x_amount', None)))
        source_url = self.request.form.get('source_url', '')

        data = {
            'first_name': first_name,
            'last_name': last_name,
            'email': email,
            'email_opt_in': email_opt_in,
            'phone': phone,
            'address_street': address,
            'address_city': city,
            'address_state': state,
            'address_zip': zipcode,
            'address_country': country,
            'secret_key': build_secret_key(),
            'amount': amount,
            'stage': 'Posted',
            'products': [],
            'campaign_sf_id': page.sf_object_id,
            'source_campaign_sf_id': page.get_source_campaign(),
            'source_url': source_url,
            'payment_method': 'Stripe',
        }

        # Stripe invoices are only used for recurring so if there is an
        # invoice.
        if charge['invoice']:
            invoice = charge['invoice']
            customer = charge['customer']
            subscriptions = customer['subscriptions']
            plan = invoice['lines']['data'][0]['plan']
            period = invoice['lines']['data'][0]['period']

            data['stripe_customer_id'] = customer['id']
            data['stripe_plan_id'] = plan['id']
            data['transaction_id'] = charge['id']
            data['is_test'] = charge['livemode'] == False
            data['title'] = '%s %s - $%i per %s' % (first_name, last_name,
                                                    amount, plan['interval'])
            data['payment_date'] = stripe_timestamp_to_date(charge['created'])
            data['next_payment_date'] = stripe_timestamp_to_date(period['end'])
        else:
            # One time donation
            data['payment_date'] = stripe_timestamp_to_date(charge['created'])
            data['transaction_id'] = charge['id']
            data['is_test'] = charge['livemode'] == False
            data['title'] = '%s %s - $%i One Time Donation' % (
                first_name, last_name, amount)

        if product_id and product is not None:
            # Set a custom name with the product info and quantity
            data['title'] = '%s %s - %s (Qty %s)' % (first_name, last_name,
                                                     product.title, quantity)

        elif products:
            # Set a custom name with the product info and quantity
            parent_form = products[0]['product'].get_parent_product_form()
            title = 'Donation'
            if parent_form:
                title = parent_form.title
            data['title'] = '%s %s - %s' % (first_name, last_name, title)

        if product_id and product is not None:
            data['products'].append('%s|%s|%s' % product.price, quantity,
                                    IUUID(product))

        if products:
            for item in products:
                data['products'].append(
                    '%s|%s|%s' % (item['product'].price, item['quantity'],
                                  IUUID(item['product'])))

        # title must be unicode for dexterity
        if data.get('title', None) and not isinstance(data['title'], unicode):
            data['title'] = unicode(data['title'])

        donation = createContentInContainer(
            page,
            'collective.salesforce.fundraising.donation',
            checkConstraints=False,
            **data)

        # If this is an honorary or memorial donation, redirect to the form to provide details
        is_honorary = self.request.form.get('is_honorary', None)
        if is_honorary == 'true':
            redirect_url = '%s/honorary-memorial-donation?key=%s' % (
                donation.absolute_url(), donation.secret_key)
        else:
            redirect_url = '%s?key=%s' % (donation.absolute_url(),
                                          donation.secret_key)

        return self.request.response.redirect(redirect_url)