Esempio n. 1
0
def process_subhub_event_subscription_updated(data):
    statsd.incr('news.tasks.process_subhub_event.subscription_updated')
    user_data = get_user_data(payee_id=data['customer_id'],
                              extra_fields=['id'])
    if not user_data:
        statsd.incr(
            'news.tasks.process_subhub_event.subscription_updated.user_not_found'
        )
        raise RetryTask('Could not find user. Try again.')

    direction = 'Down' if data['event_type'].endswith('downgrade') else 'Up'
    stage_name = f'Subscription {direction}grade'
    sfdc.opportunity.create({
        'Amount':
        cents_to_dollars(data['plan_amount_new']),
        'Plan_Amount_Old__c':
        cents_to_dollars(data['plan_amount_old']),
        'Billing_Cycle_End__c':
        iso_format_unix_timestamp(data['current_period_end']),
        'CloseDate':
        iso_format_unix_timestamp(data.get('close_date', time())),
        'Donation_Contact__c':
        user_data['id'],
        'Event_Id__c':
        data['event_id'],
        'Event_Name__c':
        data['event_type'],
        'Invoice_Number__c':
        data['invoice_number'],
        'Name':
        'Subscription Services',
        'Payment_Interval__c':
        data['interval'],
        'Payment_Source__c':
        'Stripe',
        'PMT_Invoice_ID__c':
        data['invoice_id'],
        'PMT_Subscription_ID__c':
        data['subscription_id'],
        'Proration_Amount__c':
        data['proration_amount'],
        'RecordTypeId':
        settings.SUBHUB_OPP_RECORD_TYPE,
        'Service_Plan__c':
        data['nickname_new'],
        'Nickname_Old__c':
        data['nickname_old'],
        'StageName':
        stage_name,
    })
Esempio n. 2
0
def process_subhub_event_subscription_cancel(data):
    """
    Event name: customer.subscription_cancelled or customer.deleted
    """
    statsd.incr('news.tasks.process_subhub_event.subscription_cancel')
    user_data = get_user_data(payee_id=data['customer_id'],
                              extra_fields=['id'])
    if not user_data:
        statsd.incr(
            'news.tasks.process_subhub_event_subscription_cancel.user_not_found'
        )
        raise RetryTask('Could not find user. Try again.')

    nickname = data['nickname']
    if isinstance(nickname, list):
        nickname = nickname[0]

    sfdc.opportunity.create({
        'Amount':
        cents_to_dollars(data['plan_amount']),
        'Billing_Cycle_End__c':
        iso_format_unix_timestamp(data['current_period_end']),
        'Billing_Cycle_Start__c':
        iso_format_unix_timestamp(data['current_period_start']),
        'CloseDate':
        iso_format_unix_timestamp(data.get('cancel_at', time())),
        'Donation_Contact__c':
        user_data['id'],
        'Event_Id__c':
        data['event_id'],
        'Event_Name__c':
        data['event_type'],
        'Name':
        'Subscription Services',
        'Payment_Source__c':
        'Stripe',
        'PMT_Subscription_ID__c':
        data['subscription_id'],
        'RecordTypeId':
        settings.SUBHUB_OPP_RECORD_TYPE,
        'Service_Plan__c':
        nickname,
        'StageName':
        SUB_STAGE_NAMES[data['event_type']],
    })

    if data['event_type'] == 'customer.deleted':
        sfdc.update(user_data, {'fxa_deleted': True})
Esempio n. 3
0
def process_subhub_event_subscription_reactivated(data):
    statsd.incr('news.tasks.process_subhub_event.subscription_reactivated')
    user_data = get_user_data(payee_id=data['customer_id'],
                              extra_fields=['id'])
    if not user_data:
        statsd.incr(
            'news.tasks.process_subhub_event.subscription_reactivated.user_not_found'
        )
        raise RetryTask('Could not find user. Try again.')

    nickname = data['nickname']
    if isinstance(nickname, list):
        nickname = nickname[0]

    sfdc.opportunity.create({
        'Amount':
        cents_to_dollars(data['plan_amount']),
        'Billing_Cycle_End__c':
        iso_format_unix_timestamp(data['current_period_end']),
        'CloseDate':
        iso_format_unix_timestamp(data.get('close_date', time())),
        'Credit_Card_Type__c':
        data['brand'],
        'Last_4_Digits__c':
        data['last4'],
        'Donation_Contact__c':
        user_data['id'],
        'Event_Id__c':
        data['event_id'],
        'Event_Name__c':
        data['event_type'],
        'Name':
        'Subscription Services',
        'Payment_Source__c':
        'Stripe',
        'PMT_Subscription_ID__c':
        data['subscription_id'],
        'RecordTypeId':
        settings.SUBHUB_OPP_RECORD_TYPE,
        'Service_Plan__c':
        nickname,
        'StageName':
        'Reactivation',
    })
