def test_load_formsets_mixed_destination(self): BaseBasketLineFormSet, BasketLineForm = get_classes( 'basket.forms', ('BaseBasketLineFormSet', 'BasketLineForm')) self.assertEqual('wshop.apps.basket.formsets', BaseBasketLineFormSet.__module__) self.assertEqual('wshop.apps.basket.forms', BasketLineForm.__module__) StockRecordForm, StockRecordFormSet = get_classes( 'dashboard.catalogue.forms', ('StockRecordForm', 'StockRecordFormSet')) self.assertEqual('wshop.apps.dashboard.catalogue.forms', StockRecordForm.__module__) OrderedProductForm, OrderedProductFormSet = get_classes( 'dashboard.promotions.forms', ('OrderedProductForm', 'OrderedProductFormSet')) self.assertEqual('wshop.apps.dashboard.promotions.forms', OrderedProductForm.__module__) self.assertTrue( isinstance(OrderedProductFormSet().forms[0], OrderedProductForm)) LineFormset, WishListLineForm = get_classes( 'wishlists.forms', ('LineFormset', 'WishListLineForm')) self.assertEqual('wshop.apps.wishlists.forms', WishListLineForm.__module__) self.assertTrue( isinstance( LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
def test_loading_classes_defined_in_both_local_and_wshop_modules(self): with override_settings(INSTALLED_APPS=self.installed_apps): (Free, FixedPrice) = get_classes('shipping.methods', ('Free', 'FixedPrice')) self.assertEqual('tests._site.shipping.methods', Free.__module__) self.assertEqual('wshop.apps.shipping.methods', FixedPrice.__module__)
def test_load_overriden_3rd_party_class_correctly(self): self.installed_apps.append('apps.myapp') with override_settings(INSTALLED_APPS=self.installed_apps): Cow, Goat = get_classes('myapp.models', ('Cow', 'Goat'), self.core_app_prefix) self.assertEqual('thirdparty_package.apps.myapp.models', Cow.__module__) self.assertEqual('apps.myapp.models', Goat.__module__)
def test_loading_classes_with_root_app(self): import tests._site.shipping path = dirname(dirname(tests._site.shipping.__file__)) with temporary_python_path([path]): self.installed_apps[self.installed_apps.index( 'tests._site.shipping')] = 'shipping' with override_settings(INSTALLED_APPS=self.installed_apps): (Free, ) = get_classes('shipping.methods', ('Free', )) self.assertEqual('shipping.methods', Free.__module__)
def test_loading_class_which_is_not_defined_in_local_module(self): with override_settings(INSTALLED_APPS=self.installed_apps): (FixedPrice, ) = get_classes('shipping.methods', ('FixedPrice', )) self.assertEqual('wshop.apps.shipping.methods', FixedPrice.__module__)
def test_loading_class_defined_in_local_module(self): with override_settings(INSTALLED_APPS=self.installed_apps): (Free, ) = get_classes('shipping.methods', ('Free', )) self.assertEqual('tests._site.shipping.methods', Free.__module__)
import datetime from django.conf import settings from django.db.models import Q from django.http import HttpResponseRedirect from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.views import generic from wshop.core.loading import get_classes, get_model from wshop.core.utils import format_datetime from wshop.views import sort_queryset from wshop.views.generic import BulkEditMixin ProductReviewSearchForm, DashboardProductReviewForm = \ get_classes('dashboard.reviews.forms', ('ProductReviewSearchForm', 'DashboardProductReviewForm')) ProductReview = get_model('reviews', 'productreview') class ReviewListView(BulkEditMixin, generic.ListView): model = ProductReview template_name = 'dashboard/reviews/review_list.html' context_object_name = 'review_list' form_class = ProductReviewSearchForm review_form_class = DashboardProductReviewForm paginate_by = settings.WSHOP_DASHBOARD_ITEMS_PER_PAGE actions = ('update_selected_review_status', ) checkbox_object_name = 'review' desc_template = _("%(main_filter)s %(date_filter)s %(status_filter)s" "%(kw_filter)s %(name_filter)s")
from wshop.core.loading import get_class, get_classes OrderReportGenerator = get_class('order.reports', 'OrderReportGenerator') ProductReportGenerator, UserReportGenerator \ = get_classes('analytics.reports', ['ProductReportGenerator', 'UserReportGenerator']) OpenBasketReportGenerator, SubmittedBasketReportGenerator \ = get_classes('basket.reports', ['OpenBasketReportGenerator', 'SubmittedBasketReportGenerator']) OfferReportGenerator = get_class('offer.reports', 'OfferReportGenerator') VoucherReportGenerator = get_class('voucher.reports', 'VoucherReportGenerator') class GeneratorRepository(object): generators = [ OrderReportGenerator, ProductReportGenerator, UserReportGenerator, OpenBasketReportGenerator, SubmittedBasketReportGenerator, VoucherReportGenerator, OfferReportGenerator ] def get_report_generators(self): return self.generators def get_generator(self, code): for generator in self.generators: if generator.code == code: return generator return None
import logging from django.db import IntegrityError from django.db.models import F from django.dispatch import receiver from wshop.apps.basket.signals import basket_addition from wshop.apps.catalogue.signals import product_viewed from wshop.apps.order.signals import order_placed from wshop.apps.search.signals import user_search from wshop.core.loading import get_classes UserSearch, UserRecord, ProductRecord, UserProductView = get_classes( 'analytics.models', ['UserSearch', 'UserRecord', 'ProductRecord', 'UserProductView']) # Helpers logger = logging.getLogger('wshop.analytics') def _update_counter(model, field_name, filter_kwargs, increment=1): """ Efficiently updates a counter field by a given increment. Uses Django's update() call to fetch and update in one query. TODO: This has a race condition, we should use UPSERT here :param model: The model class of the recording model :param field_name: The name of the field to update :param filter_kwargs: Parameters to the ORM's filter() function to get the
ProductCategory = get_model('catalogue', 'ProductCategory') ProductImage = get_model('catalogue', 'ProductImage') ProductRecommendation = get_model('catalogue', 'ProductRecommendation') AttributeOptionGroup = get_model('catalogue', 'AttributeOptionGroup') AttributeOption = get_model('catalogue', 'AttributeOption') (StockRecordForm, ProductCategoryForm, ProductImageForm, ProductRecommendationForm, ProductAttributesForm, AttributeOptionForm) = \ get_classes('dashboard.catalogue.forms', ('StockRecordForm', 'ProductCategoryForm', 'ProductImageForm', 'ProductRecommendationForm', 'ProductAttributesForm', 'AttributeOptionForm')) BaseStockRecordFormSet = inlineformset_factory(Product, StockRecord, form=StockRecordForm, extra=1) class StockRecordFormSet(BaseStockRecordFormSet): def __init__(self, product_class, user, *args, **kwargs): self.user = user self.require_user_stockrecord = not user.is_staff self.product_class = product_class
from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import get_object_or_404, redirect from django.urls import reverse, reverse_lazy from django.utils.translation import ugettext_lazy as _ from django.views import generic from wshop.apps.customer.utils import get_password_reset_url from wshop.core.compat import get_user_model from wshop.core.loading import (get_class, get_classes, get_model, get_profile_class) from wshop.core.utils import safe_referrer from wshop.views.generic import PostActionMixin from . import signals PageTitleMixin, RegisterUserMixin = get_classes( 'customer.mixins', ['PageTitleMixin', 'RegisterUserMixin']) Dispatcher = get_class('customer.utils', 'Dispatcher') EmailAuthenticationForm, EmailUserCreationForm, OrderSearchForm = get_classes( 'customer.forms', ['EmailAuthenticationForm', 'EmailUserCreationForm', 'OrderSearchForm']) PasswordChangeForm = get_class('customer.forms', 'PasswordChangeForm') ProfileForm, ConfirmPasswordForm = get_classes( 'customer.forms', ['ProfileForm', 'ConfirmPasswordForm']) UserAddressForm = get_class('address.forms', 'UserAddressForm') Order = get_model('order', 'Order') Line = get_model('basket', 'Line') Basket = get_model('basket', 'Basket') UserAddress = get_model('address', 'UserAddress') Email = get_model('customer', 'Email') ProductAlert = get_model('customer', 'ProductAlert') CommunicationEventType = get_model('customer', 'CommunicationEventType')
from django.contrib import messages from django.core.exceptions import ValidationError from django.http import HttpResponseRedirect from django.template.loader import render_to_string from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.views import generic from django.views.generic import ListView from wshop.core.loading import get_classes, get_model from wshop.core.utils import slugify from wshop.core.validators import URLDoesNotExistValidator FlatPage = get_model('flatpages', 'FlatPage') Site = get_model('sites', 'Site') PageSearchForm, PageUpdateForm = get_classes( 'dashboard.pages.forms', ('PageSearchForm', 'PageUpdateForm')) class PageListView(ListView): """ View for listing all existing flatpages. """ template_name = 'dashboard/pages/index.html' model = FlatPage form_class = PageSearchForm paginate_by = settings.WSHOP_DASHBOARD_ITEMS_PER_PAGE desc_template = u'%(main_filter)s %(title_filter)s' def get_queryset(self): """ Get queryset of all flatpages to be displayed. If a
from decimal import Decimal as D from decimal import ROUND_UP from django.utils import six from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext from wshop.core.loading import get_classes, get_model from wshop.templatetags.currency_filters import currency Condition = get_model('offer', 'Condition') range_anchor, unit_price = get_classes('offer.utils', ['range_anchor', 'unit_price']) __all__ = [ 'CountCondition', 'CoverageCondition', 'ValueCondition' ] class CountCondition(Condition): """ An offer condition dependent on the NUMBER of matching items from the basket. """ _description = _("Basket includes %(count)d item(s) from %(range)s") @property def name(self): return self._description % { 'count': self.value, 'range': six.text_type(self.range).lower()}
from decimal import Decimal as D from django.utils.translation import ugettext_lazy as _ from wshop.core.loading import get_class, get_classes, get_model from wshop.templatetags.currency_filters import currency Benefit = get_model('offer', 'Benefit') BasketDiscount, SHIPPING_DISCOUNT, ZERO_DISCOUNT = get_classes( 'offer.results', ['BasketDiscount', 'SHIPPING_DISCOUNT', 'ZERO_DISCOUNT']) CoverageCondition, ValueCondition = get_classes( 'offer.conditions', ['CoverageCondition', 'ValueCondition']) range_anchor = get_class('offer.utils', 'range_anchor') __all__ = [ 'PercentageDiscountBenefit', 'AbsoluteDiscountBenefit', 'FixedPriceBenefit', 'ShippingBenefit', 'MultibuyDiscountBenefit', 'ShippingAbsoluteDiscountBenefit', 'ShippingFixedPriceBenefit', 'ShippingPercentageDiscountBenefit', ] def apply_discount(line, discount, quantity, offer=None): """ Apply a given discount to the passed basket """ line.discount(discount, quantity, incl_tax=False, offer=offer)
from django.db import models from django.db.models.query import Q from django.template.defaultfilters import date as date_filter from django.urls import reverse from django.utils.encoding import python_2_unicode_compatible from django.utils.functional import cached_property from django.utils.timezone import get_current_timezone, now from django.utils.translation import ugettext_lazy as _ from wshop.core.compat import AUTH_USER_MODEL from wshop.core.loading import get_class, get_classes, get_model from wshop.models import fields from wshop.templatetags.currency_filters import currency ActiveOfferManager, BrowsableRangeManager \ = get_classes('offer.managers', ['ActiveOfferManager', 'BrowsableRangeManager']) ZERO_DISCOUNT = get_class('offer.results', 'ZERO_DISCOUNT') load_proxy, unit_price = get_classes('offer.utils', ['load_proxy', 'unit_price']) @python_2_unicode_compatible class BaseOfferMixin(models.Model): class Meta: abstract = True def proxy(self): """ Return the proxy model """ klassmap = self.proxy_map
from django.urls import reverse from django.utils.http import is_safe_url from django.utils.translation import ugettext_lazy as _ from django.views.generic import FormView, View from extra_views import ModelFormSetView from wshop.apps.basket.signals import (basket_addition, voucher_addition, voucher_removal) from wshop.core import ajax from wshop.core.loading import get_class, get_classes, get_model from wshop.core.utils import redirect_to_referrer, safe_referrer Applicator = get_class('offer.applicator', 'Applicator') (BasketLineForm, AddToBasketForm, BasketVoucherForm, SavedLineForm) = get_classes('basket.forms', ('BasketLineForm', 'AddToBasketForm', 'BasketVoucherForm', 'SavedLineForm')) BasketLineFormSet, SavedLineFormSet = get_classes( 'basket.formsets', ('BasketLineFormSet', 'SavedLineFormSet')) Repository = get_class('shipping.repository', 'Repository') OrderTotalCalculator = get_class('checkout.calculators', 'OrderTotalCalculator') BasketMessageGenerator = get_class('basket.utils', 'BasketMessageGenerator') class BasketView(ModelFormSetView): model = get_model('basket', 'Line') basket_model = get_model('basket', 'Basket') formset_class = BasketLineFormSet form_class = BasketLineForm
def test_loading_class_from_module_not_defined_in_local_app(self): with override_settings(INSTALLED_APPS=self.installed_apps): (Repository, ) = get_classes('shipping.repository', ('Repository', )) self.assertEqual('wshop.apps.shipping.repository', Repository.__module__)
from django import http from django.contrib import messages from django.contrib.auth import login from django.shortcuts import redirect from django.urls import reverse, reverse_lazy from django.utils import six from django.utils.http import urlquote from django.utils.translation import ugettext as _ from django.views import generic from wshop.core.loading import get_class, get_classes, get_model from . import signals ShippingAddressForm, ShippingMethodForm, GatewayForm \ = get_classes('checkout.forms', ['ShippingAddressForm', 'ShippingMethodForm', 'GatewayForm']) OrderCreator = get_class('order.utils', 'OrderCreator') UserAddressForm = get_class('address.forms', 'UserAddressForm') Repository = get_class('shipping.repository', 'Repository') AccountAuthView = get_class('customer.views', 'AccountAuthView') RedirectRequired, UnableToTakePayment, PaymentError \ = get_classes('payment.exceptions', ['RedirectRequired', 'UnableToTakePayment', 'PaymentError']) UnableToPlaceOrder = get_class('order.exceptions', 'UnableToPlaceOrder') OrderPlacementMixin = get_class('checkout.mixins', 'OrderPlacementMixin') CheckoutSessionMixin = get_class('checkout.session', 'CheckoutSessionMixin') NoShippingRequired = get_class('shipping.methods', 'NoShippingRequired') Order = get_model('order', 'Order') ShippingAddress = get_model('order', 'ShippingAddress') CommunicationEvent = get_model('order', 'CommunicationEvent')
from django.urls import clear_url_caches, reverse from django.utils.http import urlquote from django.utils.six.moves import http_client import mock from wshop.core.compat import get_user_model from wshop.core.loading import get_class, get_classes, get_model from wshop.apps.shipping import methods from wshop.test.testcases import WebTestCase from wshop.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():
def test_load_wshop_classes_correctly(self): Product, Category = get_classes('catalogue.models', ('Product', 'Category')) self.assertEqual('wshop.apps.catalogue.models', Product.__module__) self.assertEqual('wshop.apps.catalogue.models', Category.__module__)
from django.db.models.signals import post_save from django.dispatch import receiver from wshop.core.loading import get_classes StockRecord, StockAlert = get_classes('partner.models', ['StockRecord', 'StockAlert']) @receiver(post_save, sender=StockRecord) def update_stock_alerts(sender, instance, created, **kwargs): """ Update low-stock alerts """ if created or kwargs.get('raw', False): return stockrecord = instance try: alert = StockAlert.objects.get(stockrecord=stockrecord, status=StockAlert.OPEN) except StockAlert.DoesNotExist: alert = None if stockrecord.is_below_threshold and not alert: StockAlert.objects.create(stockrecord=stockrecord, threshold=stockrecord.low_stock_threshold) elif not stockrecord.is_below_threshold and alert: alert.close()
import os from decimal import Decimal as D from django.db.transaction import atomic from django.utils.translation import ugettext_lazy as _ from wshop.core.compat import UnicodeCSVReader from wshop.core.loading import get_class, get_classes ImportingError = get_class('partner.exceptions', 'ImportingError') Partner, StockRecord = get_classes('partner.models', ['Partner', 'StockRecord']) ProductClass, Product, Category, ProductCategory = get_classes( 'catalogue.models', ('ProductClass', 'Product', 'Category', 'ProductCategory')) create_from_breadcrumbs = get_class('catalogue.categories', 'create_from_breadcrumbs') class CatalogueImporter(object): """ CSV product importer used to built sandbox. Might not work very well for anything else. """ _flush = False def __init__(self, logger, delimiter=",", flush=False): self.logger = logger self._delimiter = delimiter self._flush = flush
from django.db import models from django.db.models import Sum from django.utils.encoding import python_2_unicode_compatible, smart_text from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from wshop.core.compat import AUTH_USER_MODEL from wshop.core.loading import get_class, get_classes from wshop.core.utils import get_default_currency from wshop.models.fields.slugfield import SlugField from wshop.templatetags.currency_filters import currency OfferApplications = get_class('offer.results', 'OfferApplications') Unavailable = get_class('partner.availability', 'Unavailable') LineOfferConsumer = get_class('basket.utils', 'LineOfferConsumer') OpenBasketManager, SavedBasketManager = get_classes( 'basket.managers', ['OpenBasketManager', 'SavedBasketManager']) @python_2_unicode_compatible class AbstractBasket(models.Model): """ Basket object """ # Baskets can be anonymously owned - hence this field is nullable. When a # anon user signs in, their two baskets are merged. owner = models.ForeignKey(AUTH_USER_MODEL, null=True, related_name='baskets', on_delete=models.CASCADE, verbose_name=_("Owner"))
from django.forms.models import inlineformset_factory from wshop.core.loading import get_class, get_classes HandPickedProductList, OrderedProduct \ = get_classes('promotions.models', ['HandPickedProductList', 'OrderedProduct']) ProductSelect = get_class('dashboard.catalogue.widgets', 'ProductSelect') OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm') OrderedProductFormSet = inlineformset_factory(HandPickedProductList, OrderedProduct, form=OrderedProductForm, extra=2)
from decimal import Decimal as D from django.core.exceptions import ImproperlyConfigured from django.utils.translation import ugettext_lazy as _ from wshop.core.loading import get_classes (Free, NoShippingRequired, TaxExclusiveOfferDiscount, TaxInclusiveOfferDiscount) \ = get_classes('shipping.methods', ['Free', 'NoShippingRequired', 'TaxExclusiveOfferDiscount', 'TaxInclusiveOfferDiscount']) class Repository(object): """ Repository class responsible for returning ShippingMethod objects for a given user, basket etc """ # We default to just free shipping. Customise this class and override this # property to add your own shipping methods. This should be a list of # instantiated shipping methods. methods = (Free(), ) # API def get_shipping_methods(self, basket, shipping_addr=None, **kwargs): """ Return a list of all applicable shipping method instances for a given basket, address etc. """
from django.shortcuts import HttpResponse, get_object_or_404 from django.template.loader import render_to_string from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext from django.views.generic import (CreateView, DeleteView, ListView, UpdateView, View) from wshop.core.loading import get_classes, get_model from wshop.views.generic import BulkEditMixin Range = get_model('offer', 'Range') RangeProduct = get_model('offer', 'RangeProduct') RangeProductFileUpload = get_model('offer', 'RangeProductFileUpload') Product = get_model('catalogue', 'Product') RangeForm, RangeProductForm = get_classes('dashboard.ranges.forms', ['RangeForm', 'RangeProductForm']) class RangeListView(ListView): model = Range context_object_name = 'ranges' template_name = 'dashboard/ranges/range_list.html' paginate_by = settings.WSHOP_DASHBOARD_ITEMS_PER_PAGE class RangeCreateView(CreateView): model = Range template_name = 'dashboard/ranges/range_form.html' form_class = RangeForm def get_success_url(self):
from django.test import TestCase from wshop.apps.dashboard.promotions import forms from wshop.core.loading import get_classes RawHTML, PagePromotion = get_classes('promotions.models', ['RawHTML', 'PagePromotion']) class TestPagePromotionForm(TestCase): def test_page_promotion_has_fields(self): promotion = RawHTML() promotion.save() instance = PagePromotion(content_object=promotion) data = {'position': 'page', 'page_url': '/'} form = forms.PagePromotionForm(data=data, instance=instance) self.assertTrue(form.is_valid()) page_promotion = form.save() self.assertEqual(page_promotion.page_url, '/')
def test_raise_exception_when_bad_appname_used(self): with self.assertRaises(AppNotFoundError): get_classes('fridge.models', ('Product', 'Category'))
from django.utils import six from django.utils.encoding import python_2_unicode_compatible from django.utils.functional import cached_property from django.utils.html import strip_tags from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.utils.translation import get_language, pgettext_lazy from treebeard.mp_tree import MP_Node from wshop.core.loading import get_class, get_classes, get_model from wshop.core.utils import slugify from wshop.core.validators import non_python_keyword from wshop.models.fields import AutoSlugField, NullCharField from wshop.models.fields.slugfield import SlugField ProductManager, BrowsableProductManager = get_classes( 'catalogue.managers', ['ProductManager', 'BrowsableProductManager']) ProductAttributesContainer = get_class('catalogue.product_attributes', 'ProductAttributesContainer') Selector = get_class('partner.strategy', 'Selector') @python_2_unicode_compatible class AbstractProductClass(models.Model): """ Used for defining options and attributes for a subset of products. E.g. Books, DVDs and Toys. A product can only belong to one product class. At least one product class must be created when setting up a new Wshop deployment. Not necessarily equivalent to top-level categories but usually will be.
from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.views.generic import (DeleteView, DetailView, FormView, ListView, UpdateView) from django.views.generic.detail import SingleObjectMixin from django.views.generic.edit import FormMixin from django_tables2 import SingleTableView from wshop.apps.customer.utils import normalise_email from wshop.core.compat import get_user_model from wshop.core.loading import get_class, get_classes, get_model from wshop.views.generic import BulkEditMixin UserSearchForm, ProductAlertSearchForm, ProductAlertUpdateForm = get_classes( 'dashboard.users.forms', ('UserSearchForm', 'ProductAlertSearchForm', 'ProductAlertUpdateForm')) PasswordResetForm = get_class('customer.forms', 'PasswordResetForm') UserTable = get_class('dashboard.users.tables', 'UserTable') ProductAlert = get_model('customer', 'ProductAlert') User = get_user_model() class IndexView(BulkEditMixin, FormMixin, SingleTableView): template_name = 'dashboard/users/index.html' table_pagination = True model = User actions = ( 'make_active', 'make_inactive', )