Ejemplo n.º 1
0
class Cart(models.Model):

    last_updated = models.DateTimeField(_("Last updated"), null=True)

    objects = managers.CartManager()

    def __iter__(self):
        """
        Allow the cart to be iterated giving access to the cart's items,
        ensuring the items are only retrieved once and cached.
        """
        if not hasattr(self, "_cached_items"):
            self._cached_items = self.items.all()
        return iter(self._cached_items)

    def add_item(self, variation, quantity):
        """
        Increase quantity of existing item if SKU matches, otherwise create
        new.
        """
        kwargs = {"sku": variation.sku, "unit_price": variation.price()}
        item, created = self.items.get_or_create(**kwargs)
        if created:
            item.description = unicode(variation)
            item.unit_price = variation.price()
            item.url = variation.product.get_absolute_url()
            image = variation.image
            if image is not None:
                item.image = unicode(image.file)
            variation.product.actions.added_to_cart()
        item.quantity += quantity
        item.save()

    def has_items(self):
        """
        Template helper function - does the cart have items?
        """
        return len(list(self)) > 0

    def total_quantity(self):
        """
        Template helper function - sum of all item quantities.
        """
        return sum([item.quantity for item in self])

    def total_price(self):
        """
        Template helper function - sum of all costs of item quantities.
        """
        return sum([item.total_price for item in self])

    def skus(self):
        """
        Returns a list of skus for items in the cart. Used by
        ``upsell_products`` and ``calculate_discount``.
        """
        return [item.sku for item in self]

    def upsell_products(self):
        """
        Returns the upsell products for each of the items in the cart.
        """
        cart = Product.objects.filter(variations__sku__in=self.skus())
        published_products = Product.objects.published()
        for_cart = published_products.filter(upsell_products__in=cart)
        with_cart_excluded = for_cart.exclude(variations__sku__in=self.skus())
        return list(with_cart_excluded.distinct())

    def calculate_discount(self, discount):
        """
        Calculates the discount based on the items in a cart, some
        might have the discount, others might not.
        """
        # Discount applies to cart total if not product specific.
        products = discount.all_products()
        if products.count() == 0:
            return discount.calculate(self.total_price())
        total = Decimal("0")
        # Create a list of skus in the cart that are applicable to
        # the discount, and total the discount for appllicable items.
        lookup = {"product__in": products, "sku__in": self.skus()}
        discount_variations = ProductVariation.objects.filter(**lookup)
        discount_skus = discount_variations.values_list("sku", flat=True)
        for item in self:
            if item.sku in discount_skus:
                total += discount.calculate(item.unit_price) * item.quantity
        return total