Esempio n. 4
0
def process_subhub_event_payment_failed(data):
    """
    Event name: invoice.payment_failed
    """
    statsd.incr('news.tasks.process_subhub_event.payment_failed')

    user_data = get_user_data(payee_id=data['customer_id'],
                              extra_fields=['id'])
    # the only user identifiable information available is the payment
    # processor/Stripe ID, so if the user wasn't found by that, there's really
    # nothing to be done here but retry.
    if not user_data:
        statsd.incr(
            'news.tasks.process_subhub_event.payment_failed.user_not_found')
        raise RetryTask('Could not find user. Try again.')

    nickname = data['nickname']
    if isinstance(nickname, list):
        nickname = nickname[0]

    sfdc.opportunity.create({
        'Amount':
        cents_to_dollars(data['amount_due']),
        'CloseDate':
        iso_format_unix_timestamp(data['created']),
        'Donation_Contact__c':
        user_data['id'],
        'Event_Id__c':
        data['event_id'],
        'Event_Name__c':
        data['event_type'],
        'Name':
        'Subscription Services',
        'PMT_Subscription_ID__c':
        data['subscription_id'],
        'PMT_Transaction_ID__c':
        data['charge_id'],
        'Payment_Source__c':
        'Stripe',
        'RecordTypeId':
        settings.SUBHUB_OPP_RECORD_TYPE,
        'Service_Plan__c':
        nickname,
        'StageName':
        'Payment Failed',
        'currency__c':
        data['currency'],
    })
Esempio n. 5
0
def fxa_verified(data):
    """Add new FxA users to SFDC"""
    # if we're not using the sandbox ignore testing domains
    if email_is_testing(data["email"]):
        return

    lang = get_best_language(get_accept_languages(data.get("locale")))
    if not lang or lang not in newsletter_languages():
        lang = "other"

    email = data["email"]
    fxa_id = data["uid"]
    create_date = data.get("createDate", data.get("ts"))
    newsletters = data.get("newsletters")
    metrics = data.get("metricsContext", {})
    new_data = {
        "email": email,
        "source_url": fxa_source_url(metrics),
        "country": data.get("countryCode", ""),
        "fxa_lang": data.get("locale"),
        "fxa_service": data.get("service", ""),
        "fxa_id": fxa_id,
        "optin": True,
        "format": "H",
    }
    if create_date:
        new_data["fxa_create_date"] = iso_format_unix_timestamp(create_date)

    newsletters = newsletters or []
    newsletters.append(settings.FXA_REGISTER_NEWSLETTER)
    new_data["newsletters"] = newsletters

    user_data = get_fxa_user_data(fxa_id, email)
    # don't overwrite the user's language if already set
    if not (user_data and user_data.get("lang")):
        new_data["lang"] = lang

    upsert_contact(SUBSCRIBE, new_data, user_data)
