Exemple #1
0
def get_user_model():
    """
    Return the User model. Doesn't require the app cache to be fully
    initialised.

    This used to live in compat to support both Django 1.4's fixed User model
    and custom user models introduced thereafter.
    Support for Django 1.4 has since been dropped in IZI, but our
    get_user_model remains because code relies on us annotating the _meta class
    with the additional fields, and other code might rely on it as well.
    """

    try:
        model = get_model(AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME)
    except LookupError:
        # Convert exception to an ImproperlyConfigured exception for
        # backwards compatibility with previous IZI versions and the
        # original get_user_model method in Django.
        raise ImproperlyConfigured(
            "AUTH_USER_MODEL refers to model '%s' that has not been installed"
            % settings.AUTH_USER_MODEL)

    # Test if user model has any custom fields and add attributes to the _meta
    # class
    core_fields = set([f.name for f in User._meta.fields])
    model_fields = set([f.name for f in model._meta.fields])
    new_fields = model_fields.difference(core_fields)
    model._meta.has_additional_fields = len(new_fields) > 0
    model._meta.additional_fields = new_fields

    return model
Exemple #2
0
 def _category_comparison_fields(self):
     # Overwritten Category models could contain a lot of data, e.g CMS
     # content. Hence, this avoids fetching unneeded data in the costly
     # range comparison queries. Note that using .only() with an empty list
     # is a no-op essentially, so nothing breaks when the field is missing.
     Category = get_model('catalogue', 'Category')
     return getattr(Category, 'COMPARISON_FIELDS', ())
Exemple #3
0
    def process(self):
        """
        Process the file upload and add products to the range
        """
        all_ids = set(self.extract_ids())
        products = self.range.all_products()
        existing_skus = products.values_list(
            'stockrecords__partner_sku', flat=True)
        existing_skus = set(filter(bool, existing_skus))
        existing_upcs = products.values_list('upc', flat=True)
        existing_upcs = set(filter(bool, existing_upcs))
        existing_ids = existing_skus.union(existing_upcs)
        new_ids = all_ids - existing_ids

        Product = get_model('catalogue', 'Product')
        products = Product._default_manager.filter(
            models.Q(stockrecords__partner_sku__in=new_ids) |
            models.Q(upc__in=new_ids))
        for product in products:
            self.range.add_product(product)

        # Processing stats
        found_skus = products.values_list(
            'stockrecords__partner_sku', flat=True)
        found_skus = set(filter(bool, found_skus))
        found_upcs = set(filter(bool, products.values_list('upc', flat=True)))
        found_ids = found_skus.union(found_upcs)
        missing_ids = new_ids - found_ids
        dupes = set(all_ids).intersection(existing_ids)

        self.mark_as_processed(products.count(), len(missing_ids), len(dupes))
        return products
Exemple #4
0
class VoucherRemoveView(View):
    voucher_model = get_model('voucher', 'voucher')
    remove_signal = voucher_removal
    http_method_names = ['post']

    def post(self, request, *args, **kwargs):
        response = redirect('basket:summary')

        voucher_id = kwargs['pk']
        if not request.basket.id:
            # Hacking attempt - the basket must be saved for it to have
            # a voucher in it.
            return response
        try:
            voucher = request.basket.vouchers.get(id=voucher_id)
        except ObjectDoesNotExist:
            messages.error(
                request, _("No voucher found with id '%s'") % voucher_id)
        else:
            request.basket.vouchers.remove(voucher)
            self.remove_signal.send(
                sender=self, basket=request.basket, voucher=voucher)
            messages.info(
                request, _("Voucher '%s' removed from basket") % voucher.code)

        return response
Exemple #5
0
 def get_queryset(self):
     Product = get_model('catalogue', 'Product')
     qs = Product.objects.browsable().base_queryset().select_related(
         'stats')
     if self.method == self.BESTSELLING:
         return qs.order_by('-stats__score')
     return qs.order_by('-date_created')
Exemple #6
0
def get_default_review_status():
    ProductReview = get_model('reviews', 'ProductReview')

    if settings.IZI_MODERATE_REVIEWS:
        return ProductReview.FOR_MODERATION

    return ProductReview.APPROVED
Exemple #7
0
    def add_product(self, product, display_order=None):
        """ Add product to the range

        When adding product that is already in the range, prevent re-adding it.
        If display_order is specified, update it.

        Default display_order for a new product in the range is 0; this puts
        the product at the top of the list.
        """

        initial_order = display_order or 0
        RangeProduct = get_model('offer', 'RangeProduct')
        relation, __ = RangeProduct.objects.get_or_create(
            range=self, product=product,
            defaults={'display_order': initial_order})

        if (display_order is not None and
                relation.display_order != display_order):
            relation.display_order = display_order
            relation.save()

        # Remove product from excluded products if it was removed earlier and
        # re-added again, thus it returns back to the range product list.
        if product.id in self._excluded_product_ids():
            self.excluded_products.remove(product)
            self.invalidate_cached_ids()