Ejemplo n.º 2
0
class Cart(models.Model):

    last_updated = models.DateTimeField(_("Last updated"), null=True)

    objects = managers.CartManager()

    def __iter__(self):
        """
        Allow the cart to be iterated giving access to the cart's items,
        ensuring the items are only retrieved once and cached.
        """
        if not hasattr(self, "_cached_items"):
            self._cached_items = self.items.all()
        return iter(self._cached_items)

    def add_item(self, variation, quantity, from_date=None, to_date=None):
        """
        Increase quantity of existing item if SKU matches, otherwise create
        new.
        """
        kwargs = {"sku": variation.sku, "unit_price": variation.price()}
        if variation.product.content_model == 'reservableproduct':
            # create always
            kwargs["cart"] = self
            item = CartItem(**kwargs)
            created = True
        else:
            item, created = self.items.get_or_create(**kwargs)
        if created:
            item.description = force_text(variation)
            item.unit_price = variation.price()
            item.url = variation.product.get_absolute_url()
            image = variation.image
            if image is not None:
                item.image = force_text(image.file)
            variation.product.actions.added_to_cart()
        item.quantity += quantity
        item.from_date = from_date
        item.to_date = to_date
        item.save()
        if variation.product.content_model == 'reservableproduct':
            # we also create a reservable cart reservation
            for date in utils.daterange(from_date, to_date):
                reservableproduct = ReservableProduct.objects.get(
                    product_ptr=variation.product.id)
                reservation = ReservableProductReservation(
                    date=date, product=reservableproduct)
                reservation.save()
                reservation_cart = ReservableProductCartReservation(
                    cart=self, reservation=reservation)
                reservation_cart.save()

    def has_items(self):
        """
        Template helper function - does the cart have items?
        """
        return len(list(self)) > 0

    def total_quantity(self):
        """
        Template helper function - sum of all item quantities.
        """
        return sum([item.quantity for item in self])

    def total_price(self):
        """
        Template helper function - sum of all costs of item quantities.
        """
        total = sum([item.total_price for item in self])
        for special in self.special_prices():
            total += special[2]
        return total

    def skus(self):
        """
        Returns a list of skus for items in the cart. Used by
        ``upsell_products`` and ``calculate_discount``.
        """
        return [item.sku for item in self]

    def upsell_products(self):
        """
        Returns the upsell products for each of the items in the cart.
        """
        if not settings.SHOP_USE_UPSELL_PRODUCTS:
            return []
        cart = Product.objects.filter(variations__sku__in=self.skus())
        published_products = Product.objects.published()
        for_cart = published_products.filter(upsell_products__in=cart)
        with_cart_excluded = for_cart.exclude(variations__sku__in=self.skus())
        return list(with_cart_excluded.distinct())

    def calculate_discount(self, discount):
        """
        Calculates the discount based on the items in a cart, some
        might have the discount, others might not.
        """
        # Discount applies to cart total if not product specific.
        products = discount.all_products()
        if products.count() == 0:
            return discount.calculate(self.total_price())
        total = Decimal("0")
        # Create a list of skus in the cart that are applicable to
        # the discount, and total the discount for appllicable items.
        lookup = {"product__in": products, "sku__in": self.skus()}
        discount_variations = ProductVariation.objects.filter(**lookup)
        discount_skus = discount_variations.values_list("sku", flat=True)
        for item in self:
            if item.sku in discount_skus:
                total += discount.calculate(item.unit_price) * item.quantity
        return total

    def special_prices(self):
        """
        Get all the special prices that affect this cart.
        """
        result = []
        items_done = []
        for item in self:
            variation = ProductVariation.objects.get(sku=item.sku)
            if variation.product.content_model == 'reservableproduct' and item in items_done:
                # only do each item once for reservables
                continue
            specials = SpecialPrice.objects.filter(product=variation.product,
                                                   special_type='WKD')
            for special in specials:
                # for reservables we check against days in reserved period
                # for other products we check against purchasing date
                if variation.product.content_model == 'reservableproduct':
                    reserved_days = ReservableProductCartReservation.objects.filter(
                        cart=self)
                    for reservation in reserved_days:
                        reservableproduct = ReservableProduct.objects.get(
                            product_ptr=variation.product.id)
                        if reservableproduct == reservation.reservation.product:
                            if reservation.reservation.date.isoweekday() in [
                                    5, 6
                            ]:
                                # reservation occurs on a weekend date
                                result.append(
                                    (variation.product.title, 'WKD',
                                     special.price_change, _("Weekend")))
                else:
                    if datetime.date.today().isoweekday() in [5, 6]:
                        # now occurs on a weekend date
                        result.append((variation.product.title, 'WKD',
                                       special.price_change, _("Weekend")))
            if variation.product.content_model == 'reservableproduct':
                reserved_days = ReservableProductCartReservation.objects.filter(
                    cart=self)
                for reservation in reserved_days:
                    reservableproduct = ReservableProduct.objects.get(
                        product_ptr=variation.product.id)
                    if reservableproduct == reservation.reservation.product:
                        try:
                            special = SpecialPrice.objects.get(
                                product=variation.product,
                                special_type='PER',
                                from_date__lte=reservation.reservation.date,
                                to_date__gte=reservation.reservation.date)
                            result.append(
                                (variation.product.title, 'PER',
                                 special.price_change, special.title))
                        except SpecialPrice.DoesNotExist:
                            pass

            items_done.append(item)
        return result

    def has_reservables(self):
        for item in self:
            if item.from_date and item.to_date:
                return True
        return False