Пример #1
0
def add_blast_subscription(form=None, customer=None):
    """
    Adds a Blast subscription. Blast subscriptions are always recurring. They have two
    email addresses: one for billing and one for the newsletter subscription.

    """

    form = clean(form)

    first_name = form["first_name"]
    last_name = form["last_name"]
    email = form["subscriber_email"]

    logging.info("----Getting contact...")
    contact = Contact.get_or_create(email=email,
                                    first_name=first_name,
                                    last_name=last_name)
    logging.info(contact)

    rdo = RDO(contact=contact)

    rdo.stripe_customer = customer["id"]
    rdo.campaign_id = form["campaign_id"]
    rdo.referral_id = form["referral_id"]
    rdo.lead_source = "Stripe"
    rdo.amount = form.get("amount", 0)
    rdo.agreed_to_pay_fees = form["pay_fees_value"]

    # Blast specific:
    rdo.installments = 0
    rdo.description = "Blast Subscription"
    rdo.open_ended_status = "Open"
    if int(float(rdo.amount)) == 40:
        rdo.installment_period = "monthly"
    else:
        rdo.installment_period = "yearly"
    now = datetime.now(tz=ZONE).strftime("%Y-%m-%d %I:%M:%S %p %Z")
    rdo.name = f"{first_name} {last_name} - {now} - The Blast"
    rdo.type = "The Blast"
    rdo.billing_email = form["stripeEmail"]
    rdo.blast_subscription_email = form["subscriber_email"]

    logging.info("----Saving RDO....")
    apply_card_details(rdo=rdo, customer=customer)
    rdo.save()
    logging.info(rdo)
    # get opportunities
    opportunities = rdo.opportunities()
    today = datetime.now(tz=ZONE).strftime("%Y-%m-%d")
    opp = [
        opportunity for opportunity in opportunities
        if opportunity.expected_giving_date == today
    ][0]
    try:
        charge(opp)
    except ChargeException:
        # TODO should we alert slack? Did not because we had no notifications here before.
        pass

    return True
def contact_from_paypal_transaction(transaction, email, org) -> Contact:

    contact = Contact(
        email=email,
        sfc=org.sfc,
        lead_source="PayPal",
        first_name=transaction.name.first_name,
        last_name=transaction.name.last_name,
    )
    if transaction.address:
        contact.mailing_country = transaction.address.mailing_country
        contact.mailing_city = transaction.address.mailing_city
        contact.mailing_state = transaction.address.mailing_state
        contact.mailing_postal_code = transaction.address.mailing_postal_code
        contact.mailing_street = transaction.address.mailing_street

    return contact
Пример #3
0
def test__format_contact():

    contact = Contact(sf_connection=sf)
    contact.email = "*****@*****.**"
    contact.first_name = "D"
    contact.last_name = "C"
    contact.lead_source = "Stripe"
    contact.work_email = "*****@*****.**"

    response = contact._format()

    expected_response = {
        "Email": "*****@*****.**",
        "FirstName": "D",
        "LastName": "C",
        "LeadSource": "Stripe",
        "MailingPostalCode": None,
        "npe01__WorkEmail__c": "*****@*****.**",
    }

    assert response == expected_response
Пример #4
0
def contact_from_eb_event(attendee, org: Organization) -> Contact:

    first_name = attendee["profile"]["first_name"]
    last_name = attendee["profile"]["last_name"]
    email = attendee["profile"]["email"]
    company = attendee["profile"]["company"] if "company" in attendee[
        "profile"] else None
    address = address_from_attendee(attendee)

    return Contact(
        email=email,
        sfc=org.sfc,
        first_name=first_name,
        last_name=last_name,
        eventbrite_company_name=company,
        mailing_country=address.mailing_country,
        mailing_state=address.mailing_state,
        mailing_postal_code=address.mailing_postal_code,
        mailing_city=address.mailing_city,
        mailing_street=address.mailing_street,
        lead_source="Eventbrite",
    )