Esempio n. 6
0
def process_subhub_event_subscription_charge(data):
    """
    Event names: customer.subscription.created, customer.recurring_charge

    This method handles both new and recurring charges.

    Each of the handled events contains the same payload data. The only variation below
    is in regards to Initial_Purchase__c, which will be True for the
    `customer.subscription.created` event, and False for the `customer.recurring_charge`
    event.
    """

    statsd.incr('news.tasks.process_subhub_event.subscription_charge')
    user_data = get_user_data(payee_id=data['customer_id'],
                              extra_fields=['id'])
    if not user_data:
        statsd.incr(
            'news.tasks.process_subhub_event.subscription_charge.user_not_found'
        )
        raise RetryTask('Could not find user. Try again.')

    nickname = data['nickname']
    if isinstance(nickname, list):
        nickname = nickname[0]

    # if a customer re-instates service after a cancellation, the record needs to be updated
    oppy_data = {
        'Amount':
        cents_to_dollars(data['plan_amount']),
        'Billing_Cycle_End__c':
        iso_format_unix_timestamp(data['current_period_end']),
        'Billing_Cycle_Start__c':
        iso_format_unix_timestamp(data['current_period_start']),
        'CloseDate':
        iso_format_unix_timestamp(data['created']),
        'Credit_Card_Type__c':
        data['brand'],
        'currency__c':
        data['currency'],
        'Donation_Contact__c':
        user_data['id'],
        'Event_Id__c':
        data['event_id'],
        'Event_Name__c':
        data['event_type'],
        'Initial_Purchase__c':
        data['event_type'] == 'customer.subscription.created',
        'Invoice_Number__c':
        data['invoice_number'],
        'Last_4_Digits__c':
        data['last4'],
        'Name':
        'Subscription Services',
        'Next_Invoice_Date__c':
        iso_format_unix_timestamp(data['next_invoice_date']),
        'Payment_Source__c':
        'Stripe',
        'PMT_Subscription_ID__c':
        data['subscription_id'],
        'PMT_Transaction_ID__c':
        data['charge'],
        'RecordTypeId':
        settings.SUBHUB_OPP_RECORD_TYPE,
        'Service_Plan__c':
        nickname,
        'StageName':
        'Closed Won',
    }
    if 'proration_amount' in data:
        oppy_data['Proration_Amount__c'] = cents_to_dollars(
            data['proration_amount'])

    if 'total_amount' in data:
        oppy_data['Total_Amount__c'] = cents_to_dollars(data['total_amount'])

    sfdc.opportunity.upsert(f'PMT_Invoice_ID__c/{data["invoice_id"]}',
                            oppy_data)
Esempio n. 7
0
def process_donation(data):
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    # do "or ''" because data can contain None values
    first_name = (data.get('first_name') or '').strip()
    last_name = (data.get('last_name') or '').strip()
    if first_name and last_name:
        contact_data['first_name'] = first_name
        contact_data['last_name'] = last_name
    elif first_name:
        contact_data['first_name'] = first_name
    elif last_name:
        names = data['last_name'].rsplit(None, 1)
        if len(names) == 2:
            first, last = names
        else:
            first, last = '', names[0]
        if first:
            contact_data['first_name'] = first
        if last:
            contact_data['last_name'] = last

    user_data = get_user_data(email=data['email'], extra_fields=['id'])
    if user_data:
        if contact_data and (
            ('first_name' in contact_data
             and contact_data['first_name'] != user_data['first_name']) or
            ('last_name' in contact_data
             and contact_data['last_name'] != user_data['last_name'])):
            sfdc.update(user_data, contact_data)
    else:
        contact_data['token'] = generate_token()
        contact_data['email'] = data['email']
        contact_data['record_type'] = settings.DONATE_CONTACT_RECORD_TYPE

        # returns a dict with the new ID but no other user data, but that's enough here
        user_data = sfdc.add(contact_data)
        if not user_data.get('id'):
            # retry here to make sure we associate the donation data with the proper account
            raise RetryTask('User not yet available')

    # add opportunity
    donation = {
        'RecordTypeId': settings.DONATE_OPP_RECORD_TYPE,
        'Name': 'Foundation Donation',
        'Donation_Contact__c': user_data['id'],
        'StageName': 'Closed Won',
        'Amount': float(data['donation_amount']),
        'Currency__c': data['currency'].upper(),
        'Payment_Source__c': data['service'],
        'PMT_Transaction_ID__c': data['transaction_id'],
        'Payment_Type__c': 'Recurring' if data['recurring'] else 'One-Time',
    }
    # this is a unix timestamp in ms since epoc
    timestamp = data.get('created')
    if timestamp:
        donation['CloseDate'] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_NEW_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if data.get(source_name):
            # truncate at 2000 chars as that's the max for
            # a SFDC text field. We may do more granular
            # truncation per field in future.
            donation[dest_name] = data[source_name][:2000]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Esempio n. 8
