예제 #1
0
    def order_refunded(self, order):
        """
        The seller has refunded an order
        """
        context = self._order_context(order)
        self._sendmail('order-refunded-to-customer', order.user.email, context)

        self._sendmail('order-refunded-to-stall-owner', order.stall.user.email,
                       context)

        try:
            # Track the Seller refunding the Order
            order_info = self._mixpanel_order_info(order)
            mixpanel_track(self.request, "Clicked Refund Button", order_info)
            mixpanel_engage(self.request, {'$add': {'Refunds Made': 1}})

            # Update the Buyers properties, reducing their GMV
            # XXX: we can't delete the transaction after it's refunded!!!
            #      adding the transaction needs to happen on Dispatch
            user = order.user
            stall = order.stall
            mixpanel_engage(None, {
                '$set': {
                    'Orders': user.orders.completed().count(),
                    'Total GMV to Date': str(
                        user.get_profile().total_gmv.amount),
                },
                '$ignore_time': True
            },
                            distinct_id=user.id)
        except:
            LOG.warning("Couldn't notify MixPanel of refund", exc_info=True)
예제 #2
0
    def user_followed(self, follow):
        """
        :param follow: UserFollow object which has just been created
        """
        mixpanel_track(self.request, "Followed User",
                       {"followed_user": follow.target.username})

        mixpanel_engage(self.request, get_mixpanel_info(follow.user),
                        follow.user.id)

        mixpanel_engage(self.request,
                        get_mixpanel_info(follow.target, ignore_time=True),
                        follow.target.id)

        template_name = 'new-follower-notification'
        context = {
            'USER_USERNAME':
            follow.user.username,
            'USER_PROFILE_URL':
            absolute_uri(follow.user.get_profile().get_absolute_url()),
            'TARGET_USER_USERNAME':
            follow.target.username,
            'TARGET_USER_PROFILE_URL':
            absolute_uri(follow.target.get_profile().get_absolute_url())
        }
        print absolute_uri(follow.user.get_profile().get_absolute_url()), \
            absolute_uri(follow.target.get_profile().get_absolute_url())
        email_notification = follow.target.email_notification
        if email_notification.follower_notifications:
            self._sendmail(template_name, follow.target.email, context)
        else:
            LOG.info(
                "Email not send to %s, since follower_notifications is set to OFF",
                follow.target.email)
예제 #3
0
    def order_placed(self, order):
        """
         1) Syncs cart with SailThru
         2) Sends 'Order Completed' e-mail to customer via Sailthru
         3) Syncs order information with MixPanel
        """
        # Technically the transaction isn't complete yet because the seller hasn't
        # marked the order as complete so could potentially refund the money.
        try:
            context = self._order_context(order)
            self._sendmail('order-placed-to-customer', order.user.email,
                           context)

            self._sendmail('order-placed-to-stall-owner',
                           order.stall.user.email, context)
        except:
            LOG.error("Events.order_placed failed to send email",
                      exc_info=True)

        # Send completed order to SailThru, this updates the users 'Total Revenue'
        try:
            self.sailthru.order_purchased(order)
        except:
            LOG.error("Events.order_placed failed to sync order with SailThru",
                      exc_info=True)

        # Sync user properties with MixPanel
        try:
            user = order.user
            mixpanel_engage(self.request, {
                '$set': {
                    'Orders': user.orders.completed().count(),
                    'Total GMV to Date': str(
                        user.get_profile().total_gmv.amount),
                }
            },
                            distinct_id=user.id)
            mixpanel_engage(self.request, {
                '$append': {
                    '$transactions': {
                        '$time': order.created.isoformat(),
                        '$amount': str(order.total().amount),
                        'Order ID': order.id
                    }
                }
            },
                            distinct_id=user.id)
            if self.request is not None:
                order_info = self._mixpanel_order_info(order)
                mixpanel_track(self.request, "Purchased Order", order_info)
        except:
            LOG.warning("Couldn't notify MixPanel of new order", exc_info=True)
