Beispiel #1
0
def create_task_if_not_order(customer_id):
    customer = Customer.get_by_id(customer_id)
    # Check if the customer has linked his credit card after he clicked the 'pay' button
    # If he didn't (one hour after the last time he tried to pay), create a new ShopTask to call this customer.
    if not customer.stripe_valid and customer.team_id:
        if customer.prospect_id:
            rmt, prospect = db.get([
                RegioManagerTeam.create_key(customer.team_id),
                Prospect.create_key(customer.prospect_id)
            ])
        else:
            prospect = create_prospect_from_customer(customer)
            rmt = RegioManagerTeam.get(
                RegioManagerTeam.create_key(customer.team_id))
        azzert(rmt.support_manager,
               'No support manager found for team %s' % rmt.name)
        task = create_task(
            prospect_or_key=prospect,
            status=ShopTask.STATUS_NEW,
            task_type=ShopTask.TYPE_SUPPORT_NEEDED,
            address=None,
            created_by=STORE_MANAGER.email(),
            assignee=rmt.support_manager,
            execution_time=today() + 86400 + 11 * 3600,  # tomorrow, 11:00,
            app_id=prospect.app_id,
            comment=u"Customer wanted to pay an order in the customer store, "
            "but didn't succeed because he did not link his creditcard.",
            notify_by_email=True)
        task.put()
Beispiel #2
0
 def trans():
     prospect = Prospect(key_name=place_id,
                         name=name,
                         app_id=app.app_id,
                         type=[],
                         categories=[u'unclassified'],
                         address=address,
                         geo_point=db.GeoPt(lat, lon),
                         assignee=assignee,
                         status=Prospect.STATUS_ADDED_BY_DISCOVERY,
                         phone=''
                         )
     task = create_task(assignee, Prospect.create_key(place_id), assignee, now() + 86400, ShopTask.TYPE_CALL,
                        app.app_id, ShopTask.STATUS_NEW, address, u'Created prospect via discovery', None, None)
     db.put([prospect, task])
     return prospect
Beispiel #3
0
def job(cursor=None):
    qry = Prospect.all()
    if cursor:
        qry.with_cursor(cursor)

    prospects = qry.fetch(200)
    if not prospects:
        return
    to_put = list()
    index = search.Index(name=PROSPECT_INDEX)
    for prospect in prospects:
        try:
            index.delete(prospect.id)
        except ValueError:
            pass

        fields = [
            search.AtomField(name='key', value=prospect.id),
            search.TextField(name='name', value=prospect.name),
            search.TextField(name='address', value=prospect.address),
            search.TextField(name='phone', value=prospect.phone),
            search.TextField(name='email', value=prospect.email)
        ]
        doc = search.Document(doc_id=prospect.id, fields=fields)
        to_put.append(doc)

    index.put(to_put)
    deferred.defer(job, qry.cursor())
def _unassign_prospects(manager_email):
    logging.info('Unassigning regional manager %s from all prospects',
                 manager_email)
    to_put = []
    for prospect in Prospect.find_by_assignee(manager_email).fetch(None):
        prospect.assignee = None
        to_put.append(prospect)
    put_in_chunks(to_put)
def job(cursor=None):
    qry = Prospect.all()
    if cursor:
        qry.with_cursor(cursor)

    prospects = qry.fetch(200)
    if not prospects:
        return

    for p in prospects:
        if p.status == Prospect.STATUS_ADDED_BY_DISCOVERY:
            p.categories = ['unclassified']
        else:
            p.categories = Prospect.convert_place_types(p.type)

    db.put(prospects)

    deferred.defer(job, qry.cursor())
Beispiel #6
0
def search_prospects(query):
    """
    Uses the PROSPECT_INDEX search index to search for prospects based on their name, address, phone number and email.
    Args:
        query: The search query

    Returns:
        list(Prospect): List of prospects that match the search query.
    """
    if not query:
        return []
    search_index = search.Index(name=PROSPECT_INDEX)
    q = normalize_search_string(query)
    query = search.Query(query_string=q, options=search.QueryOptions(limit=20))

    search_result = search_index.search(query)
    prospect_keys = [Prospect.create_key(long(result.doc_id) if result.doc_id.isdigit() else result.doc_id) for result
                     in search_result.results]
    return Prospect.get(prospect_keys)