0
def process_donation(data):
    get_lock(data["email"])
    contact_data = {
        "_set_subscriber": False,  # SFDC, leave "subscriber" flag alone
        "mofo_relevant": True,  # CTMS, set a MoFo relevant contact
    }
    # do "or ''" because data can contain None values
    first_name = (data.get("first_name") or "").strip()
    last_name = (data.get("last_name") or "").strip()
    if first_name and last_name:
        contact_data["first_name"] = first_name
        contact_data["last_name"] = last_name
    elif first_name:
        contact_data["first_name"] = first_name
    elif last_name:
        names = data["last_name"].rsplit(None, 1)
        if len(names) == 2:
            first, last = names
        else:
            first, last = "", names[0]
        if first:
            contact_data["first_name"] = first
        if last:
            contact_data["last_name"] = last

    user_data = get_user_data(email=data["email"], extra_fields=["id"])
    if user_data:
        if contact_data and (
            (
                "first_name" in contact_data
                and contact_data["first_name"] != user_data["first_name"]
            )
            or (
                "last_name" in contact_data
                and contact_data["last_name"] != user_data["last_name"]
            )
        ):
            sfdc.update(user_data, contact_data)
            ctms_data = contact_data.copy()
            del ctms_data["_set_subscriber"]
            ctms.update(user_data, ctms_data)
    else:
        contact_data["token"] = generate_token()
        contact_data["email"] = data["email"]
        contact_data["record_type"] = settings.DONATE_CONTACT_RECORD_TYPE

        ctms_data = contact_data.copy()
        del ctms_data["_set_subscriber"]
        del ctms_data["record_type"]
        contact = ctms.add(ctms_data)
        if contact:
            contact_data["email_id"] = contact["email"]["email_id"]

        if not settings.SFDC_ENABLED:
            return

        # returns a dict with the new ID but no other user data, but that's enough here
        user_data = sfdc.add(contact_data)
        if not user_data.get("id"):
            # retry here to make sure we associate the donation data with the proper account
            raise RetryTask("User not yet available")

    if not settings.SFDC_ENABLED:
        return

    # add opportunity
    donation = {
        "RecordTypeId": settings.DONATE_OPP_RECORD_TYPE,
        "Name": "Foundation Donation",
        "Donation_Contact__c": user_data["id"],
        "StageName": "Closed Won",
        "Amount": float(data["donation_amount"]),
        "Currency__c": data["currency"].upper(),
        "Payment_Source__c": data["service"],
        "PMT_Transaction_ID__c": data["transaction_id"],
        "Payment_Type__c": "Recurring" if data["recurring"] else "One-Time",
    }
    # https://github.com/mozmeao/basket/issues/364
    if "campaign_id" in data:
        donation["CampaignId"] = data["campaign_id"]

    # this is a unix timestamp in ms since epoc
    timestamp = data.get("created")
    if timestamp:
        donation["CloseDate"] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_NEW_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if data.get(source_name):
            # truncate at 2000 chars as that's the max for
            # a SFDC text field. We may do more granular
            # truncation per field in future.
            donation[dest_name] = data[source_name][:2000]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get("errorCode") == "DUPLICATE_VALUE":
            # already in the system, ignore
            pass
        else:
            raise