Exemple #8
0
class ConditionFactory(factory.DjangoModelFactory):
    type = get_model('offer', 'Condition').COUNT
    value = 10
    range = factory.SubFactory(RangeFactory)

    class Meta:
        model = get_model('offer', 'Condition')
Exemple #9
0
class BenefitFactory(factory.DjangoModelFactory):
    type = get_model('offer', 'Benefit').PERCENTAGE
    value = 10
    max_affected_items = None
    range = factory.SubFactory(RangeFactory)

    class Meta:
        model = get_model('offer', 'Benefit')
Exemple #10
0
    def products(self, create, extracted, **kwargs):
        if not create or not extracted:
            return

        RangeProduct = get_model('offer', 'RangeProduct')

        for product in extracted:
            RangeProduct.objects.create(product=product, range=self)
Exemple #11
0
 class Meta:
     model = get_model('order', 'shippingaddress')
     fields = [
         'title', 'first_name', 'last_name',
         'line1', 'line2', 'line3', 'line4',
         'state', 'postcode', 'country',
         'phone_number', 'notes',
     ]
Exemple #12
0
 def get_site_offers(self):
     """
     Return site offers that are available to all users
     """
     ConditionalOffer = get_model('offer', 'ConditionalOffer')
     qs = ConditionalOffer.active.filter(offer_type=ConditionalOffer.SITE)
     # Using select_related with the condition/benefit ranges doesn't seem
     # to work.  I think this is because both the related objects have the
     # FK to range with the same name.
     return qs.select_related('condition', 'benefit')
Exemple #13
0
    def products(self):
        """
        Return a queryset of products in this offer
        """
        Product = get_model('catalogue', 'Product')
        if not self.has_products:
            return Product.objects.none()

        queryset = self.condition.range.all_products()
        return queryset.filter(is_discountable=True).exclude(
            structure=Product.CHILD)
Exemple #14
0
 def remove_product(self, product):
     """
     Remove product from range. To save on queries, this function does not
     check if the product is in fact in the range.
     """
     RangeProduct = get_model('offer', 'RangeProduct')
     RangeProduct.objects.filter(range=self, product=product).delete()
     # Making sure product will be excluded from range products list by adding to
     # respective field. Otherwise, it could be included as a product from included
     # category or etc.
     self.excluded_products.add(product)
     # Invalidating cached property value with list of IDs of already excluded products.
     self.invalidate_cached_ids()
    def add_new(self):
        """Add a new voucher to this set"""
        Voucher = get_model('voucher', 'Voucher')
        code = get_unused_code(length=self.code_length)
        voucher = Voucher.objects.create(name=self.name,
                                         code=code,
                                         voucher_set=self,
                                         usage=Voucher.SINGLE_USE,
                                         start_datetime=self.start_datetime,
                                         end_datetime=self.end_datetime)

        if self.offer:
            voucher.offers.add(self.offer)

        return voucher
 def _validate_option(self, value, valid_values=None):
     if not isinstance(value, get_model('catalogue', 'AttributeOption')):
         raise ValidationError(
             _("Must be an AttributeOption model object instance"))
     if not value.pk:
         raise ValidationError(_("AttributeOption has not been saved yet"))
     if valid_values is None:
         valid_values = self.option_group.options.values_list('option',
                                                              flat=True)
     if value.option not in valid_values:
         raise ValidationError(
             _("%(enum)s is not a valid choice for %(attr)s") % {
                 'enum': value,
                 'attr': self
             })
Exemple #17
0
class RequestFactory(BaseRequestFactory):
    Basket = get_model('basket', 'basket')
    selector = get_class('partner.strategy', 'Selector')()

    def request(self, user=None, **request):
        request = super().request(**request)
        request.user = user or AnonymousUser()
        request.session = SessionStore()
        request._messages = FallbackStorage(request)

        request.basket = self.Basket()
        request.basket_hash = None
        strategy = self.selector.strategy(request=request, user=request.user)
        request.strategy = request.basket.strategy = strategy

        return request
Exemple #18
0
 def _validate_url(self, value):
     try:
         resolve(value)
     except Http404:
         # We load flatpages here as it causes a circular reference problem
         # sometimes.  FlatPages is None if not installed
         FlatPage = get_model('flatpages', 'FlatPage')
         if FlatPage is not None:
             try:
                 FlatPage.objects.get(url=value)
             except FlatPage.DoesNotExist:
                 self.is_local_url = True
             else:
                 return
         raise ValidationError(_('The URL "%s" does not exist') % value)
     else:
         self.is_local_url = True
