예제 #1
0
        def get_products(self):
            """
            Get all active products for the current category.

            As opposed to the original function in the base class, this also
            includes products in subcategories of the current category object.

            """

            from shopkit.core.settings import PRODUCT_MODEL
            from shopkit.core.utils import get_model_from_string

            product_class = get_model_from_string(PRODUCT_MODEL)

            in_shop = product_class.in_shop
            descendants = self.get_descendants(include_self=True)

            # To do: Create in_category manager for products to circumvent
            # this awkward lookup
            if hasattr(product_class, "categories"):
                return in_shop.filter(categories__in=descendants).distinct()
            else:
                # Distinct not necessary - product can only be in one
                # category. Haha.
                return in_shop.filter(category__in=descendants)
예제 #2
0
    def get_shipping_method(self, **kwargs):
        """
        Return the cheapest shipping method or an order or item.

        .. todo::
            This code is probably a bit too low-level.
        """

        assert 'order_methods' in kwargs or 'item_methods' in kwargs, \
            'We need either a restriction to order shipping methods or '+ \
            'item shipping methods in order to find the cheapest method.'

        shipping_method_class = get_model_from_string(SHIPPING_METHOD_MODEL)

        shipping_address = getattr(self, 'shipping_address', None)
        if not 'country' in kwargs and shipping_address:
            assert self.shipping_address.country

            country = self.shipping_address.country

            logger.debug(u'Using country %s to find cheapest shipping method for %s',
                         country, self)

            kwargs['country'] = country

        shipping_method = shipping_method_class.get_cheapest(**kwargs)

        logger.debug(u'Found shipping method %s for %s', shipping_method, self)

        return shipping_method
예제 #3
0
    def from_cart(cls, cart):
        """
        Instantiate an order based on the basis of a
        shopping cart, copying all the items.
        """

        assert cart.customer

        order = cls(customer=cart.customer, cart=cart)

        # Save in order to be able to associate items
        order.save()

        orderitem_class = get_model_from_string(ORDERITEM_MODEL)

        for cartitem in cart.cartitem_set.all():
            orderitem = orderitem_class.from_cartitem(cartitem=cartitem,
                                                      order=order)
            orderitem.save()

            assert orderitem, 'Something went wrong creating an \
                               OrderItem from a CartItem.'
            assert orderitem.pk

        assert len(cart.get_items()) == len(order.get_items())

        return order
예제 #4
0
def get_product_choices():
    """ Get available products for shopping cart. This
        has to be wrapped in a SimpleLazyObject, otherwise
        Sphinx will complain in the worst ways. """
    product_class = get_model_from_string(PRODUCT_MODEL)
    
    return product_class.in_shop.all()
예제 #5
0
    def get_products(self):
        """ Get all active products for the current category.
        """

        from shopkit.core.settings import PRODUCT_MODEL
        from shopkit.core.utils import get_model_from_string
        product_class = get_model_from_string(PRODUCT_MODEL)

        return product_class.in_shop.filter(category=self)
예제 #6
0
    def setUp(self):
        """
        We want to have the category class available in `self`.
        """

        super(CategoryTestMixinBase, self).setUp()

        self.category_class = \
            get_model_from_string(settings.SHOPKIT_CATEGORY_MODEL)
예제 #7
0
    def _update_state(self, message=None):
        """
        Update the order state, optionaly attach a message to the state
        change. When no message has been given and the order state is the
        same as the previous order state, no action is performed.
        """

        assert self.pk, 'Cannot update state for unsaved order.'

        orderstate_change_class = \
            get_model_from_string(ORDERSTATE_CHANGE_MODEL)

        latest_statechange = orderstate_change_class.get_latest(order=self)

        if latest_statechange:
            latest_state = latest_statechange.state
        else:
            latest_state = None

        logger.debug(
            u'Considering state change: %s %s %s',
            self,
            latest_state,
            self.state
        )

        if latest_state is None or latest_state != self.state or message:
            state_change = orderstate_change_class(state=self.state,
                                                   order=self,
                                                   message=message)
            state_change.save()

            # There's a new state change to be made
            logger.debug(
                u'Saved state change from %s to %s for %s with message \'%s\'',
                latest_state,
                self.state,
                self,
                message
            )

            # Send order_state_change signal
            results = signals.order_state_change.send_robust(
                sender=self,
                old_state=latest_state,
                new_state=self.state,
                state_change=state_change
            )

            # Re-raise exceptions in listeners
            for (receiver, response) in results:
                if isinstance(response, Exception):
                    raise response

        else:
            logger.debug(u'Same state %s for %s, not saving change.',
                         self.state, self)