예제 #4
0
    def user_unfollowed(self, unfollow):
        """
        :param unfollow: UserFollow object which is about to be deleted
        """
        mixpanel_track(self.request, "Unfollowed User",
                       {"followed_user": unfollow.target.username})

        mixpanel_engage(self.request, get_mixpanel_info(unfollow.user),
                        unfollow.user.id)

        mixpanel_engage(self.request,
                        get_mixpanel_info(unfollow.target, ignore_time=True),
                        unfollow.target.id)
예제 #5
0
def checkout_add(request, slug):
    """
    Adds product to cart.
    """
    product = get_object_or_404(Product, slug=slug)
    country = None
    if request.POST.get('shipping_country', None):
        try:
            country = Country.objects.get(
                code=request.POST.get('shipping_country', None))
        except:
            pass

    # When no cart is found, send them to login - where all users have carts
    if getattr(request.user, 'cart', None) is None:
        # This allows a streamlined log in process, the product_to_add_id
        # session variable is used by the register view to add a product
        # to the cart and redirect straight to the cart view.
        request.session["product_to_add_id"] = product.id
        login_url = reverse('login')
        return redirect_to_login(reverse('checkout_cart'), login_url=login_url)

    cart = request.user.cart
    try:
        # If the user is anonymous the cart won't exist in the DB yet
        # This avoids doing a DB insert for every request.
        if cart.id is None:
            cart.save()
        cart.add(product, country=country)
        mixpanel_track(
            request, 'Clicked Add to Cart', {
                'Product Title':
                product.title,
                'Product ID':
                product.id,
                'Number in stock':
                'unlimited' if product.stock is None else product.stock,
                'Number of Images':
                product.images.all().count(),
                'Has Welcome Video':
                product.stall.has_welcome_video(),
                'Ships Worldwide':
                product.shipping_profile.ships_worldwide(),
                'Price':
                str(product.get_price_instance().amount)
            })
        Events(request).cart_updated(cart)
    except purchase.models.OutOfStockError:
        messages.error(request, "That product is out of stock")
    return HttpResponseRedirect(reverse('checkout_cart'))
예제 #6
0
    def logged_in(self, user):
        """
        The user has logged in to the site

        :param user: User object
        """
        # Integration with sailthru
        if self.sailthru.enabled():
            self.sailthru.login(user)

        # Internal LifetimeTrack
        try:
            lt = LifetimeTrack.objects.get(user=user)
            merge_lifetime_track(self.request.lifetime_track, lt)
        except Exception as e:
            print "=-" * 34, e

        # Integration with mixpanel
        try:
            mixpanel_track(self.request, "logged in",
                           {"$last_seen": datetime.datetime.now()})
            mixpanel_engage(self.request, {'$add': {'Times Logged In': 1}})
            try:
                has_stall = user.stall is not None
            except:
                has_stall = False
            if has_stall:
                member_type = 'Regular'
            else:
                member_type = 'Stall Owner'
            mixpanel_engage(
                self.request, {
                    '$set': {
                        'last_login': datetime.datetime.now().isoformat(),
                        '$email': user.email,
                        '$username': user.username,
                        '$created': user.date_joined.isoformat(),
                        "$last_seen": datetime.datetime.now().isoformat(),
                        '$first_name': user.first_name,
                        '$last_name': user.last_name,
                        'gender': user.user_profile.get_gender_display(),
                        'mp_name_tag': user.get_full_name(),
                        'Member Type': member_type,
                    }
                })
        except:
            LOG.warn('Could not send login event to MixPanel', exc_info=True)
예제 #7
0
    def _confirm_stock_check(self):
        """
        Updates the stalls last stock check datetime.

        :return:
        """
        now = datetime.now(tz=pytz.utc)
        self.stall.last_stock_checked_at = now

        # If the stall is at a very frequent stock check level,
        # then move them to a 30 day level after a successful
        # stock check is complete.
        if self.stall.renewal_tier < 3:
            self.stall.renewal_tier = 3
        
        if self.stall.is_suspended:
            self.stall.products.filter(
                status=Product.PUBLISHED_SUSPENDED
            ).update(
                status=Product.PUBLISHED_LIVE,
                updated=now
            )
            self.stall.is_suspended = False

            status = StallStatusLog()
            status.stall = self.stall
            status.renewal_tier = self.stall.renewal_tier
            status.is_suspended = False
            status.reason_for_suspension = None
            status.updated_at = now
            status.save()
        self.stall.save()

        mixpanel_track(
            self.request,
            'Renewed Products',
        )

        messages.success(self.request, 'Thanks! Your stock check is done. '
           'You will need to do another stock check within the next %d days. '
           'We do however suggest that if your inventory changes frequently '
           'that you log in to Eco Market and and do these stock checks more often. '
           'You can do a stock check as many times as you like at any time, '
           'but at the moment you as required to do one every 30 days to keep '
           'your products live in our marketplace.'
           % _get_days_to_next_stockcheck(self.request))