Exemple #19
0
class RequestFactory(BaseRequestFactory):
    Basket = get_model('basket', 'basket')
    selector = get_class('partner.strategy', 'Selector')()

    def request(self, user=None, basket=None, **request):
        request = super().request(**request)
        request.user = user or AnonymousUser()
        request.session = SessionStore()
        request._messages = FallbackStorage(request)

        # Mimic basket middleware
        request.strategy = self.selector.strategy(
            request=request, user=request.user)
        request.basket = basket or self.Basket()
        request.basket.strategy = request.strategy
        request.basket_hash = Signer().sign(basket.pk) if basket else None
        request.cookies_to_delete = []

        return request
    def save_value(self, product, value):  # noqa: C901 too complex
        ProductAttributeValue = get_model('catalogue', 'ProductAttributeValue')
        try:
            value_obj = product.attribute_values.get(attribute=self)
        except ProductAttributeValue.DoesNotExist:
            # FileField uses False for announcing deletion of the file
            # not creating a new value
            delete_file = self.is_file and value is False
            if value is None or value == '' or delete_file:
                return
            value_obj = ProductAttributeValue.objects.create(product=product,
                                                             attribute=self)

        if self.is_file:
            self._save_file(value_obj, value)
        elif self.is_multi_option:
            self._save_multi_option(value_obj, value)
        else:
            self._save_value(value_obj, value)
Exemple #21
0
    def all_products(self):
        """
        Return a queryset containing all the products in the range

        This includes included_products plus the products contained in the
        included classes and categories, minus the products in
        excluded_products.
        """
        if self.proxy:
            return self.proxy.all_products()

        Product = get_model("catalogue", "Product")
        if self.includes_all_products:
            # Filter out child products and blacklisted products
            return Product.objects.browsable().exclude(
                id__in=self._excluded_product_ids())

        return Product.objects.filter(
            Q(id__in=self._included_product_ids()) |
            Q(product_class_id__in=self._class_ids()) |
            Q(productcategory__category_id__in=self._category_ids())
        ).exclude(id__in=self._excluded_product_ids()).distinct()
Exemple #22
0
def create_default_accounts():
    """Create the default structure"""
    from izi_accounts import names
    AccountType = get_model('izi_accounts', 'AccountType')

    assets = AccountType.add_root(name=names.ASSETS)
    sales = assets.add_child(name=names.SALES)

    sales.accounts.create(name=names.REDEMPTIONS)
    sales.accounts.create(name=names.LAPSED)

    cash = assets.add_child(name=names.CASH)
    cash.accounts.create(name=names.BANK, credit_limit=None)

    unpaid = assets.add_child(name=names.UNPAID_ACCOUNT_TYPE)
    for name in names.UNPAID_ACCOUNTS:
        unpaid.accounts.create(name=name, credit_limit=None)

    # Create liability accounts
    liabilities = AccountType.add_root(name=names.LIABILITIES)
    income = liabilities.add_child(name=names.DEFERRED_INCOME)
    for i, name in enumerate(names.DEFERRED_INCOME_ACCOUNT_TYPES):
        income.add_child(name=name)
    def test_filters(self):
        f = DashboardStoreSearchForm()
        Store = get_model('stores', 'Store')

        location = '{"type": "Point", "coordinates": [144.917908,-37.815751]}'

        store1 = StoreFactory(name='store1', location=location)
        store2 = StoreFactory(name='store2', location=location)

        StoreAddressFactory(store=store1, line1='Great Portland st., London')

        StoreAddressFactory(store=store2, line1='Sturt Street, Melbourne')

        f.cleaned_data = {'address': 'portland st, london'}
        qs = f.apply_filters(Store.objects.all())
        self.assertEqual(list(qs), [store1])

        f.cleaned_data = {'name': 'store2'}
        qs = f.apply_filters(Store.objects.all())
        self.assertEqual(list(qs), [store2])

        f.cleaned_data = {'name': 'store2', 'address': 'london'}
        qs = f.apply_filters(Store.objects.all())
        self.assertEqual(list(qs), [])
from django.conf import settings
from django.utils.module_loading import import_string
from django.views.generic.list import MultipleObjectMixin

from izi.core.loading import get_class, get_model

BrowseCategoryForm = get_class('search.forms', 'BrowseCategoryForm')
SearchHandler = get_class('search.search_handlers', 'SearchHandler')
is_solr_supported = get_class('search.features', 'is_solr_supported')
is_elasticsearch_supported = get_class('search.features',
                                       'is_elasticsearch_supported')
Product = get_model('catalogue', 'Product')