Beispiel #7
0
def job(cursor=None):
    qry = Prospect.all()
    if cursor:
        qry.with_cursor(cursor)

    prospects = qry.fetch(200)
    if not prospects:
        return

    for p in prospects:
        p.categories = list(set(p.categories))

    db.put(prospects)

    deferred.defer(job, qry.cursor())
Beispiel #8
0
def create_task_for_order(customer_team_id, prospect_id, order_number):
    team, prospect = db.get([
        RegioManagerTeam.create_key(customer_team_id),
        Prospect.create_key(prospect_id)
    ])
    azzert(team.support_manager,
           u'No support manager found for team %s' % team.name)
    comment = u'Customer placed a new order: %s' % (order_number)
    task = create_task(
        created_by=STORE_MANAGER.email(),
        prospect_or_key=prospect,
        app_id=prospect.app_id,
        status=ShopTask.STATUS_NEW,
        task_type=ShopTask.TYPE_SUPPORT_NEEDED,
        address=None,
        assignee=team.support_manager,
        comment=comment,
        execution_time=today() + 86400 + 11 * 3600,  # tomorrow at 11:00
        notify_by_email=True)
    task.put()
    broadcast_task_updates([team.support_manager])
Beispiel #9
0
    def trans():
        prospect = Prospect.get_by_key_name(place_id)
        if prospect:
            logging.debug('There already was a prospect for place %s',
                          place_id)
            return

        prospect = Prospect(
            key_name=place_id,
            app_id=app_id,
            name=result['name'],
            type=result['types'],
            categories=Prospect.convert_place_types(result['types']),
            address=address,
            geo_point=db.GeoPt(location['lat'], location['lng']),
            phone=phone_number,
            website=result.get('website'))
        prospect.put()
        deferred.defer(re_index_prospect, prospect, _transactional=True)
        deferred.defer(broadcast_prospect_creation,
                       None,
                       prospect,
                       _transactional=True)
    def trans():
        charge = None
        expired_subscription, customer = db.get([ExpiredSubscription.create_key(customer_id),
                                                       Customer.create_key(customer_id)])
        expired_subscription.status = status
        expired_subscription.status_updated_timestamp = now()

        if status == ExpiredSubscription.STATUS_WILL_LINK_CREDIT_CARD:
            # Create a task for regiomanager to check if the customer has linked his credit card after two weeks.
            # the ExpiredSubscription object from this customer will be cleaned up in recurrentbilling the day after he has linked it.
            to_put.append(expired_subscription)
            team, prospect = db.get([RegioManagerTeam.create_key(customer.team_id),
                                     Prospect.create_key(customer.prospect_id)])
            execution_time = now() + DAY * 14
            date_string = datetime.datetime.utcfromtimestamp(execution_time).strftime(u'%A %d %b %Y')
            comment = u'Check if the customer has linked his creditcard (for automatic subscription renewal).' \
                      u' If he hasn\'t linked it before %s, contact him again.' % date_string
            task = create_task(current_user.email(), prospect, team.support_manager, execution_time,
                               ShopTask.TYPE_CHECK_CREDIT_CARD, prospect.app_id, comment=comment)
            to_put.append(task)

        elif status == ExpiredSubscription.STATUS_EXTEND_SUBSCRIPTION:
            # Creates a new charge using the customer his subscription order.
            subscription_order, team = db.get([Order.create_key(customer.id, customer.subscription_order_number),
                                               RegioManagerTeam.create_key(customer.team_id)])
            extension_order_item_keys = list()
            order_items = list(OrderItem.list_by_order(subscription_order.key()))
            products_to_get = list()
            for item in order_items:
                products_to_get.append(Product.create_key(item.product_code))
            products = {p.code: p for p in Product.get(products_to_get)}
            # extend per year
            months = 12
            total_amount = 0
            for item in order_items:
                product = products[item.product_code]
                if product.is_subscription and item.price > 0:
                    total_amount += months * item.price
                elif not product.is_subscription and (product.is_subscription_discount or product.extra_subscription_months > 0):
                    total_amount += months * item.price
                elif product.is_subscription_extension:
                    total_amount += months * item.price
                    extension_order_item_keys.append(item.key())

            if total_amount <= 0:
                raise BusinessException('The created charge has a negative amount (%d)' % total_amount)
            next_charge_datetime = datetime.datetime.utcfromtimestamp(now()) + relativedelta(months=months)
            subscription_order.next_charge_date = get_epoch_from_datetime(next_charge_datetime)
            to_put.append(subscription_order)

            # reconnect all previously connected friends if the service was disabled in the past
            if customer.service_disabled_at != 0:
                deferred.defer(set_service_enabled, customer.id, _transactional=True)

            vat_pct = get_vat_pct(customer, team)
            charge = Charge(parent=subscription_order)
            charge.date = now()
            charge.type = Charge.TYPE_SUBSCRIPTION_EXTENSION
            charge.subscription_extension_length = months
            charge.subscription_extension_order_item_keys = extension_order_item_keys
            charge.amount = total_amount
            charge.vat_pct = vat_pct
            charge.vat = int(total_amount * vat_pct / 100)
            charge.total_amount = charge.amount + charge.vat
            charge.currency_code = team.legal_entity.currency_code
            to_put.append(charge)
            to_delete.append(expired_subscription)

        db.put(to_put)
        if to_delete:
            db.delete(to_delete)

        return charge
