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)
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
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
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()
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)
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)
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)
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)}
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)
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)
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()
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
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)
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)
# 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()})
# 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>`."""
# # 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.')
# 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