Пример #5
0
def test__format_slack():

    opportunity = Opportunity(sf_connection=sf)
    opportunity.account_id = "0011700000BpR8PAAV"
    opportunity.amount = 9
    opportunity.encouraged_by = "Because I love the Trib!"
    opportunity.name = "D C ([email protected])"
    opportunity.stripe_id = "cus_78MqJSBejMN9gn"
    opportunity.agreed_to_pay_fees = True
    opportunity.referral_id = "1234"
    opportunity.lead_source = "Stripe"
    opportunity.description = "The Texas Tribune Membership"
    opportunity.stripe_customer = "cus_78MqJSBejMN9gn"

    rdo = RDO(sf_connection=sf)
    rdo.referral_id = "1234"
    rdo.encouraged_by = "Because I love the Trib!"
    rdo.lead_source = "Stripe"
    rdo.contact_id = "0031700000BHQzBAAX"
    rdo.installment_period = "yearly"
    rdo.stripe_customer = "cus_78MqJSBejMN9gn"
    rdo.amount = 100
    rdo.name = "foo"
    rdo.installments = 3
    rdo.open_ended_status = None
    rdo.description = "Texas Tribune Circle Membership"
    rdo.agreed_to_pay_fees = True
    rdo.type = "Giving Circle"

    contact = Contact(sf_connection=sf)
    contact.email = "*****@*****.**"
    contact.first_name = "D"
    contact.last_name = "C"
    contact.lead_source = "Stripe"
    contact.work_email = "*****@*****.**"

    account = Account(sf_connection=sf)
    account.name = "Acme Inc."
    account.website = "http://acme.com"
    account.shipping_street = "Street"
    account.shipping_city = "Austin"
    account.shipping_postalcode = "78701"
    account.shipping_state = "TX"
    account.record_type_name = "Household"

    actual = construct_slack_message(account=account,
                                     rdo=rdo,
                                     opportunity=None,
                                     contact=None)
    expected = "Acme Inc. pledged $100 [yearly] (Because I love the Trib!)"

    assert actual == expected

    actual = construct_slack_message(account=None,
                                     rdo=rdo,
                                     opportunity=None,
                                     contact=contact)
    expected = "D C pledged $100 [yearly] (Because I love the Trib!)"

    assert actual == expected

    actual = construct_slack_message(account=None,
                                     rdo=None,
                                     opportunity=opportunity,
                                     contact=contact)
    expected = "D C pledged $9 [one-time] (Because I love the Trib!)"

    assert actual == expected
Пример #6
0
    reader = csv.DictReader(csvfile)
    assert set(reader.fieldnames) == set(FIELDNAMES)

    for row in reader:
        print(
            f"processing record for {row['email']} (${row['amount']} each {row['interval']})..."
        )

        add_email_to_stripe(row["customer_id"], row["email"])
        # check for dupe
        if (RDO.get(stripe_customer_id=row["customer_id"],
                    sf_connection=sf_connection)) is not None:
            print("Exiting; WARNING: duplicate!")
            sys.exit(-1)

        contact = Contact.get_or_create(sf_connection=sf_connection,
                                        email=row["email"])
        now = datetime.now(tz=pytz.utc).strftime("%Y-%m-%d %I:%M:%S %p %Z")

        if contact.last_name == "Subscriber":
            rdo_name = f"{now} for {row['email']}"
        else:
            rdo_name = f"{now} for {contact.first_name} {contact.last_name}"

        rdo = RDO(contact=contact, sf_connection=sf_connection)
        rdo.stripe_customer_id = row["customer_id"].strip()
        rdo.name = rdo_name
        rdo.description = f"{row['subscription_id']} ({row['plan_name']})"
        rdo.lead_source = "Stripe"
        rdo.installment_period = interval_map[row["interval"].strip()]
        rdo.amount = row["amount"].strip()
        rdo.open_ended_status = "Open"
Пример #7
0
def authorization_notification(payload):

    amzn_id = payload["AuthorizationNotification"]["AuthorizationDetails"][
        "AmazonAuthorizationId"]

    # trim everything after the last dash - seems like there should be a more
    # straightforward way to do this
    match = re.search("^(.*)[-]", amzn_id)
    amzn_id = match.group(1)
    logging.info(amzn_id)

    client = AmazonPayClient(
        mws_access_key=MWS_ACCESS_KEY,
        mws_secret_key=MWS_SECRET_KEY,
        merchant_id=AMAZON_MERCHANT_ID,
        region="na",
        currency_code="USD",
        sandbox=AMAZON_SANDBOX,
    )
    response = client.get_order_reference_details(
        amazon_order_reference_id=amzn_id)
    response = response.to_dict()

    logging.info(json.dumps(response, indent=4))

    details = response["GetOrderReferenceDetailsResponse"][
        "GetOrderReferenceDetailsResult"]["OrderReferenceDetails"]

    amount = details["OrderTotal"]["Amount"]
    logging.info(amount)
    name = HumanName(details["Buyer"]["Name"])
    first_name = name.first
    last_name = name.last
    email = details["Buyer"]["Email"]
    zipcode = get_zip(details=details)
    description = details["SellerOrderAttributes"]["StoreName"]

    logging.info("----Getting contact....")
    contact = Contact.get_or_create(email=email,
                                    first_name=first_name,
                                    last_name=last_name,
                                    zipcode=zipcode)
    logging.info(contact)

    if contact.first_name == "Subscriber" and contact.last_name == "Subscriber":
        logging.info(f"Changing name of contact to {first_name} {last_name}")
        contact.first_name = first_name
        contact.last_name = last_name
        contact.save()

    if contact.first_name != first_name or contact.last_name != last_name:
        logging.info(
            f"Contact name doesn't match: {contact.first_name} {contact.last_name}"
        )

    if zipcode and not contact.created and contact.mailing_postal_code != zipcode:
        contact.mailing_postal_code = zipcode
        contact.save()

    logging.info("----Adding opportunity...")

    opportunity = Opportunity(contact=contact, stage_name="Closed Won")
    opportunity.amount = amount
    opportunity.description = description
    opportunity.lead_source = "Amazon Alexa"
    opportunity.amazon_order_id = amzn_id
    opportunity.campaign_id = AMAZON_CAMPAIGN_ID
    opportunity.name = (
        f"[Alexa] {contact.first_name} {contact.last_name} ({contact.email})")
    opportunity.save()
    logging.info(opportunity)
    notify_slack(contact=contact, opportunity=opportunity)
    if contact.duplicate_found:
        send_multiple_account_warning(contact)