def get_product_search_handler_class():
    """
    Determine the search handler to use.

    Currently only Solr is supported as a search backend, so it falls
    back to rudimentary category browsing if that isn't enabled.
    """
    # Use get_class to ensure overridability
    if settings.IZI_PRODUCT_SEARCH_HANDLER is not None:
        return import_string(settings.IZI_PRODUCT_SEARCH_HANDLER)
    if is_solr_supported():
        return get_class('catalogue.search_handlers',
                         'SolrProductSearchHandler')
    elif is_elasticsearch_supported():
        return get_class(
            'catalogue.search_handlers',
            'ESProductSearchHandler',
Exemple #25
0
# -*- coding: utf-8 -*-
from django.conf import settings
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from django.utils.translation import get_language, activate
from izi.core.loading import get_model

Product = get_model('catalogue', 'Product')
Category = get_model('catalogue', 'Category')
"""
A basic example what a sitemap could look like for a multi-language IZI
instance.
Creates entries for the homepage, for each product and each category.
Repeats those for each enabled language.
"""


class I18nSitemap(Sitemap):
    """
    A language-specific Sitemap class. Returns URLS for items for passed
    language.
    """
    def __init__(self, language):
        self.language = language
        self.original_language = get_language()

    def get_obj_location(self, obj):
        return obj.get_absolute_url()

    def location(self, obj):
        activate(self.language)
Exemple #26
0
from http import client as http_client
from unittest.mock import patch

from django.urls import reverse

from izi.core.loading import get_model, get_class
from izi.test import factories
from izi.test.testcases import WebTestCase
from . import CheckoutMixin

Order = get_model('order', 'Order')
OrderPlacementMixin = get_class('checkout.mixins', 'OrderPlacementMixin')
ConditionalOffer = get_model('offer', 'ConditionalOffer')
UserAddress = get_model('address', 'UserAddress')
GatewayForm = get_class('checkout.forms', 'GatewayForm')


class TestIndexView(CheckoutMixin, WebTestCase):
    def test_requires_login(self):
        response = self.get(reverse('checkout:index'), user=None)
        self.assertIsRedirect(response)

    def test_redirects_customers_with_empty_basket(self):
        response = self.get(reverse('checkout:index'))
        self.assertRedirectsTo(response, 'basket:summary')

    def test_redirects_customers_to_shipping_address_view(self):
        self.add_product_to_basket()
        response = self.get(reverse('checkout:index'))
        self.assertRedirectsTo(response, 'checkout:shipping-address')
Exemple #27
0
from django.utils.translation import gettext as _
from izi.core import prices
from izi.core.loading import get_class, get_model
from rest_framework import exceptions, serializers

from iziapi.basket.operations import (
    assign_basket_strategy, )
from iziapi.serializers import (VoucherSerializer, OfferDiscountSerializer)
from iziapi.utils import (IZIHyperlinkedModelSerializer, IZIModelSerializer,
                          overridable)
from iziapi.serializers.fields import TaxIncludedDecimalField

OrderPlacementMixin = get_class('checkout.mixins', 'OrderPlacementMixin')
OrderTotalCalculator = get_class('checkout.calculators',
                                 'OrderTotalCalculator')
ShippingAddress = get_model('order', 'ShippingAddress')
BillingAddress = get_model('order', 'BillingAddress')
Order = get_model('order', 'Order')
OrderLine = get_model('order', 'Line')
OrderLineAttribute = get_model('order', 'LineAttribute')

Basket = get_model('basket', 'Basket')
Country = get_model('address', 'Country')
Repository = get_class('shipping.repository', 'Repository')

UserAddress = get_model('address', 'UserAddress')


class PriceSerializer(serializers.Serializer):
    currency = serializers.CharField(max_length=12,
                                     default=settings.IZI_DEFAULT_CURRENCY,
Exemple #28
0
from izi.core.compat import get_user_model
from izi.core.loading import get_class, get_classes, get_model
from izi.apps.shipping import methods
from izi.test.testcases import WebTestCase
from izi.test import factories
from . import CheckoutMixin

GatewayForm = get_class('checkout.forms', 'GatewayForm')
CheckoutSessionData = get_class('checkout.utils', 'CheckoutSessionData')
RedirectRequired, UnableToTakePayment, PaymentError = get_classes(
    'payment.exceptions',
    ['RedirectRequired', 'UnableToTakePayment', 'PaymentError'])
UnableToPlaceOrder = get_class('order.exceptions', 'UnableToPlaceOrder')

Basket = get_model('basket', 'Basket')
Order = get_model('order', 'Order')
User = get_user_model()

# Python 3 compat
try:
    from imp import reload
except ImportError:
    pass


def reload_url_conf():
    # Reload URLs to pick up the overridden settings
    if settings.ROOT_URLCONF in sys.modules:
        reload(sys.modules[settings.ROOT_URLCONF])
    import_module(settings.ROOT_URLCONF)
Exemple #29
0
 class Meta:
     model = get_model('basket', 'LineAttribute')
Exemple #30
0
 class Meta:
     model = get_model('basket', 'Basket')