Beispiel #11
0
def _get_all_prospects():
    return Prospect.all()
Beispiel #12
0
def generate_prospect_export_excel(prospect_ids, do_send_email=True, recipients=None):
    if not prospect_ids:
        raise BusinessException('No prospects to export')
    azzert(not do_send_email or recipients)
    bold_style = xlwt.XFStyle()
    bold_style.font.bold = True
    column_name, column_address, column_city, column_phone, column_status, column_type, column_categories, column_comments = range(8)

    book = xlwt.Workbook(encoding="utf-8")
    sheet = book.add_sheet('Prospects')
    prospects = Prospect.get(map(Prospect.create_key, prospect_ids))
    app_id = None

    sheet.write(0, column_name, 'Name', bold_style)
    sheet.write(0, column_address, 'Address', bold_style)
    sheet.write(0, column_city, 'City', bold_style)
    sheet.write(0, column_phone, 'Phone', bold_style)
    sheet.write(0, column_status, 'Status', bold_style)
    sheet.write(0, column_type, 'Type', bold_style)
    sheet.write(0, column_categories, 'Category', bold_style)
    sheet.write(0, column_comments, 'Comments', bold_style)
    for i, prospect in enumerate(prospects):
        row = i + 1
        comments_str = '\n'.join(['* %s' % comment.text for comment in prospect.comments])
        sheet.write(row, column_name, prospect.name)
        formatted_address = format_address(prospect.address)
        sheet.write(row, column_address, formatted_address[0])
        sheet.write(row, column_city, formatted_address[1])
        sheet.write(row, column_phone, prospect.phone)
        sheet.write(row, column_status, Prospect.STATUS_TYPES[prospect.status])
        sheet.write(row, column_type, ', '.join(prospect.type))
        sheet.write(row, column_categories, ', '.join(prospect.categories))
        sheet.write(row, column_comments, comments_str)
        sheet.col(column_name).width = 5000
        sheet.col(column_address).width = 5000
        sheet.col(column_phone).width = 5000
        sheet.col(column_status).width = 5000
        sheet.col(column_type).width = 10000
        sheet.col(column_categories).width = 10000
        sheet.col(column_comments).width = 20000
        if not app_id:
            app_id = prospect.app_id
    excel = StringIO()
    book.save(excel)
    excel_string = excel.getvalue()

    if do_send_email:
        app = get_app_by_id(app_id)
        solution_server_settings = get_solution_server_settings()
        current_date = format_datetime(datetime.datetime.now(), locale=DEFAULT_LANGUAGE)
        subject = 'Exported prospects of %s %s' % (app.name, current_date)
        from_email = solution_server_settings.shop_export_email
        to_emails = recipients
        body_text = 'See attachment for the exported prospects'
        
        attachments = []
        attachments.append(('Prospects %s %s.xls' % (app.name, current_date),
                            base64.b64encode(excel_string)))
        
        send_mail(from_email, to_emails, subject, body_text, attachments=attachments)
    return excel_string