예제 #8
0
    def get(self, request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseRedirect(
                reverse('stockcheck_landing')
            )

        # Handle stall owners who have no products at all
        # https://app.asana.com/0/8319277024263/8336587616129
        if not request.user.stall.products.count():
            messages.info(request, 'It seems like you are trying to do a stock '
                'check but you have no products listed. You are not required to do '
                'a stock check at the moment.')
            return HttpResponseRedirect(
                reverse('selling')
            )

        # Handle stall owners with just unpublished products
        # https://app.asana.com/0/8319277024263/8336587616134
        if (not request.user.stall.products.filter(status=Product.PUBLISHED_LIVE).count() and
            not request.user.stall.products.filter(status=Product.PUBLISHED_SUSPENDED).count()):
            messages.info(request, 'It seems like you are trying to do a stock '
                'check but you have no live or out of stock products. You cannot '
                'do a stock check on unpublished products (since they are '
                'completely removed from Eco Market) so first you must republish '
                'them, then you may do a stock check on these items. You can '
                '<a href="%(url)s" target="_blank">read more</a> about the difference between '
                'unpublishing items and editing stock.' % dict(
                    url='http://help.ecomarket.com/customer/portal/articles/1346382'
                ))
            return HttpResponseRedirect(
                reverse('selling')
            )

        mixpanel_track(
            request,
            'Viewed Stockcheck Page'
        )

        messages.success(self.request, 'Thanks for helping us keep your items up to date on Eco Market. '
            'To find out more on what this stock check is and a video tutorial explaining how '
            'to use them you can see this <a href="%(url)s" target="_blank">help centre article</a>.' % dict(
                url='http://help.ecomarket.com/customer/portal/articles/1342284'
            ))

        return super(StockcheckUpdateView, self).get(request, *args, **kwargs)
예제 #9
0
def stockcheck_start(request, template_name='accounts/stockcheck/landing.html'):
    """
    Allow a user to log in with either username/email and password.

    """
    next_url = reverse('stockcheck_update')
    context = {
        'next': next_url,
        'social_login_error': int(request.GET.get('social-login-error', 0)),
    }

    mixpanel_track(
        request,
        'Clicked CTA In Renewal Email'
    )

    data = request.POST or None
    login_form = LoginForm(data=data)

    if request.user.is_authenticated():
        return HttpResponseRedirect(next_url)

    if login_form.is_valid():
        username = login_form.cleaned_data.get('username', None)
        password = login_form.cleaned_data.get('password', None)

        user = authenticate(username=username, password=password)
        login_success = user and not user.is_anonymous()
        if login_success:
            login(request, user)
            Events(request).logged_in(user)
            if not request.POST.get('remember_me', None):
                expiry = 0
            else:
                expiry = SESSION_EXPIRY

            request.session.set_expiry(expiry)
            return HttpResponseRedirect(next_url)

    context.update({'login_form': login_form})

    return render(request, template_name, context)
예제 #10
0
    def message_sent(self, msg):
        """
        A new message has been sent, notify the recipient via e-mail

        :param msg: Message object
        """
        if not msg.parent_msg:
            template_name = "new-message-received"
        else:
            template_name = "message-reply-received"

        # TODO: notification settings

        context = {
            "SENDER_USERNAME": msg.sender.username,
            "MESSAGE_SUBJECT": msg.subject,
            "MESSAGE_BODY": msg.body,
            'MESSAGE_VIEW_URL': absolute_uri(reverse('messaging_inbox'))
        }

        # send mail to hipchat
        template_context = Context({
            'request': self.request,
            'message': msg,
        })
        template = loader.get_template(
            "messaging/fragments/hipchat_message.html")
        output = template.render(template_context)

        send_to_hipchat(
            output,
            room_id=settings.HIPCHAT_MAIL_ROOM,
            notify=1,
        )

        mixpanel_track(self.request, "Sent Message", {})
        mixpanel_engage(self.request, {'$add': {'Messages Sent': 1}})

        self._sendmail(template_name, msg.recipient.email, context)
예제 #11
0
    def order_dispatched(self, order):
        """
        The seller has marked an order as dispatched
        """
        try:
            context = self._order_context(order)
            self._sendmail('order-dispatched-to-customer', order.user.email,
                           context)
        except:
            LOG.warning("Couldn't send Order Dispatched email to Customer",
                        exc_info=True)

        try:
            order_info = self._mixpanel_order_info(order)
            mixpanel_track(self.request, 'Clicked Mark Order as Dispatched',
                           order_info)
            mixpanel_engage(self.request, {'$add': {
                'Orders Dispatched': 1
            }},
                            distinct_id=order.stall.user.id)
        except:
            LOG.warning("Couldn't update MixPanel after Order Dispatch",
                        exc_info=True)
예제 #12
0
def checkout_shipping(request, cart_stall_id):
    """Asks the user to select a shipping address or create one"""
    if not isinstance(cart_stall_id, CartStall):
        cart_stall = get_object_or_404(CartStall, id=cart_stall_id)
    else:
        cart_stall = cart_stall_id
        cart_stall_id = cart_stall.id
    address_form = None
    address_with_error = None
    if request.method == "POST":
        address = None
        if "shipping_address_id" in request.POST:
            address_id = request.POST["shipping_address_id"]
            address = ShippingAddress.objects.get(id=address_id)
        else:
            # We have a new shipping address to validate and create
            share_orders = request.POST.get('check_order_in_activity_feed',
                                            False)
            request.session['check_orders_in_activity_feed'] = share_orders

            address_form = ShippingAddressForm(request.POST)
            if address_form.is_valid():
                address = address_form.save(commit=False)
                address.user = request.user
                address.save()
        if address:
            address.last_select_date_time = timezone.now()
            address.save()
            try:
                cart_stall.set_address(address)
                cart_stall.save()
                return redirect(
                    reverse('checkout_pay_stall',
                            kwargs={"cart_stall_id": cart_stall.id}))
            except purchase.models.MismatchingCountryError:
                print("Mismatching country")
                messages.error(
                    request,
                    'Oops. Your delivery prices have been worked out for %s '
                    'only so the address you have selected isn\'t suitable. '
                    'You can add/edit your addresses below or '
                    '<a href="%s" title="Back to your cart">go back to your cart</a> '
                    'to edit your delivery prices for the country you would like to deliver to.'
                    % (cart_stall.speculative_country.title,
                       reverse('checkout_cart')))
                address_with_error = address.id
                address_form = None  # We save this address as is, even though it can't be shipped.
            except purchase.models.UnavailableShippingCountryError:
                messages.error(
                    request, "Sorry that country isn't available for delivery")
                address_with_error = address.id
                address_form = None  # We save this address as is, even though it can't be shipped.

    if address_form is None:
        address_form = ShippingAddressForm()

    share_orders = request.user.email_notification.share_orders_in_activity_feed
    request.session['check_orders_in_activity_feed'] = share_orders

    existing_addresses = request.user.addresses.all().order_by('-pk')
    context = {
        "cart_stall":
        cart_stall,
        "shipping_addresses":
        existing_addresses,
        "shipping_addresses_by_use":
        request.user.addresses.all().order_by('-last_select_date_time'),
        "address_form":
        address_form,
        'share_orders':
        request.session['check_orders_in_activity_feed'],
        "address_with_error":
        address_with_error,
    }
    mixpanel_track(request, 'Clicked Continue to Payment at Delivery', {})
    request.clicktale.record = True
    return render(request, "purchase/checkout_shipping.html", context)