Пример #8
0
def add_donation(form=None,
                 customer=None,
                 donation_type=None,
                 bad_actor_request=None):
    """
    Add a contact and their donation into SF. This is done in the background
    because there are a lot of API calls and there's no point in making the
    payer wait for them. It sends a notification about the donation to Slack (if configured).
    """
    bad_actor_response = BadActor(bad_actor_request=bad_actor_request)
    quarantine = bad_actor_response.quarantine

    form = clean(form)
    first_name = form["first_name"]
    last_name = form["last_name"]
    period = form["installment_period"]
    email = form["stripeEmail"]
    zipcode = form["zipcode"]

    logging.info("----Getting contact....")
    contact = Contact.get_or_create(email=email,
                                    first_name=first_name,
                                    last_name=last_name,
                                    zipcode=zipcode)
    logging.info(contact)

    if contact.first_name == "Subscriber" and contact.last_name == "Subscriber":
        logging.info(f"Changing name of contact to {first_name} {last_name}")
        contact.first_name = first_name
        contact.last_name = last_name
        contact.mailing_postal_code = zipcode
        contact.save()

    if contact.first_name != first_name or contact.last_name != last_name:
        logging.info(
            f"Contact name doesn't match: {contact.first_name} {contact.last_name}"
        )

    if zipcode and not contact.created and contact.mailing_postal_code != zipcode:
        contact.mailing_postal_code = zipcode
        contact.save()

    if contact.duplicate_found:
        send_multiple_account_warning(contact)

    if period is None:
        logging.info("----Creating one time payment...")
        opportunity = add_opportunity(contact=contact,
                                      form=form,
                                      customer=customer,
                                      quarantine=quarantine)
        try:
            charge(opportunity)
            logging.info(opportunity)
            notify_slack(contact=contact, opportunity=opportunity)
        except ChargeException as e:
            e.send_slack_notification()
        except QuarantinedException:
            bad_actor_response.notify_bad_actor(transaction_type="Opportunity",
                                                transaction=opportunity)
        return True

    elif donation_type == "circle":
        logging.info("----Creating circle payment...")
        rdo = add_circle_membership(contact=contact,
                                    form=form,
                                    customer=customer,
                                    quarantine=False)
    else:
        logging.info("----Creating recurring payment...")
        rdo = add_recurring_donation(contact=contact,
                                     form=form,
                                     customer=customer,
                                     quarantine=quarantine)

    # get opportunities
    opportunities = rdo.opportunities()
    today = datetime.now(tz=ZONE).strftime("%Y-%m-%d")
    opp = [
        opportunity for opportunity in opportunities
        if opportunity.expected_giving_date == today
    ][0]
    try:
        charge(opp)
        logging.info(rdo)
        notify_slack(contact=contact, rdo=rdo)
    except ChargeException as e:
        e.send_slack_notification()
    except QuarantinedException:
        bad_actor_response.notify_bad_actor(transaction_type="RDO",
                                            transaction=rdo)
    return True