예제 #8
0
    def setUp(self):
        """ 
        This function gets the model classes from `settings.py` and
        makes them available as `self.cusomter_class`, `self.product_class` 
        etcetera.
        """
        super(CoreTestMixin, self).setUp()
        
        self.customer_class = \
            get_model_from_string(settings.SHOPKIT_CUSTOMER_MODEL)
        
        self.product_class = \
            get_model_from_string(settings.SHOPKIT_PRODUCT_MODEL)
        
        self.cart_class = \
            get_model_from_string(settings.SHOPKIT_CART_MODEL)

        self.cartitem_class = \
            get_model_from_string(settings.SHOPKIT_CARTITEM_MODEL)

        self.order_class = \
            get_model_from_string(settings.SHOPKIT_ORDER_MODEL)

        self.orderitem_class = \
            get_model_from_string(settings.SHOPKIT_ORDERITEM_MODEL)
def cart(request):
    """
    Request context processor adding the shopping cart to the current
    context as `cart`.

    .. todo::
        Make this lazy object: we should only perform the actual
        database query when this object is requested from within
        template.

    """
    cart_class = get_model_from_string(CART_MODEL)
    return {'cart': cart_class.from_request(request)}
예제 #10
0
    def confirm(self):
        """
        Register discount usage.
        """

        # Call registration for superclass
        super(AccountedDiscountedItemMixin, self).confirm()

        # Make sure we're of the proper type so we have a discounts property
        assert isinstance(self, PersistentDiscountedItemBase)

        discount_class = get_model_from_string(DISCOUNT_MODEL)

        discounts = self.discounts.all()

        # Register discount usage for order
        discount_class.register_use(discounts)
예제 #11
0
    def get_products(self):
        """ Get all active products for the current category.

            For performance reasons, and added control, this only
            returns only products explicitly associated to this
            category - as opposed to listing also products in subcategories
            of the current category.

            This would take a lot more requests and is probably not
            what we should wish for.
        """

        from shopkit.core.settings import PRODUCT_MODEL
        from shopkit.core.utils import get_model_from_string
        product_class = get_model_from_string(PRODUCT_MODEL)

        return product_class.in_shop.filter(categories__in=self)
예제 #12
0
        def get_products(self):
            """
            Get all active products for the current category.

            As opposed to the original function in the base class, this also
            includes products in subcategories of the current category object.

            """

            from shopkit.core.settings import PRODUCT_MODEL
            from shopkit.core.utils import get_model_from_string

            product_class = get_model_from_string(PRODUCT_MODEL)

            in_shop = product_class.in_shop
            descendants = self.get_descendants(include_self=True)

            return in_shop.filter(categories__in=descendants).distinct()
예제 #13
0
    def get_item(self, product, create=True, **kwargs):
        """ Either instantiates and returns a CartItem for the
            Cart-Product combination or fetches it from the
            database. The creation is lazy: the resulting CartItem
            is not automatically saved.

            :param create:
                Whether or not to create a new object if no object was found.

            :param kwargs:
                If `kwargs` are specified, these signify filters or
                instantiation parameters for getting or creating the item.
        """

        # It makes more sense to execute this code on a higher level
        # instead of everytime a cart item is requested.
        cartitem_class = get_model_from_string(CARTITEM_MODEL)

        # Note that we won't use 'get_or_create' here as it automatically
        # saves the object.
        try:
            cartitem = cartitem_class.objects.get(cart=self,
                                                  product=product,
                                                  **kwargs)

            logger.debug(
                u'Found existing cart item for product \'%s\'', product
            )

        except cartitem_class.DoesNotExist:
            if create:
                logger.debug(
                    u'Product \'%s\' not already in Cart, creating item.',
                    product
                )

                cartitem = cartitem_class(cart=self,
                                          product=product,
                                          **kwargs)
            else:
                return None

        return cartitem