Beispiel #13
0
def create_prospect_from_customer(customer):
    azzert(customer.prospect_id is None and customer.service_email)

    contact = Contact.get_one(customer.key())
    azzert(contact)

    si = get_default_service_identity(users.User(customer.service_email))

    prospect = Prospect(key_name=str(uuid.uuid4()) + str(uuid.uuid4()))
    prospect.name = customer.name
    prospect.address = ', '.join(filter(None, [customer.address1 + ((' ' + customer.address2) if customer.address2 else ''),
                                               customer.zip_code,
                                               customer.city,
                                               OFFICIALLY_SUPPORTED_COUNTRIES.get(customer.country, customer.country)]))
    prospect.phone = contact.phone_number
    prospect.email = contact.email
    prospect.type = ['establishment']
    if customer.organization_type == OrganizationType.EMERGENCY:
        prospect.type.append('health')
    prospect.customer_id = customer.id
    prospect.status = Prospect.STATUS_CUSTOMER
    prospect.app_id = si.app_id
    
    solution_server_settings = get_solution_server_settings()
    prospect.add_comment(u'Converted customer to prospect', users.User(solution_server_settings.shop_no_reply_email)) 
    try:
        result = geo_code(prospect.address)
    except GeoCodeZeroResultsException:
        try:
            result = geo_code(' '.join(filter(None, [customer.zip_code,
                                                     customer.city,
                                                     OFFICIALLY_SUPPORTED_COUNTRIES.get(customer.country,
                                                                                        customer.country)])))
        except GeoCodeZeroResultsException:
            logging.warn('Could not geo_code customer: %s', db.to_dict(customer))
            return

    prospect.geo_point = db.GeoPt(result['geometry']['location']['lat'],
                                  result['geometry']['location']['lng'])

    customer.prospect_id = prospect.id
    prospect.customer_id = customer.id

    logging.info('Creating prospect: %s', db.to_dict(prospect, dict(prospect_id=prospect.id)))
    put_and_invalidate_cache(customer, prospect)
    return prospect
