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
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', ())
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
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
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')
def get_default_review_status(): ProductReview = get_model('reviews', 'ProductReview') if settings.IZI_MODERATE_REVIEWS: return ProductReview.FOR_MODERATION return ProductReview.APPROVED
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()
class ConditionFactory(factory.DjangoModelFactory): type = get_model('offer', 'Condition').COUNT value = 10 range = factory.SubFactory(RangeFactory) class Meta: model = get_model('offer', 'Condition')
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')
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)
class Meta: model = get_model('order', 'shippingaddress') fields = [ 'title', 'first_name', 'last_name', 'line1', 'line2', 'line3', 'line4', 'state', 'postcode', 'country', 'phone_number', 'notes', ]
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')
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)
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 })
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
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
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)
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()
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',
# -*- 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)
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')
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,
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)
class Meta: model = get_model('basket', 'LineAttribute')
class Meta: model = get_model('basket', 'Basket')