예제 #14
0
    def form_valid(self, form):
        """
        Form data was valid: add a CartItem to the Cart or increase
        the number.

        ..todo::
            Refactor this!
        """
        cart_class = get_model_from_string(CART_MODEL)

        cart = cart_class.from_request(self.request)

        # The cart might not have been saved so far
        if not cart.pk:
            cart.save()

        product = form.cleaned_data['product']
        quantity = form.cleaned_data['quantity']

        self.object = cart.add_item(product, quantity)

        # Make sure that we know whether we updated an existing item
        updated = self.object.pk or False

        # After this, it will allways have a pk.
        self.object.save()

        if updated:
            # Object updated
            messages.add_message(self.request, messages.SUCCESS,
                _('Updated \'%s\' in shopping cart.') % product)
        else:
            # Object updated
            messages.add_message(self.request, messages.SUCCESS,
                _('Added \'%s\' to shopping cart.') % product)

        return super(BaseFormView, self).form_valid(form)
예제 #15
0
    def get_valid_discounts(self, **kwargs):
        """ Return valid discounts for the given arguments. """

        discount_class = get_model_from_string(DISCOUNT_MODEL)
        return discount_class.get_valid_discounts(**kwargs)
예제 #16
0
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import logging
logger = logging.getLogger(__name__)

from shopkit.core.utils import get_model_from_string

from shopkit.category.settings import CATEGORY_MODEL
category_class = get_model_from_string(CATEGORY_MODEL)


""" Mixins relevant for shops with categories. """

class CategoriesMixin(object):
    """ View Mixin providing a list of categories. """
    
    def get_context_data(self, **kwargs):
        """ Adds the available categories to the context as `categories`."""
        
        logger.debug(u'CategoriesMixin')

        context = super(CategoriesMixin, self).get_context_data(**kwargs)
        
        context.update({'categories': category_class.get_categories()})
예제 #17
0
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from django.contrib import admin

from shopkit.core.utils import get_model_from_string

from shopkit.price.advanced.forms import PriceInlineFormSet
from shopkit.price.advanced.settings import PRICE_MODEL
price_class = get_model_from_string(PRICE_MODEL)


class PriceInline(admin.TabularInline):
    """ Inline price admin for prices belonging to products. """
    
    model = price_class
    
    extra = 1
    """ By default, onlye one extra form is shown, as to prevent clogging up
        of the user interface.
    """
    
    formset = PriceInlineFormSet
    """ An alias for :class:`PriceInlineFormSet <shopkit.price.advanced.forms.PriceInlineFormSet>`."""
예제 #18
0
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import logging

logger = logging.getLogger(__name__)

from django.contrib import admin

from django.utils.translation import ugettext_lazy as _

from shopkit.images.settings import PRODUCTIMAGE_MODEL
from shopkit.core.utils import get_model_from_string
productimage_class = get_model_from_string(PRODUCTIMAGE_MODEL)

try:
    from sorl.thumbnail.admin import AdminInlineImageMixin

    from sorl.thumbnail.default import backend as sorl_backend

    SORL_THUMBNAIL = True
    logger.debug(u'Sorl-thumbnail found: using it.')

except ImportError:
    class AdminInlineImageMixin(object):
        pass

    SORL_THUMBNAIL = False
    logger.debug(u'Sorl-thumbnail not found. Skipping.')
예제 #19
0
# This file is part of django-shopkit.
#
# django-shopkit is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import logging
logger = logging.getLogger(__name__)

from django.contrib import admin

from shopkit.variations.settings import PRODUCTVARIATION_MODEL
from shopkit.core.utils import get_model_from_string
productvariation_class = get_model_from_string(PRODUCTVARIATION_MODEL)


class ProductVariationInline(admin.TabularInline):
    """ Inline admin for product variations. """

    model = productvariation_class
    extra = 0