Beispiel #14
0
    def trans():
        customer_id = order_key.parent().id()
        order, customer = db.get([order_key, Customer.create_key(customer_id)])
        if not order.next_charge_date:
            logging.warning(
                'Not creating recurrent charge for order %s (%s: %s) because no next charge date is set',
                order.order_number, customer_id, customer.name)
            return None
        elif order.next_charge_date > today:
            # Scenario: this job fails today, tomorrow this job runs again and fails again
            # -> 2 jobs for the same order would create 2 charges when the bug is fixed
            logging.warning(
                'This order has already been charged this month, skipping... %s (%s: %s)',
                order.order_number, customer_id, customer.name)
            return None
        elif customer.subscription_cancel_pending_date:
            logging.info('Disabling service from customer %s (%d)',
                         customer.name, customer.id)
            try:
                cancel_order(customer, order.order_number)
            except OrderAlreadyCanceledException as exception:
                logging.info('Order %s already canceled, continuing...',
                             exception.order.order_number)

            set_service_disabled(customer, Customer.DISABLED_OTHER)
            cleanup_expired_subscription(customer)
            return None

        logging.info("Creating recurrent charge for order %s (%s: %s)",
                     order.order_number, customer_id, customer.name)
        subscription_extension_orders = list(
            Order.all().ancestor(customer).filter(
                "next_charge_date <",
                today).filter("is_subscription_order =", False).filter(
                    'is_subscription_extension_order =',
                    True).filter("status =",
                                 Order.STATUS_SIGNED))  # type: list[Order]
        subscription_extension_order_keys = [
            o.key() for o in subscription_extension_orders
        ]
        order_item_qry = OrderItem.all().ancestor(
            customer if subscription_extension_order_keys else order)

        subscription_extension_order_item_keys = []
        total_amount = 0
        subscription_length = 0
        current_date = datetime.datetime.utcnow()
        to_put = []
        for order_item in order_item_qry:  # type: OrderItem
            product = products[order_item.product_code]
            if order_item.order_number == order.order_number:
                if product.is_subscription:
                    subscription_length = order_item.count
                if product.is_subscription or product.is_subscription_discount or product.is_subscription_extension:
                    if product.charge_interval != 1:
                        last_charge_date = datetime.datetime.utcfromtimestamp(
                            order_item.last_charge_timestamp)
                        new_charge_date = last_charge_date + relativedelta(
                            months=product.charge_interval)
                        if new_charge_date < current_date:
                            logging.debug(
                                'new_charge_date %s < current_date %s, adding %s to total_amount',
                                new_charge_date, current_date,
                                order_item.price)
                            total_amount += order_item.price
                            order_item.last_charge_timestamp = now()
                            to_put.append(order_item)
                    else:
                        total_amount += order_item.price

            elif order_item.parent().key(
            ) in subscription_extension_order_keys:
                if product.is_subscription_extension:
                    total_amount += order_item.price
                    subscription_extension_order_item_keys.append(
                        order_item.key())
        if total_amount == 0:
            order.next_charge_date = Order.default_next_charge_date()
            order.put()
            logging.info(
                "Skipping, cannot calculate recurrent charge of 0 euros for order %s (%s: %s)",
                order.order_number, customer_id, customer.name)
            return None

        if subscription_length == 0:
            raise Exception('subscription_length is 0')

        if not (customer.stripe_id and
                customer.stripe_credit_card_id) and subscription_length != 1:
            logging.debug(
                'Tried to bill customer, but no credit card info was found')
            audit_log(
                customer.id,
                'Tried to bill customer, but no credit card info was found')
            # Log the customer as expired. If this has not been done before.
            expired_subscription_key = ExpiredSubscription.create_key(
                customer_id)
            if not ExpiredSubscription.get(expired_subscription_key):
                to_put.append(
                    ExpiredSubscription(
                        key=expired_subscription_key,
                        expiration_timestamp=order.next_charge_date))
                # Create a task for the support manager
                assignee = customer.manager and customer.manager.email()
                if customer.team_id is not None:
                    team = RegioManagerTeam.get_by_id(customer.team_id)
                    if team.support_manager:
                        assignee = team.support_manager
                if assignee:
                    if customer.prospect_id:
                        prospect = Prospect.get(
                            Prospect.create_key(customer.prospect_id))
                    else:
                        # We can only create tasks for prospects. So we must create a prospect if there was none.
                        prospect = create_prospect_from_customer(customer)
                        customer.prospect_id = prospect.id
                        to_put.append(customer)
                        to_put.append(prospect)
                    to_put.append(
                        create_task(
                            created_by=None,
                            prospect_or_key=prospect,
                            assignee=assignee,
                            execution_time=today + 11 * 3600,
                            task_type=ShopTask.TYPE_SUPPORT_NEEDED,
                            app_id=prospect.app_id,
                            status=ShopTask.STATUS_NEW,
                            comment=
                            u"Customer needs to be contacted for subscription renewal",
                            notify_by_email=True))
                put_and_invalidate_cache(*to_put)
            return None
        else:
            cleanup_expired_subscription(customer)

        @db.non_transactional  # prevent contention on entity group RegioManagerTeam
        def get_currency_code():
            return customer.team.legal_entity.currency_code

        charge = Charge(parent=order_key)
        charge.date = now()
        charge.type = Charge.TYPE_RECURRING_SUBSCRIPTION
        charge.subscription_extension_length = 1
        charge.subscription_extension_order_item_keys = subscription_extension_order_item_keys
        charge.currency_code = get_currency_code()
        charge.team_id = customer.team_id
        charge.amount = total_amount
        charge.vat_pct = order.vat_pct
        charge.vat = int(total_amount * order.vat_pct / 100)
        charge.total_amount = charge.amount + charge.vat
        to_put.append(charge)

        next_charge_datetime = datetime.datetime.utcfromtimestamp(
            order.next_charge_date) + relativedelta(months=1)
        next_charge_date_int = int(
            (next_charge_datetime -
             datetime.datetime.utcfromtimestamp(0)).total_seconds())
        order.next_charge_date = next_charge_date_int
        to_put.append(order)
        for extension_order in subscription_extension_orders:
            extension_order.next_charge_date = next_charge_date_int
            to_put.append(extension_order)

        put_and_invalidate_cache(*to_put)
        return charge