Esempio n. 9
0
def process_donation(data):
    if 'data' in data:
        # here for old messages
        # TODO remove in a subsequent deployment
        data = data['data']
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    first_name = data.get('first_name', '').strip()
    last_name = data.get('last_name', '').strip()
    if first_name and last_name:
        contact_data['first_name'] = first_name
        contact_data['last_name'] = last_name
    elif first_name:
        contact_data['first_name'] = first_name
    elif last_name:
        names = data['last_name'].rsplit(None, 1)
        if len(names) == 2:
            first, last = names
        else:
            first, last = '', names[0]
        if first:
            contact_data['first_name'] = first
        if last:
            contact_data['last_name'] = last

    user_data = get_user_data(email=data['email'],
                              extra_fields=['id'])
    if user_data:
        if contact_data and (
                ('first_name' in contact_data and contact_data['first_name'] != user_data['first_name']) or
                ('last_name' in contact_data and contact_data['last_name'] != user_data['last_name'])):
            sfdc.update(user_data, contact_data)
    else:
        contact_data['token'] = generate_token()
        contact_data['email'] = data['email']
        contact_data['record_type'] = settings.DONATE_CONTACT_RECORD_TYPE

        sfdc.add(contact_data)
        # fetch again to get ID
        user_data = get_user_data(email=data.get('email'),
                                  extra_fields=['id'])
        if not user_data:
            # retry here to make sure we associate the donation data with the proper account
            raise RetryTask('User not yet available')

    # add opportunity
    donation = {
        'RecordTypeId': settings.DONATE_OPP_RECORD_TYPE,
        'Name': 'Foundation Donation',
        'Donation_Contact__c': user_data['id'],
        'StageName': 'Closed Won',
        'Amount': float(data['donation_amount']),
        'Currency__c': data['currency'].upper(),
        'Payment_Source__c': data['service'],
        'PMT_Transaction_ID__c': data['transaction_id'],
        'Payment_Type__c': 'Recurring' if data['recurring'] else 'One-Time',
    }
    # this is a unix timestamp in ms since epoc
    timestamp = data.get('created')
    if timestamp:
        donation['CloseDate'] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise
Esempio n. 10
0
def process_donation(data):
    get_lock(data['email'])
    # tells the backend to leave the "subscriber" flag alone
    contact_data = {'_set_subscriber': False}
    # do "or ''" because data can contain None values
    first_name = (data.get('first_name') or '').strip()
    last_name = (data.get('last_name') or '').strip()
    if first_name and last_name:
        contact_data['first_name'] = first_name
        contact_data['last_name'] = last_name
    elif first_name:
        contact_data['first_name'] = first_name
    elif last_name:
        names = data['last_name'].rsplit(None, 1)
        if len(names) == 2:
            first, last = names
        else:
            first, last = '', names[0]
        if first:
            contact_data['first_name'] = first
        if last:
            contact_data['last_name'] = last

    user_data = get_user_data(email=data['email'],
                              extra_fields=['id'])
    if user_data:
        if contact_data and (
                ('first_name' in contact_data and contact_data['first_name'] != user_data['first_name']) or
                ('last_name' in contact_data and contact_data['last_name'] != user_data['last_name'])):
            sfdc.update(user_data, contact_data)
    else:
        contact_data['token'] = generate_token()
        contact_data['email'] = data['email']
        contact_data['record_type'] = settings.DONATE_CONTACT_RECORD_TYPE

        sfdc.add(contact_data)
        # fetch again to get ID
        user_data = get_user_data(email=data.get('email'),
                                  extra_fields=['id'])
        if not user_data:
            # retry here to make sure we associate the donation data with the proper account
            raise RetryTask('User not yet available')

    # add opportunity
    donation = {
        'RecordTypeId': settings.DONATE_OPP_RECORD_TYPE,
        'Name': 'Foundation Donation',
        'Donation_Contact__c': user_data['id'],
        'StageName': 'Closed Won',
        'Amount': float(data['donation_amount']),
        'Currency__c': data['currency'].upper(),
        'Payment_Source__c': data['service'],
        'PMT_Transaction_ID__c': data['transaction_id'],
        'Payment_Type__c': 'Recurring' if data['recurring'] else 'One-Time',
    }
    # this is a unix timestamp in ms since epoc
    timestamp = data.get('created')
    if timestamp:
        donation['CloseDate'] = iso_format_unix_timestamp(timestamp)

    for dest_name, source_name in DONATION_NEW_FIELDS.items():
        if source_name in data:
            donation[dest_name] = data[source_name]

    for dest_name, source_name in DONATION_OPTIONAL_FIELDS.items():
        if source_name in data:
            # truncate at 2000 chars as that's the max for
            # a SFDC text field. We may do more granular
            # truncation per field in future.
            donation[dest_name] = data[source_name][:2000]

    try:
        sfdc.opportunity.create(donation)
    except sfapi.SalesforceMalformedRequest as e:
        if e.content and e.content[0].get('errorCode') == 'DUPLICATE_VALUE':
            # already in the system, ignore
            pass
        else:
            raise