Пример #9
0
def add_business_membership(
    form=None,
    customer=None,
    donation_type="business_membership",
    bad_actor_request=None,
):
    """
    Adds a business membership. Both single and recurring.

    It will look for a matching Contact (or create one). Then it will look for a
    matching Account (or create one). Then it will add the single or recurring donation
    to the Account. Then it will add an Affiliation to link the Contact with the
    Account. It sends a notification to Slack (if configured). It will send email
    notification about the new membership.

    """

    form = clean(form)

    first_name = form["first_name"]
    last_name = form["last_name"]
    email = form["stripeEmail"]

    website = form["website"]
    business_name = form["business_name"]
    shipping_city = form["shipping_city"]
    shipping_street = form["shipping_street"]
    shipping_state = form["shipping_state"]
    shipping_postalcode = form["shipping_postalcode"]

    bad_actor_response = BadActor(bad_actor_request=bad_actor_request)
    quarantine = bad_actor_response.quarantine

    logging.info("----Getting contact....")
    contact = Contact.get_or_create(email=email,
                                    first_name=first_name,
                                    last_name=last_name)
    if contact.work_email is None:
        contact.work_email = email
        contact.save()
    logging.info(contact)

    if contact.first_name == "Subscriber" and contact.last_name == "Subscriber":
        logging.info(f"Changing name of contact to {first_name} {last_name}")
        contact.first_name = first_name
        contact.last_name = last_name
        contact.save()

    if contact.first_name != first_name or contact.last_name != last_name:
        logging.info(
            f"Contact name doesn't match: {contact.first_name} {contact.last_name}"
        )

    logging.info("----Getting account....")

    account = Account.get_or_create(
        record_type_name="Organization",
        website=website,
        name=business_name,
        shipping_street=shipping_street,
        shipping_city=shipping_city,
        shipping_state=shipping_state,
        shipping_postalcode=shipping_postalcode,
    )
    logging.info(account)

    if form["installment_period"] not in ["yearly", "monthly"]:
        raise Exception("Business membership must be either yearly or monthly")

    logging.info("----Creating recurring business membership...")
    rdo = add_business_rdo(account=account,
                           form=form,
                           customer=customer,
                           quarantine=False)
    logging.info(rdo)

    logging.info("----Getting affiliation...")

    affiliation = Affiliation.get_or_create(account=account,
                                            contact=contact,
                                            role="Business Member Donor")
    logging.info(affiliation)

    send_email_new_business_membership(account=account, contact=contact)

    # get opportunities
    opportunities = rdo.opportunities()
    today = datetime.now(tz=ZONE).strftime("%Y-%m-%d")
    opp = [
        opportunity for opportunity in opportunities
        if opportunity.expected_giving_date == today
    ][0]
    try:
        charge(opp)
        notify_slack(account=account, contact=contact, rdo=rdo)
    except ChargeException as e:
        e.send_slack_notification()
    except QuarantinedException:
        bad_actor_response.notify_bad_actor(transaction_type="RDO",
                                            transaction=rdo)

    if contact.duplicate_found:
        send_multiple_account_warning(contact)

    return True
Пример #10
0
def add_donation(form=None, customer=None):
    """
    Add a contact and their donation into SF. This is done in the background
    because there are a lot of API calls and there's no point in making the
    payer wait for them. It sends a notification about the donation to Slack (if configured).
    """
    form = clean(form)
    first_name = form["first_name"]
    last_name = form["last_name"]
    period = form["installment_period"]
    email = form["stripeEmail"]
    zipcode = form["zipcode"]

    logging.info("----Getting contact....")
    contact = Contact.get_or_create(email=email,
                                    first_name=first_name,
                                    last_name=last_name,
                                    zipcode=zipcode)
    logging.info(contact)

    if contact.first_name == "Subscriber" and contact.last_name == "Subscriber":
        logging.info(f"Changing name of contact to {first_name} {last_name}")
        contact.first_name = first_name
        contact.last_name = last_name
        contact.mailing_postal_code = zipcode
        contact.save()

    if contact.first_name != first_name or contact.last_name != last_name:
        logging.info(
            f"Contact name doesn't match: {contact.first_name} {contact.last_name}"
        )

    if zipcode and not contact.created and contact.mailing_postal_code != zipcode:
        contact.mailing_postal_code = zipcode
        contact.save()

    if period is None:
        logging.info("----Creating one time payment...")
        opportunity = add_opportunity(contact=contact,
                                      form=form,
                                      customer=customer)
        charge(opportunity)
        logging.info(opportunity)
        notify_slack(contact=contact, opportunity=opportunity)
    else:
        logging.info("----Creating recurring payment...")
        rdo = add_recurring_donation(contact=contact,
                                     form=form,
                                     customer=customer)
        # get opportunities
        opportunities = rdo.opportunities()
        today = datetime.now(tz=ZONE).strftime("%Y-%m-%d")
        opp = [
            opportunity for opportunity in opportunities
            if opportunity.expected_giving_date == today
        ][0]
        charge(opp)
        logging.info(rdo)
        notify_slack(contact=contact, rdo=rdo)

    if contact.duplicate_found:
        send_multiple_account_warning(contact)

    return True