Ejemplo n.º 1
0
 def ready(self):
     self.order_list_view = get_class('dashboard.orders.views', 'OrderListView')
     self.order_detail_view = get_class('dashboard.orders.views', 'OrderDetailView')
     self.shipping_address_view = get_class('dashboard.orders.views',
                                            'ShippingAddressUpdateView')
     self.line_detail_view = get_class('dashboard.orders.views', 'LineDetailView')
     self.order_stats_view = get_class('dashboard.orders.views', 'OrderStatsView')
Ejemplo n.º 2
0
 def proxy_map(self):
     return {
         self.COUNT: get_class(
             'offer.conditions', 'CountCondition'),
         self.VALUE: get_class(
             'offer.conditions', 'ValueCondition'),
         self.COVERAGE: get_class(
             'offer.conditions', 'CoverageCondition'),
     }
Ejemplo n.º 3
0
 def test_raise_importerror_if_app_raises_importerror(self):
     """
     This tests that Oscar doesn't fall back to using the Oscar catalogue
     app if the overriding app throws an ImportError.
     """
     apps = list(settings.INSTALLED_APPS)
     apps[apps.index('oscar.apps.catalogue')] = 'tests._site.import_error_app.catalogue'
     with override_settings(INSTALLED_APPS=apps):
         with self.assertRaises(ImportError):
             get_class('catalogue.app', 'CatalogueApplication')
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 is_solr_supported():
        return get_class("catalogue.search_handlers", "ProductSearchHandler")
    else:
        return get_class("catalogue.search_handlers", "SimpleProductSearchHandler")
Ejemplo n.º 5
0
def prepare_basket(request, product, voucher=None):
    """
    Create or get the basket, add the product, apply a voucher, and record referral data.

    Existing baskets are merged. The specified product will
    be added to the remaining open basket. If voucher is passed, all existing
    vouchers added to the basket are removed because we allow only one voucher per basket.
    Vouchers are not applied if an enrollment code product is in the basket.

    Arguments:
        request (Request): The request object made to the view.
        product (Product): Product to be added to the basket.
        voucher (Voucher): Voucher to apply to the basket.

    Returns:
        basket (Basket): Contains the product to be redeemed and the Voucher applied.
    """
    basket = Basket.get_basket(request.user, request.site)
    basket.flush()
    basket.add_product(product, 1)
    if product.get_product_class().name == ENROLLMENT_CODE_PRODUCT_CLASS_NAME:
        basket.clear_vouchers()
    elif voucher:
        basket.clear_vouchers()
        basket.vouchers.add(voucher)
        Applicator().apply(basket, request.user, request)
        logger.info('Applied Voucher [%s] to basket [%s].', voucher.code, basket.id)

    attribute_cookie_data(basket, request)

    # Call signal handler to notify listeners that something has been added to the basket
    basket_addition = get_class('basket.signals', 'basket_addition')
    basket_addition.send(sender=basket_addition, product=product, user=request.user, request=request, basket=basket)

    return basket
Ejemplo n.º 6
0
    def test_raise_importerror_if_app_raises_importerror(self):
        """
        This tests that Oscar doesn't fall back to using the Oscar core
        app class if the overriding app class throws an ImportError.

        "get_class()" returns None in this case, since there is no such named
        class in the core app. We use this fictitious class because classes in
        the "models" and "views" modules (along with modules they are related
        to) are imported as part of the Django app-loading process, which is
        triggered when we override the INSTALLED_APPS setting.
        """
        apps = list(settings.INSTALLED_APPS)
        apps[apps.index('tests._site.apps.catalogue')] = 'tests._site.import_error_app.catalogue'
        with override_settings(INSTALLED_APPS=apps):
            with self.assertRaises(ImportError):
                get_class('catalogue.import_error_module', 'ImportErrorClass')
Ejemplo n.º 7
0
def create_menu(menu_items, parent=None):
    """
    Create the navigation nodes based on a passed list of dicts
    """
    nodes = []
    access_fn_str = settings.OSCAR_DASHBOARD_DEFAULT_ACCESS_FUNCTION
    default_fn = get_class(*access_fn_str.rsplit('.', 1))
    for menu_dict in menu_items:
        try:
            label = menu_dict['label']
        except KeyError:
            raise ImproperlyConfigured(
                "No label specified for menu item in dashboard")

        children = menu_dict.get('children', [])
        if children:
            node = Node(label=label, icon=menu_dict.get('icon', None),
                        access_fn=menu_dict.get('access_fn', default_fn))
            create_menu(children, parent=node)
        else:
            node = Node(label=label, icon=menu_dict.get('icon', None),
                        url_name=menu_dict.get('url_name', None),
                        url_kwargs=menu_dict.get('url_kwargs', None),
                        url_args=menu_dict.get('url_args', None),
                        access_fn=menu_dict.get('access_fn', default_fn))
        if parent is None:
            nodes.append(node)
        else:
            parent.add_child(node)
    return nodes
Ejemplo n.º 8
0
 def get_session(self):
     if hasattr(self, 'user_session'):
         return self.user_session
     else:
         try:
             return get_class('user.session', 'UserSessionData')(self.request)
         except (ImportError, AppNotFoundError, ClassNotFoundError, ModuleNotFoundError):
             return FictaSessionData(self.request)
Ejemplo n.º 9
0
    def test_override_class_loader(self):
        # Clear lru cache for the class loader
        get_class_loader.cache_clear()

        View = get_class('catalogue.views', 'ProductDetailView')
        self.assertEqual(View, DummyClass)

        # Clear lru cache for the class loader again
        get_class_loader.cache_clear()
Ejemplo n.º 10
0
 def ready(self):
     self.index_view = get_class('checkout.views', 'IndexView')
     self.shipping_address_view = get_class('checkout.views', 'ShippingAddressView')
     self.user_address_update_view = get_class('checkout.views',
                                               'UserAddressUpdateView')
     self.user_address_delete_view = get_class('checkout.views',
                                               'UserAddressDeleteView')
     self.shipping_method_view = get_class('checkout.views', 'ShippingMethodView')
     self.payment_method_view = get_class('checkout.views', 'PaymentMethodView')
     self.payment_details_view = get_class('checkout.views', 'PaymentDetailsView')
     self.thankyou_view = get_class('checkout.views', 'ThankYouView')
Ejemplo n.º 11
0
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.OSCAR_PRODUCT_SEARCH_HANDLER is not None:
        return import_string(settings.OSCAR_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',
        )
    else:
        return get_class(
            'catalogue.search_handlers', 'SimpleProductSearchHandler')
Ejemplo n.º 12
0
    def ready(self):
        self.list_view = get_class('dashboard.partners.views', 'PartnerListView')
        self.create_view = get_class('dashboard.partners.views', 'PartnerCreateView')
        self.manage_view = get_class('dashboard.partners.views', 'PartnerManageView')
        self.delete_view = get_class('dashboard.partners.views', 'PartnerDeleteView')

        self.user_link_view = get_class('dashboard.partners.views',
                                        'PartnerUserLinkView')
        self.user_unlink_view = get_class('dashboard.partners.views',
                                          'PartnerUserUnlinkView')
        self.user_create_view = get_class('dashboard.partners.views',
                                          'PartnerUserCreateView')
        self.user_select_view = get_class('dashboard.partners.views',
                                          'PartnerUserSelectView')
        self.user_update_view = get_class('dashboard.partners.views',
                                          'PartnerUserUpdateView')
Ejemplo n.º 13
0
 def ready(self):
     self.list_view = get_class('dashboard.offers.views', 'OfferListView')
     self.metadata_view = get_class('dashboard.offers.views', 'OfferMetaDataView')
     self.condition_view = get_class('dashboard.offers.views', 'OfferConditionView')
     self.benefit_view = get_class('dashboard.offers.views', 'OfferBenefitView')
     self.restrictions_view = get_class('dashboard.offers.views',
                                        'OfferRestrictionsView')
     self.delete_view = get_class('dashboard.offers.views', 'OfferDeleteView')
     self.detail_view = get_class('dashboard.offers.views', 'OfferDetailView')
Ejemplo n.º 14
0
def default_access_fn(user, url_name, url_args=None, url_kwargs=None):
    """
    Given a url_name and a user, this function tries to assess whether the
    user has the right to access the URL.
    The application instance of the view is fetched via dynamic imports,
    and those assumptions will only hold true if the standard Oscar layout
    is followed.
    Once the permissions for the view are known, the access logic used
    by the dashboard decorator is evaluated

    This function might seem costly, but a simple comparison with DTT
    did not show any change in response time
    """
    exception = ImproperlyConfigured(
        "Please follow Oscar's default dashboard app layout or set a "
        "custom access_fn")
    if url_name is None:  # it's a heading
        return True

    # get view module string.
    try:
        url = reverse(url_name, args=url_args, kwargs=url_kwargs)
    except NoReverseMatch:
        # In Oscar 1.5 this exception was silently ignored which made debugging
        # very difficult. Now it is being logged and in future the exception will
        # be propagated.
        logger.exception('Invalid URL name {}'.format(url_name))
        return False

    view_module = resolve(url).func.__module__

    # We can't assume that the view has the same parent module as the app,
    # as either the app or view can be customised. So we turn the module
    # string (e.g. 'oscar.apps.dashboard.catalogue.views') into an app
    # label that can be loaded by get_class (e.g.
    # 'dashboard.catalogue.app), which then essentially checks
    # INSTALLED_APPS for the right module to load
    match = re.search('(dashboard[\w\.]*)\.views$', view_module)
    if not match:
        raise exception
    app_label_str = match.groups()[0] + '.app'

    try:
        app_instance = get_class(app_label_str, 'application')
    except AppNotFoundError:
        raise exception

    # handle name-spaced view names
    if ':' in url_name:
        view_name = url_name.split(':')[1]
    else:
        view_name = url_name
    permissions = app_instance.get_permissions(view_name)
    return check_permissions(user, permissions)
Ejemplo n.º 15
0
 def ready(self):
     self.list_view = get_class('dashboard.ranges.views', 'RangeListView')
     self.create_view = get_class('dashboard.ranges.views', 'RangeCreateView')
     self.update_view = get_class('dashboard.ranges.views', 'RangeUpdateView')
     self.delete_view = get_class('dashboard.ranges.views', 'RangeDeleteView')
     self.products_view = get_class('dashboard.ranges.views', 'RangeProductListView')
     self.reorder_view = get_class('dashboard.ranges.views', 'RangeReorderView')
Ejemplo n.º 16
0
    def ready(self):
        from oscar.apps.promotions.conf import PROMOTION_CLASSES

        self.list_view = get_class('dashboard.promotions.views',
                                   'ListView')
        self.page_list = get_class('dashboard.promotions.views',
                                   'PageListView')
        self.page_detail = get_class('dashboard.promotions.views',
                                     'PageDetailView')
        self.create_redirect_view = get_class('dashboard.promotions.views',
                                              'CreateRedirectView')
        self.delete_page_promotion_view = get_class('dashboard.promotions.views',
                                                    'DeletePagePromotionView')

        # Dynamically set the CRUD views for all promotion classes
        view_names = (
            ('create_%s_view', 'Create%sView'),
            ('update_%s_view', 'Update%sView'),
            ('delete_%s_view', 'Delete%sView'),
        )
        for klass in PROMOTION_CLASSES:
            for attr_name, view_name in view_names:
                full_attr_name = attr_name % klass.classname()
                full_view_name = view_name % klass.__name__
                view = get_class('dashboard.promotions.views', full_view_name)
                vars(self)[full_attr_name] = view
Ejemplo n.º 17
0
    def render_content(self, options):
        request = options['request']

        Partner = get_class('partner.models', 'Partner')

        manufacturer_list = Partner.objects.all()

        context = RequestContext(options['request'], {
            'widget': self,
            'request': request,
            'manufacturer_list': manufacturer_list,
        })
        return render_to_string(self.get_template, context)
Ejemplo n.º 18
0
    def ready(self):
        from django.contrib.auth.forms import SetPasswordForm

        self.catalogue_app = apps.get_app_config('catalogue')
        self.customer_app = apps.get_app_config('customer')
        self.basket_app = apps.get_app_config('basket')
        self.checkout_app = apps.get_app_config('checkout')
        self.search_app = apps.get_app_config('search')
        self.dashboard_app = apps.get_app_config('dashboard')
        self.offer_app = apps.get_app_config('offer')

        self.password_reset_form = get_class('customer.forms', 'PasswordResetForm')
        self.set_password_form = SetPasswordForm
Ejemplo n.º 19
0
    def _default_access_fn(self, user):
        """
        Given a url_name and a user, this function tries to assess whether the
        user has the right to access the URL.
        The application instance of the view is fetched via dynamic imports,
        and those assumptions will only hold true if the standard Oscar layout
        is followed.
        Once the permissions for the view are known, the access logic used
        by the dashboard decorator is evaluated

        This function might seem costly, but a simple comparison with DTT
        did not show any change in response time
        """
        exception = ImproperlyConfigured(
            "Please follow Oscar's default dashboard app layout or set a "
            "custom access_fn")
        if self.is_heading:
            return True
        # get view module string
        try:
            url = reverse(self.url_name, args=self.url_args,
                          kwargs=self.url_kwargs)
            view_module = resolve(url).func.__module__
        except (NoReverseMatch, Http404):
            # if there's no match, no need to display it
            return False

        # We can't assume that the view has the same parent module as the app,
        # as either the app or view can be customised. So we turn the module
        # string (e.g. 'oscar.apps.dashboard.catalogue.views') into an app
        # label that can be loaded by get_class (e.g.
        # 'dashboard.catalogue.app), which then essentially checks
        # INSTALLED_APPS for the right module to load
        match = re.search('(dashboard[\w\.]*)\.views$', view_module)
        if not match:
            raise exception
        app_label_str = match.groups()[0] + '.app'

        try:
            app_instance = get_class(app_label_str, 'application')
        except AppNotFoundError:
            raise exception

        # handle name-spaced view names
        if ':' in self.url_name:
            view_name = self.url_name.split(':')[1]
        else:
            view_name = self.url_name
        permissions = app_instance.get_permissions(view_name)
        return check_permissions(user, permissions)
Ejemplo n.º 20
0
    def ready(self):
        self.index_view = get_class('dashboard.views', 'IndexView')

        self.catalogue_app = apps.get_app_config('catalogue_dashboard')
        self.reports_app = apps.get_app_config('reports_dashboard')
        self.orders_app = apps.get_app_config('orders_dashboard')
        self.users_app = apps.get_app_config('users_dashboard')
        self.pages_app = apps.get_app_config('pages_dashboard')
        self.partners_app = apps.get_app_config('partners_dashboard')
        self.offers_app = apps.get_app_config('offers_dashboard')
        self.ranges_app = apps.get_app_config('ranges_dashboard')
        self.reviews_app = apps.get_app_config('reviews_dashboard')
        self.vouchers_app = apps.get_app_config('vouchers_dashboard')
        self.comms_app = apps.get_app_config('communications_dashboard')
        self.shipping_app = apps.get_app_config('shipping_dashboard')
Ejemplo n.º 21
0
    def update(self, request, *args, **kwargs):
        order = self.get_object()

        if not order.is_fulfillable:
            return Response(status=status.HTTP_406_NOT_ACCEPTABLE)

        logger.info('Attempting fulfillment of order [%s]...', order.number)
        post_checkout = get_class('checkout.signals', 'post_checkout')
        post_checkout.send(sender=post_checkout, order=order)

        if order.is_fulfillable:
            logger.warning('Fulfillment of order [%s] failed!', order.number)
            return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        serializer = self.get_serializer(order)
        return Response(serializer.data)
Ejemplo n.º 22
0
 def ready(self):
     self.index_view = get_class('dashboard.users.views', 'IndexView')
     self.user_detail_view = get_class('dashboard.users.views', 'UserDetailView')
     self.password_reset_view = get_class('dashboard.users.views',
                                          'PasswordResetView')
     self.alert_list_view = get_class('dashboard.users.views',
                                      'ProductAlertListView')
     self.alert_update_view = get_class('dashboard.users.views',
                                        'ProductAlertUpdateView')
     self.alert_delete_view = get_class('dashboard.users.views',
                                        'ProductAlertDeleteView')
Ejemplo n.º 23
0
 def test_load_formset_new_destination(self):
     BaseBasketLineFormSet = get_class('basket.formsets', 'BaseBasketLineFormSet')
     self.assertEqual('oscar.apps.basket.formsets', BaseBasketLineFormSet.__module__)
     StockRecordFormSet = get_class('dashboard.catalogue.formsets', 'StockRecordFormSet')
     self.assertEqual('oscar.apps.dashboard.catalogue.formsets', StockRecordFormSet.__module__)
     OrderedProductFormSet = get_class('dashboard.promotions.formsets', 'OrderedProductFormSet')
     OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm')
     self.assertTrue(isinstance(OrderedProductFormSet().forms[0], OrderedProductForm))
     LineFormset = get_class('wishlists.formsets', 'LineFormset')
     WishListLineForm = get_class('wishlists.forms', 'WishListLineForm')
     self.assertTrue(isinstance(LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
Ejemplo n.º 24
0
def assign_basket_strategy(basket, request):
    # fixes too early import of Selector
    # TODO: check if this is still true, now the basket models nolonger
    #       require this module to be loaded.
    global Selector

    if hasattr(request, 'strategy'):
        basket.strategy = request.strategy
    else:  # in management commands, the request might not be available.
        if Selector is None:
            Selector = get_class('partner.strategy', 'Selector')
        basket.strategy = Selector().strategy(
            request=request, user=request.user)

    apply_offers(request, basket)

    return basket
Ejemplo n.º 25
0
    def fulfill(self, request, number=None):  # pylint: disable=unused-argument
        """ Fulfill order """
        order = self.get_object()

        if not order.is_fulfillable:
            return Response(status=status.HTTP_406_NOT_ACCEPTABLE)

        logger.info('Attempting fulfillment of order [%s]...', order.number)
        post_checkout = get_class('checkout.signals', 'post_checkout')
        post_checkout.send(sender=post_checkout, order=order, request=request)

        if order.is_fulfillable:
            logger.warning('Fulfillment of order [%s] failed!', order.number)
            return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        serializer = self.get_serializer(order)
        return Response(serializer.data)
Ejemplo n.º 26
0
 def proxy_map(self):
     return {
         self.PERCENTAGE: get_class(
             'offer.benefits', 'PercentageDiscountBenefit'),
         self.FIXED: get_class(
             'offer.benefits', 'AbsoluteDiscountBenefit'),
         self.MULTIBUY: get_class(
             'offer.benefits', 'MultibuyDiscountBenefit'),
         self.FIXED_PRICE: get_class(
             'offer.benefits', 'FixedPriceBenefit'),
         self.SHIPPING_ABSOLUTE: get_class(
             'offer.benefits', 'ShippingAbsoluteDiscountBenefit'),
         self.SHIPPING_FIXED_PRICE: get_class(
             'offer.benefits', 'ShippingFixedPriceBenefit'),
         self.SHIPPING_PERCENTAGE: get_class(
             'offer.benefits', 'ShippingPercentageDiscountBenefit')
     }
Ejemplo n.º 27
0
    def children(self, page, **kwargs):
        from oscar.core.loading import get_class

        Store = get_class('stores.models', 'Store')
        stores = Store.objects.all()
        for store in stores:
            yield PagePretender(
                title=store.name,
                url=store.get_absolute_url(),
                tree_id=page.tree_id,
                level=page.level + 1,
                language=getattr(page, 'language', settings.LANGUAGE_CODE),
                slug=store.slug,
                parent=page,
                parent_id=page.id,
                lft=page.lft,
                rght=page.rght,
                _mptt_meta=getattr(page, '_mptt_meta', None),
            )
Ejemplo n.º 28
0
    def children(self, page, **kwargs):
        from oscar.core.loading import get_class

        Category = get_class('catalogue.categories', 'Category')
        categories = Category.objects.all()
        for category in categories:
            yield PagePretender(
                title=category.name,
                url=category.get_absolute_url(),
                tree_id=page.tree_id,
                level=page.level + 1,
                language=getattr(page, 'language', settings.LANGUAGE_CODE),
                slug=category.slug,
                parent=page,
                parent_id=page.id,
                lft=page.lft,
                rght=page.rght,
                _mptt_meta=getattr(page, '_mptt_meta', None),
            )
Ejemplo n.º 29
0
 def test_load_formset_old_destination(self):
     BaseBasketLineFormSet = get_class('basket.forms', 'BaseBasketLineFormSet')
     self.assertEqual('oscar.apps.basket.formsets', BaseBasketLineFormSet.__module__)
     StockRecordFormSet = get_class('dashboard.catalogue.forms', 'StockRecordFormSet')
     self.assertEqual('oscar.apps.dashboard.catalogue.formsets', StockRecordFormSet.__module__)
     OrderedProductFormSet = get_class('dashboard.promotions.forms', 'OrderedProductFormSet')
     OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm')
     # Since OrderedProductFormSet created with metaclass, it has __module__
     # attribute pointing to the Django module. Thus, we test if formset was
     # loaded correctly by initiating class instance and checking its forms.
     self.assertTrue(isinstance(OrderedProductFormSet().forms[0], OrderedProductForm))
     LineFormset = get_class('wishlists.forms', 'LineFormset')
     WishListLineForm = get_class('wishlists.forms', 'WishListLineForm')
     self.assertTrue(isinstance(LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
Ejemplo n.º 30
0
import json

from django.conf import settings

from oscar.core.loading import get_class, get_model

product_viewed = get_class('catalogue.signals', 'product_viewed')
Product = get_model('catalogue', 'Product')


def get(request):
    """
    Return a list of recently viewed products
    """
    ids = extract(request)

    # Reordering as the ID order gets messed up in the query
    product_dict = Product.browsable.in_bulk(ids)
    ids.reverse()
    return [product_dict[id] for id in ids if id in product_dict]


def extract(request, response=None):
    """
    Extract the IDs of products in the history cookie
    """
    ids = []
    cookie_name = settings.OSCAR_RECENTLY_VIEWED_COOKIE_NAME
    if cookie_name in request.COOKIES:
        try:
            ids = json.loads(request.COOKIES[cookie_name])
Ejemplo n.º 31
0
from django import forms
from django.contrib.auth.models import Permission
from django.contrib.auth.password_validation import validate_password
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import pgettext_lazy

from oscar.core.compat import existing_user_fields, get_user_model
from oscar.core.loading import get_class, get_model

User = get_user_model()
Partner = get_model('partner', 'Partner')
PartnerAddress = get_model('partner', 'PartnerAddress')
EmailUserCreationForm = get_class('customer.forms', 'EmailUserCreationForm')


class PartnerSearchForm(forms.Form):
    name = forms.CharField(required=False,
                           label=pgettext_lazy(u"Partner's name", u"Name"))


class PartnerCreateForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PartnerCreateForm, self).__init__(*args, **kwargs)
        # Partner.name is optional and that is okay. But if creating through
        # the dashboard, it seems sensible to enforce as it's the only field
        # in the form.
        self.fields['name'].required = True

    class Meta:
        model = Partner
        fields = ('name', )
Ejemplo n.º 32
0
"""Functions used for data retrieval and manipulation by the API."""
import logging

from oscar.core.loading import get_model, get_class

from ecommerce.extensions.api import exceptions

NoShippingRequired = get_class('shipping.methods', 'NoShippingRequired')
OrderTotalCalculator = get_class('checkout.calculators',
                                 'OrderTotalCalculator')
Product = get_model('catalogue', 'Product')

logger = logging.getLogger(__name__)


def get_product(sku):
    """Retrieve the product corresponding to the provided SKU."""
    try:
        return Product.objects.get(stockrecords__partner_sku=sku)
    except Product.DoesNotExist:
        raise exceptions.ProductNotFoundError(
            exceptions.PRODUCT_NOT_FOUND_DEVELOPER_MESSAGE.format(sku=sku))


def get_order_metadata(basket):
    """Retrieve information required to place an order.

    Arguments:
        basket (Basket): The basket whose contents are to be ordered.

    Returns:
Ejemplo n.º 33
0
def prepare_basket(request, products, voucher=None):
    """
    Create or get the basket, add products, apply a voucher, and record referral data.

    Existing baskets are merged. Specified products will
    be added to the remaining open basket. If voucher is passed, all existing
    vouchers added to the basket are removed because we allow only one voucher per basket.
    Vouchers are not applied if an enrollment code product is in the basket.

    Arguments:
        request (Request): The request object made to the view.
        products (List): List of products to be added to the basket.
        voucher (Voucher): Voucher to apply to the basket.

    Returns:
        basket (Basket): Contains the product to be redeemed and the Voucher applied.
    """
    basket = Basket.get_basket(request.user, request.site)
    basket.flush()
    basket.save()
    basket_addition = get_class('basket.signals', 'basket_addition')
    already_purchased_products = []
    bundle = request.GET.get('bundle')

    _set_basket_bundle_status(bundle, basket)

    if request.site.siteconfiguration.enable_embargo_check:
        if not embargo_check(request.user, request.site, products):
            messages.error(
                request,
                _('Due to export controls, we cannot allow you to access this course at this time.'
                  ))
            logger.warning(
                'User [%s] blocked by embargo check, not adding products to basket',
                request.user.username)
            return basket

    is_multi_product_basket = True if len(products) > 1 else False
    for product in products:
        if product.is_enrollment_code_product or \
                not UserAlreadyPlacedOrder.user_already_placed_order(user=request.user,
                                                                     product=product, site=request.site):
            basket.add_product(product, 1)
            # Call signal handler to notify listeners that something has been added to the basket
            basket_addition.send(
                sender=basket_addition,
                product=product,
                user=request.user,
                request=request,
                basket=basket,
                is_multi_product_basket=is_multi_product_basket)
        else:
            already_purchased_products.append(product)
            logger.warning(
                'User [%s] attempted to repurchase the [%s] seat of course [%s]',
                request.user.username, mode_for_product(product),
                product.course_id)
    if already_purchased_products and basket.is_empty:
        raise AlreadyPlacedOrderException

    if len(products) == 1 and products[0].is_enrollment_code_product:
        basket.clear_vouchers()
    elif voucher:
        basket.clear_vouchers()
        basket.vouchers.add(voucher)
        Applicator().apply(basket, request.user, request)
        logger.info('Applied Voucher [%s] to basket [%s].', voucher.code,
                    basket.id)

    attribute_cookie_data(basket, request)
    return basket
import datetime
import logging

import pytz
from django.core.management.base import BaseCommand, CommandError
from django.db.models import Sum
from oscar.core.loading import get_class, get_model

from ecommerce.core.constants import COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME, SEAT_PRODUCT_CLASS_NAME
from ecommerce.core.utils import use_read_replica_if_available

logger = logging.getLogger(__name__)
Order = get_model('order', 'Order')
PaymentEvent = get_model('order', 'PaymentEvent')
PaymentEventType = get_model('order', 'PaymentEventType')
PaymentEventTypeName = get_class('order.constants', 'PaymentEventTypeName')

DEFAULT_START_DELTA_TIME = 240
DEFAULT_END_DELTA_TIME = 60
VALID_PRODUCT_CLASS_NAMES = [
    SEAT_PRODUCT_CLASS_NAME, COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME
]


class Command(BaseCommand):
    ORDERS_WITHOUT_PAYMENTS = None
    MULTI_PAYMENT_ON_ORDER = None
    ORDER_PAYMENT_TOTALS_MISMATCH = None
    REFUND_AMOUNT_EXCEEDED = None
    PAID_EVENT_TYPE = None
    REFUNDED_EVENT_TYPE = None
Ejemplo n.º 35
0
 def proxy_map(self):
     return {
         self.COUNT: get_class('offer.conditions', 'CountCondition'),
         self.VALUE: get_class('offer.conditions', 'ValueCondition'),
         self.COVERAGE: get_class('offer.conditions', 'CoverageCondition'),
     }
Ejemplo n.º 36
0
from django_tables2 import A, Column, LinkColumn, TemplateColumn

from oscar.core.loading import get_class

DashboardTable = get_class('dashboard.tables', 'DashboardTable')


class UserTable(DashboardTable):
    check = TemplateColumn(
        template_name='dashboard/users/user_row_checkbox.html',
        verbose_name=' ',
        orderable=False)
    email = LinkColumn('dashboard:user-detail',
                       args=[A('id')],
                       accessor='email')
    name = Column(accessor='get_full_name',
                  order_by=('last_name', 'first_name'))
    active = Column(accessor='is_active')
    staff = Column(accessor='is_staff')
    date_registered = Column(accessor='date_joined')
    num_orders = Column(accessor='orders.count', orderable=False)
    actions = TemplateColumn(
        template_name='dashboard/users/user_row_actions.html',
        verbose_name=' ')

    icon = "group"

    class Meta(DashboardTable.Meta):
        template = 'dashboard/users/table.html'
Ejemplo n.º 37
0
from django.test import override_settings
from oscar.core.loading import get_class, get_model
from oscar.test.factories import ProductFactory, RangeFactory, create_order

from ecommerce.extensions.basket.utils import prepare_basket
from ecommerce.extensions.fulfillment.status import ORDER
from ecommerce.extensions.order.constants import PaymentEventTypeName
from ecommerce.extensions.payment.constants import CARD_TYPES
from ecommerce.extensions.payment.models import PaymentProcessorResponse
from ecommerce.extensions.payment.processors.cybersource import Cybersource
from ecommerce.extensions.payment.processors.paypal import Paypal
from ecommerce.extensions.test.factories import UserFactory, create_basket, prepare_voucher
from ecommerce.management.utils import FulfillFrozenBaskets, refund_basket_transactions
from ecommerce.tests.testcases import TestCase

Free = get_class('shipping.methods', 'Free')
OrderTotalCalculator = get_class('checkout.calculators',
                                 'OrderTotalCalculator')
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
OrderCreator = get_class('order.utils', 'OrderCreator')

Order = get_model('order', 'Order')
PaymentEvent = get_model('order', 'PaymentEvent')
Source = get_model('payment', 'Source')


class RefundBasketTransactionsTests(TestCase):
    def test_no_basket_ids(self):
        assert refund_basket_transactions(self.site, []) == (
            0,
            0,
Ejemplo n.º 38
0
    def create(self, request, *args, **kwargs):
        """Add products to the authenticated user's basket.

        Expects an array of product objects, 'products', each containing a SKU, in the request
        body. The SKUs are used to populate the user's basket with the corresponding products.

        The caller indicates whether checkout should occur by providing a Boolean value
        in the request body, 'checkout'. If checkout operations are requested and the
        contents of the user's basket are free, an order is placed immediately.

        If checkout operations are requested but the contents of the user's basket are not
        free, pre-payment operations are performed instead of placing an order. The caller
        indicates which payment processor to use by providing a string in the request body,
        'payment_processor_name'.

        Protected by JWT authentication. Consuming services (e.g., the LMS)
        must authenticate themselves by passing a JWT in the Authorization
        HTTP header, prepended with the string 'JWT '. The JWT payload should
        contain user details. At a minimum, these details must include a
        username; providing an email is recommended.

        Arguments:
            request (HttpRequest): With parameters 'products', 'checkout', and
                'payment_processor_name' in the body.

        Returns:
            200 if a basket was created successfully; the basket ID is included in the response body along with
                either an order number corresponding to the placed order (None if one wasn't placed) or
                payment information (None if payment isn't required).
            400 if the client provided invalid data or attempted to add an unavailable product to their basket,
                with reason for the failure in JSON format.
            401 if an unauthenticated request is denied permission to access the endpoint.
            429 if the client has made requests at a rate exceeding that allowed by the configured rate limit.
            500 if an error occurs when attempting to initiate checkout.

        Examples:
            Create a basket for the user with username 'Saul' as follows. Successful fulfillment
            requires that a user with username 'Saul' exists on the LMS, and that EDX_API_KEY be
            configured within both the LMS and the ecommerce service.

            >>> url = 'http://*****:*****@bettercallsaul.com'}, 'insecure-secret-key')
            >>> headers = {
                'content-type': 'application/json',
                'Authorization': 'JWT ' + token
            }

            If checkout is not desired:

            >>> data = {'products': [{'sku': 'SOME-SEAT'}, {'sku': 'SOME-OTHER-SEAT'}], 'checkout': False}
            >>> response = requests.post(url, data=json.dumps(data), headers=headers)
            >>> response.json()
            {
                'id': 7,
                'order': None,
                'payment_data': None
            }

            If the product with SKU 'FREE-SEAT' is free and checkout is desired:

            >>> data = {'products': [{'sku': 'FREE-SEAT'}], 'checkout': True, 'payment_processor_name': 'paypal'}
            >>> response = requests.post(url, data=json.dumps(data), headers=headers)
            >>> response.json()
            {
                'id': 7,
                'order': {'number': 'OSCR-100007'},
                'payment_data': None
            }

            If the product with SKU 'PAID-SEAT' is not free and checkout is desired:

            >>> data = {'products': [{'sku': 'PAID-SEAT'}], 'checkout': True, 'payment_processor_name': 'paypal'}
            >>> response = requests.post(url, data=json.dumps(data), headers=headers)
            >>> response.json()
            {
                'id': 7,
                'order': None,
                'payment_data': {
                    'payment_processor_name': 'paypal',
                    'payment_form_data': {...},
                    'payment_page_url': 'https://www.someexternallyhostedpaymentpage.com'
                }
            }
        """
        # Explicitly delimit operations which will be rolled back if an exception occurs.
        # atomic() context managers restore atomicity at points where we are modifying data
        # (baskets, then orders) to ensure that we don't leave the system in a dirty state
        # in the event of an error.
        with transaction.atomic():
            basket = Basket.create_basket(request.site, request.user)
            basket_id = basket.id

            attribute_cookie_data(basket, request)

            requested_products = request.data.get('products')
            if requested_products:
                is_multi_product_basket = True if len(
                    requested_products) > 1 else False
                for requested_product in requested_products:
                    # Ensure the requested products exist
                    sku = requested_product.get('sku')
                    if sku:
                        try:
                            product = data_api.get_product(sku)
                        except api_exceptions.ProductNotFoundError as error:
                            return self._report_bad_request(
                                error.message,
                                api_exceptions.PRODUCT_NOT_FOUND_USER_MESSAGE)
                    else:
                        return self._report_bad_request(
                            api_exceptions.SKU_NOT_FOUND_DEVELOPER_MESSAGE,
                            api_exceptions.SKU_NOT_FOUND_USER_MESSAGE)

                    # Ensure the requested products are available for purchase before adding them to the basket
                    availability = basket.strategy.fetch_for_product(
                        product).availability
                    if not availability.is_available_to_buy:
                        return self._report_bad_request(
                            api_exceptions.
                            PRODUCT_UNAVAILABLE_DEVELOPER_MESSAGE.format(
                                sku=sku, availability=availability.message),
                            api_exceptions.PRODUCT_UNAVAILABLE_USER_MESSAGE)

                    basket.add_product(product)
                    logger.info('Added product with SKU [%s] to basket [%d]',
                                sku, basket_id)

                    # Call signal handler to notify listeners that something has been added to the basket
                    basket_addition = get_class('basket.signals',
                                                'basket_addition')
                    basket_addition.send(
                        sender=basket_addition,
                        product=product,
                        user=request.user,
                        request=request,
                        basket=basket,
                        is_multi_product_basket=is_multi_product_basket)
            else:
                # If no products were included in the request, we cannot checkout.
                return self._report_bad_request(
                    api_exceptions.PRODUCT_OBJECTS_MISSING_DEVELOPER_MESSAGE,
                    api_exceptions.PRODUCT_OBJECTS_MISSING_USER_MESSAGE)

        if request.data.get('checkout') is True:
            # Begin the checkout process, if requested, with the requested payment processor.
            payment_processor_name = request.data.get('payment_processor_name')
            if payment_processor_name:
                try:
                    payment_processor = get_processor_class_by_name(
                        payment_processor_name)
                except payment_exceptions.ProcessorNotFoundError as error:
                    return self._report_bad_request(
                        error.message,
                        payment_exceptions.PROCESSOR_NOT_FOUND_USER_MESSAGE)
            else:
                payment_processor = get_default_processor_class()

            try:
                response_data = self._checkout(basket,
                                               payment_processor(request.site),
                                               request)
            except Exception as ex:  # pylint: disable=broad-except
                basket.delete()
                logger.exception(
                    'Failed to initiate checkout for Basket [%d]. The basket has been deleted.',
                    basket_id)
                return Response({'developer_message': ex.message},
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            # Return a serialized basket, if checkout was not requested.
            response_data = self._generate_basic_response(basket)

        return Response(response_data, status=status.HTTP_200_OK)
Ejemplo n.º 39
0
from ecommerce.core.utils import get_cache_key
from ecommerce.enterprise.entitlements import get_entitlement_voucher
from ecommerce.extensions.analytics.utils import audit_log
from ecommerce.extensions.api import data as data_api
from ecommerce.extensions.api import exceptions as api_exceptions
from ecommerce.extensions.api.permissions import IsStaffOrOwner
from ecommerce.extensions.api.serializers import BasketSerializer, OrderSerializer
from ecommerce.extensions.api.throttles import ServiceUserThrottle
from ecommerce.extensions.basket.constants import TEMPORARY_BASKET_CACHE_KEY
from ecommerce.extensions.basket.utils import attribute_cookie_data
from ecommerce.extensions.checkout.mixins import EdxOrderPlacementMixin
from ecommerce.extensions.partner.shortcuts import get_partner_for_site
from ecommerce.extensions.payment import exceptions as payment_exceptions
from ecommerce.extensions.payment.helpers import get_default_processor_class, get_processor_class_by_name

Applicator = get_class('offer.applicator', 'Applicator')
Basket = get_model('basket', 'Basket')
logger = logging.getLogger(__name__)
Order = get_model('order', 'Order')
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
Product = get_model('catalogue', 'Product')
Selector = get_class('partner.strategy', 'Selector')
User = get_user_model()
Voucher = get_model('voucher', 'Voucher')


class BasketCreateView(EdxOrderPlacementMixin, generics.CreateAPIView):
    """Endpoint for creating baskets.

    If requested, performs checkout operations on baskets, placing an order if
    the contents of the basket are free, and generating payment parameters otherwise.
Ejemplo n.º 40
0
import waffle
from django.conf import settings
from django.contrib import messages
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from oscar.apps.basket.signals import voucher_addition
from oscar.core.loading import get_class, get_model

from ecommerce.courses.utils import mode_for_product
from ecommerce.extensions.offer.constants import CUSTOM_APPLICATOR_USE_FLAG
from ecommerce.extensions.order.exceptions import AlreadyPlacedOrderException
from ecommerce.extensions.order.utils import UserAlreadyPlacedOrder
from ecommerce.extensions.payment.utils import embargo_check
from ecommerce.referrals.models import Referral

Applicator = get_class('offer.applicator', 'Applicator')
CustomApplicator = get_class('offer.applicator', 'CustomApplicator')
Basket = get_model('basket', 'Basket')
BasketAttribute = get_model('basket', 'BasketAttribute')
BasketAttributeType = get_model('basket', 'BasketAttributeType')
BUNDLE = 'bundle_identifier'
ORGANIZATION_ATTRIBUTE_TYPE = 'organization'
ENTERPRISE_CATALOG_ATTRIBUTE_TYPE = 'enterprise_catalog_uuid'
StockRecord = get_model('partner', 'StockRecord')
OrderLine = get_model('order', 'Line')
Refund = get_model('refund', 'Refund')
Voucher = get_model('voucher', 'Voucher')

logger = logging.getLogger(__name__)

Ejemplo n.º 41
0
from decimal import Decimal as D

from django.conf import settings
from django.utils.translation import gettext_lazy as _

from oscar.core.loading import get_class, get_classes, get_model
from oscar.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, incl_tax=None):
    """
    Apply a given discount to the passed basket
    """
Ejemplo n.º 42
0
logger = logging.getLogger(__name__)

Basket = get_model('basket', 'Basket')
Benefit = get_model('offer', 'Benefit')
BillingAddress = get_model('order', 'BillingAddress')
Catalog = get_model('catalogue', 'Catalog')
Category = get_model('catalogue', 'Category')
Line = get_model('order', 'Line')
Order = get_model('order', 'Order')
Partner = get_model('partner', 'Partner')
Product = get_model('catalogue', 'Product')
ProductAttributeValue = get_model('catalogue', 'ProductAttributeValue')
ProductCategory = get_model('catalogue', 'ProductCategory')
Refund = get_model('refund', 'Refund')
Selector = get_class('partner.strategy', 'Selector')
StockRecord = get_model('partner', 'StockRecord')
Voucher = get_model('voucher', 'Voucher')
User = get_user_model()

COURSE_DETAIL_VIEW = 'api:v2:course-detail'
PRODUCT_DETAIL_VIEW = 'api:v2:product-detail'


def is_custom_code(obj):
    """Helper method to check if the voucher contains custom code. """
    return not is_enrollment_code(obj) and retrieve_quantity(obj) == 1


def is_enrollment_code(obj):
    benefit = retrieve_voucher(obj).benefit
Ejemplo n.º 43
0
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import FormView, View
from oscar.apps.partner import strategy
from oscar.apps.payment.exceptions import PaymentError, TransactionDeclined, UserCancelled
from oscar.core.loading import get_class, get_model

from ecommerce.extensions.checkout.mixins import EdxOrderPlacementMixin
from ecommerce.extensions.checkout.utils import get_receipt_page_url
from ecommerce.extensions.payment.exceptions import InvalidBasketError, InvalidSignatureError
from ecommerce.extensions.payment.forms import PaymentForm
from ecommerce.extensions.payment.processors.cybersource import Cybersource
from ecommerce.extensions.payment.utils import clean_field_value

logger = logging.getLogger(__name__)

Applicator = get_class('offer.utils', 'Applicator')
Basket = get_model('basket', 'Basket')
BillingAddress = get_model('order', 'BillingAddress')
Country = get_model('address', 'Country')
NoShippingRequired = get_class('shipping.methods', 'NoShippingRequired')
Order = get_model('order', 'Order')
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
OrderTotalCalculator = get_class('checkout.calculators',
                                 'OrderTotalCalculator')


class CybersourceSubmitView(FormView):
    """ Starts CyberSource payment process.

    This view is intended to be called asynchronously by the payment form. The view expects POST data containing a
    `Basket` ID. The specified basket is frozen, and CyberSource parameters are returned as a JSON object.
Ejemplo n.º 44
0
import logging
from decimal import Decimal

from django.contrib.sites.models import Site
from django.conf import settings
from django.http import Http404
from django.urls import reverse

from mollie.api.client import Client
from oscar.apps.payment.exceptions import UnableToTakePayment
from oscar.core.loading import get_class, get_model
from . import signals

logger = logging.getLogger('oscar.checkout')

EventHandler = get_class('order.processing', 'EventHandler')
Order = None
SourceType = None


def _lazy_get_payment_event_models():
    global PaymentEvent
    global PaymentEventType
    global PaymentEventQuantity

    PaymentEvent = get_model('order', 'PaymentEvent')
    PaymentEventType = get_model('order', 'PaymentEventType')
    PaymentEventQuantity = get_model('order', 'PaymentEventQuantity')


def _lazy_get_models():
Ejemplo n.º 45
0
from ecommerce.extensions.payment.processors.paypal import Paypal
from ecommerce.extensions.payment.tests.mixins import PaymentEventsMixin, PaypalMixin
from ecommerce.extensions.payment.views.paypal import PaypalPaymentExecutionView
from ecommerce.extensions.test.factories import create_basket
from ecommerce.invoice.models import Invoice
from ecommerce.tests.testcases import TestCase

JSON = 'application/json'

Basket = get_model('basket', 'Basket')
Order = get_model('order', 'Order')
PaymentEvent = get_model('order', 'PaymentEvent')
PaymentEventType = get_model('order', 'PaymentEventType')
PaymentProcessorResponse = get_model('payment', 'PaymentProcessorResponse')
Product = get_model('catalogue', 'Product')
Selector = get_class('partner.strategy', 'Selector')
SourceType = get_model('payment', 'SourceType')
Voucher = get_model('voucher', 'Voucher')

post_checkout = get_class('checkout.signals', 'post_checkout')


@ddt.ddt
class PaypalPaymentExecutionViewTests(PaypalMixin, PaymentEventsMixin,
                                      TestCase):
    """Test handling of users redirected by PayPal after approving payment."""
    def setUp(self):
        super(PaypalPaymentExecutionViewTests, self).setUp()

        self.basket = create_basket(owner=factories.UserFactory(),
                                    site=self.site)
Ejemplo n.º 46
0
from django import forms
from django.conf import settings
from django.utils.translation import ugettext_lazy as _

from oscar.apps.promotions.conf import PROMOTION_CLASSES
from oscar.core.loading import get_class, get_classes
from oscar.forms.fields import ExtendedURLField

HandPickedProductList, RawHTML, SingleProduct, PagePromotion, OrderedProduct \
    = get_classes('promotions.models',
                  ['HandPickedProductList', 'RawHTML', 'SingleProduct',
                   'PagePromotion', 'OrderedProduct'])
ProductSelect = get_class('dashboard.catalogue.widgets', 'ProductSelect')


class PromotionTypeSelectForm(forms.Form):
    choices = []
    for klass in PROMOTION_CLASSES:
        choices.append((klass.classname(), klass._meta.verbose_name))
    promotion_type = forms.ChoiceField(choices=tuple(choices),
                                       label=_("Promotion type"))


class RawHTMLForm(forms.ModelForm):
    class Meta:
        model = RawHTML
        fields = ['name', 'body']

    def __init__(self, *args, **kwargs):
        super(RawHTMLForm, self).__init__(*args, **kwargs)
        self.fields['body'].widget.attrs['class'] = "no-widget-init"
Ejemplo n.º 47
0
from decimal import Decimal as D

from django.db import models
from django.conf import settings
from django.db.models import get_model
from django.utils.translation import ugettext_lazy as _
from django.utils.importlib import import_module as django_import_module

from oscar.core.utils import slugify
from oscar.core.loading import get_class
from oscar.apps.partner.exceptions import InvalidStockAdjustment
DefaultWrapper = get_class('partner.wrappers', 'DefaultWrapper')

# Cache dict of partner_id => availability wrapper instance
partner_wrappers = None

default_wrapper = DefaultWrapper()


def get_partner_wrapper(partner_id):
    """
    Returns the appropriate partner wrapper given the partner's PK
    """
    if partner_wrappers is None:
        _load_partner_wrappers()
    return partner_wrappers.get(partner_id, default_wrapper)


def _load_partner_wrappers():
    # Prime cache of partner wrapper dict
    global partner_wrappers
Ejemplo n.º 48
0
import datetime

from oscar.core.loading import get_model, get_class

from django.views import generic
from django.core.exceptions import ObjectDoesNotExist

Post = get_model('appblog', 'Post')
Category = get_model('appblog', 'Category')
CategoryGroup = get_model('appblog', 'CategoryGroup')

SearchPostForm = get_class('appblog.forms', 'SearchPostForm')


class BlogPostView(generic.ListView):

    template_name = 'appblog/blog-post-list.html'
    model = Post
    paginate_by = 2
    context_object_name = 'posts'
    form_class = SearchPostForm

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = self.get_categories()
        context['form'] = self.form_class()
        return context

    def get_posts_published(self, queryset):
        return queryset.filter(post_date__lte=datetime.date.today())
Ejemplo n.º 49
0
class InvestorsDashboardApplication(DashboardApplication):
    name = None
    default_permissions = [
        'is_staff',
    ]

    permissions_map = {
        'investor-list': (['is_staff'], ['investor.dashboard_access']),
        'investor-manage': (['is_staff'], ['investor.dashboard_access']),
        'investment-create': (['is_staff'], ['investor.dashboard_access']),
        'investmentcomments-create':
        (['is_staff'], ['investor.dashboard_access'],
         ['company.dashboard_access']),
        'investor-member': (['is_staff'], ['investor.dashboard_access']),
        'investor-order': (['is_staff'], ['investor.dashboard_access']),
        'project-announcement-list':
        (['is_staff'], ['investor.dashboard_access']),
        'project-announcement-create':
        (['is_staff'], ['investor.dashboard_access']),
        'project-announcement-detail':
        (['is_staff'], ['investor.dashboard_access']),
        #'create_investment_comments_view': (['is_staff'], ['investor.dashboard_access']),
        #'money-list': (['is_staff'], ['investor.dashboard_access']),
    }

    list_view = get_class('dashboard.investors.views', 'InvestorListView')
    create_view = get_class('dashboard.investors.views', 'InvestorCreateView')
    manage_view = get_class('dashboard.investors.views', 'InvestorManageView')
    delete_view = get_class('dashboard.investors.views', 'InvestorDeleteView')

    create_investment_view = get_class('dashboard.investors.views',
                                       'InvestmentCreateView')

    create_investment_comments_view = get_class(
        'dashboard.investors.views', 'InvestmentCommentsCreateView')

    user_link_view = get_class('dashboard.investors.views',
                               'InvestorUserLinkView')
    user_unlink_view = get_class('dashboard.investors.views',
                                 'InvestorUserUnlinkView')
    user_create_view = get_class('dashboard.investors.views',
                                 'InvestorUserCreateView')
    user_select_view = get_class('dashboard.investors.views',
                                 'InvestorUserSelectView')
    user_update_view = get_class('dashboard.investors.views',
                                 'InvestorUserUpdateView')
    investor_member_view = get_class('dashboard.investors.views',
                                     'InvestorMembersView')
    investor_order_view = get_class('dashboard.investors.views',
                                    'InvestorOrderView')

    project_announcement_create_view = get_class(
        'dashboard.investors.views', 'ProjectAnnouncementCreateView')
    project_announcement_list_view = get_class('dashboard.investors.views',
                                               'ProjectAnnouncementListView')
    project_announcement_detail_view = get_class(
        'dashboard.investors.views', 'ProjectAnnouncementDetailView')

    def get_urls(self):
        urls = [
            url(r'^$', self.list_view.as_view(), name='investor-list'),
            url(r'^create/$',
                self.create_view.as_view(),
                name='investor-create'),
            url(r'^(?P<pk>\d+)/$',
                self.manage_view.as_view(),
                name='investor-manage'),
            url(r'^(?P<pk>\d+)/delete/$',
                self.delete_view.as_view(),
                name='investor-delete'),
            url(r'^(?P<investor_pk>\d+)/users/add/$',
                self.user_create_view.as_view(),
                name='investor-user-create'),
            url(r'^(?P<investor_pk>\d+)/users/select/$',
                self.user_select_view.as_view(),
                name='investor-user-select'),
            url(r'^(?P<investor_pk>\d+)/users/(?P<user_pk>\d+)/link/$',
                self.user_link_view.as_view(),
                name='investor-user-link'),
            url(r'^(?P<investor_pk>\d+)/users/(?P<user_pk>\d+)/unlink/$',
                self.user_unlink_view.as_view(),
                name='investor-user-unlink'),
            url(r'^(?P<investor_pk>\d+)/users/(?P<user_pk>\d+)/update/$',
                self.user_update_view.as_view(),
                name='investor-user-update'),
            url(r'^createinvestment/(?P<company_pk>\d+)/(?P<pk>\d+)/$',
                self.create_investment_view.as_view(),
                name='investment-create'),
            url(r'^createinvestmentcomments/(?P<company_pk>\d+)/(?P<prospectus_pk>\d+)/(?P<pk>\d+)/$',
                self.create_investment_comments_view.as_view(),
                name='investmentcomments-create'),
            url(r'^investor/members/$',
                self.investor_member_view.as_view(),
                name='investor-member'),
            url(r'^investor/orders/$',
                self.investor_order_view.as_view(),
                name='investor-order'),
            url(r'^projectannouncementlist/$',
                self.project_announcement_list_view.as_view(),
                name='project-announcement-list'),
            url(r'^createprojectannouncement/(?P<investor_pk>\d+)/$',
                self.project_announcement_create_view.as_view(),
                name='project-announcement-create'),
            url(r'^detailprojectannouncement/(?P<investor_pk>\d+)/(?P<pk>\d+)/$',
                self.project_announcement_detail_view.as_view(),
                name='project-announcement-detail'),
        ]
        return self.post_process_urls(urls)
Ejemplo n.º 50
0
from django.db.models.query import Q
from django.template.defaultfilters import date as date_filter
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.timezone import get_current_timezone, now
from django.utils.translation import gettext_lazy as _

from oscar.core.compat import AUTH_USER_MODEL
from oscar.core.loading import (cached_import_string, get_class, get_classes,
                                get_model)
from oscar.models import fields
from oscar.templatetags.currency_filters import currency

ActiveOfferManager, RangeManager, BrowsableRangeManager \
    = get_classes('offer.managers', ['ActiveOfferManager', 'RangeManager', 'BrowsableRangeManager'])
ZERO_DISCOUNT = get_class('offer.results', 'ZERO_DISCOUNT')
load_proxy, unit_price = get_classes('offer.utils',
                                     ['load_proxy', 'unit_price'])


class BaseOfferMixin(models.Model):
    class Meta:
        abstract = True

    def proxy(self):
        """
        Return the proxy model
        """
        klassmap = self.proxy_map
        # Short-circuit logic if current class is already a proxy class.
        if self.__class__ in klassmap.values():
Ejemplo n.º 51
0
from django import forms
from django.utils.translation import gettext_lazy as _

from oscar.core.loading import get_class
from oscar.forms.widgets import DatePickerInput

GeneratorRepository = get_class('dashboard.reports.utils',
                                'GeneratorRepository')


class ReportForm(forms.Form):
    generators = GeneratorRepository().get_report_generators()

    type_choices = []
    count =1
    for generator in generators:
        if(count<=5):
            type_choices.append((generator.code, generator.description))
            print(generator.description)
        count +=1
    report_type = forms.ChoiceField(widget=forms.Select(),
                                    choices=type_choices,
                                    label=_("Report Type"),
                                    help_text=_("Only the offer and order"
                                                " reports use the selected"
                                                " date range"))

    date_from = forms.DateField(label=_("Date from"), required=False,
                                widget=DatePickerInput)
    date_to = forms.DateField(label=_("Date to"),
                              help_text=_("The report is inclusive of this"
Ejemplo n.º 52
0
from ecommerce.core.url_utils import get_lms_url
from ecommerce.extensions.api.serializers import OrderSerializer
from ecommerce.extensions.order.constants import PaymentEventTypeName
from ecommerce.extensions.payment.exceptions import InvalidBasketError, InvalidSignatureError
from ecommerce.extensions.payment.processors.cybersource import Cybersource
from ecommerce.extensions.payment.tests.mixins import CybersourceMixin, CybersourceNotificationTestsMixin
from ecommerce.extensions.payment.views.cybersource import CybersourceInterstitialView
from ecommerce.extensions.test.factories import create_basket
from ecommerce.tests.testcases import TestCase

JSON = 'application/json'

Basket = get_model('basket', 'Basket')
Order = get_model('order', 'Order')
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
PaymentEvent = get_model('order', 'PaymentEvent')
PaymentProcessorResponse = get_model('payment', 'PaymentProcessorResponse')
Selector = get_class('partner.strategy', 'Selector')
Source = get_model('payment', 'Source')

post_checkout = get_class('checkout.signals', 'post_checkout')


class LoginMixin(object):
    def setUp(self):
        super(LoginMixin, self).setUp()
        self.user = self.create_user()
        self.client.login(username=self.user.username, password=self.password)

Ejemplo n.º 53
0
import logging
import time

from django.contrib.sites.models import Site
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import NoReverseMatch, reverse
from django.http import HttpResponseRedirect
from django.conf import settings

from oscar.core.compat import user_is_authenticated
from oscar.core.loading import get_class, get_model

OrderCreator = get_class('order.utils', 'OrderCreator')
Dispatcher = get_class('customer.utils', 'Dispatcher')
CheckoutSessionMixin = get_class('checkout.session', 'CheckoutSessionMixin')
BillingAddress = get_model('order', 'BillingAddress')
ShippingAddress = get_model('order', 'ShippingAddress')
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
PaymentEventType = get_model('order', 'PaymentEventType')
PaymentEvent = get_model('order', 'PaymentEvent')
PaymentEventQuantity = get_model('order', 'PaymentEventQuantity')
UserAddress = get_model('address', 'UserAddress')
Basket = get_model('basket', 'Basket')
CommunicationEventType = get_model('customer', 'CommunicationEventType')
UnableToPlaceOrder = get_class('order.exceptions', 'UnableToPlaceOrder')

post_checkout = get_class('checkout.signals', 'post_checkout')

# Standard logger for checkout events
logger = logging.getLogger('oscar.checkout')
Ejemplo n.º 54
0
from django.template import RequestContext
from django.core.urlresolvers import reverse, resolve
from django.utils import simplejson as json
from django.db.models import get_model
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.views.generic import FormView, View
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist

from extra_views import ModelFormSetView
from oscar.core import ajax
from oscar.apps.basket.signals import basket_addition, voucher_addition
from oscar.templatetags.currency_filters import currency
from oscar.core.loading import get_class, get_classes

Applicator = get_class('offer.utils', 'Applicator')
(BasketLineForm, AddToBasketForm, BasketVoucherForm,
 SavedLineFormSet, SavedLineForm, ProductSelectionForm) = get_classes(
     'basket.forms',
     ('BasketLineForm', 'AddToBasketForm', 'BasketVoucherForm',
      'SavedLineFormSet', 'SavedLineForm', 'ProductSelectionForm'))
Repository = get_class('shipping.repository', ('Repository'))


def get_messages(basket, offers_before, offers_after, include_buttons=True):
    """
    Return the messages about offer changes
    """
    # Look for changes in offers
    offers_lost = set(offers_before.keys()).difference(set(
        offers_after.keys()))
Ejemplo n.º 55
0
from django.conf import settings
from django.contrib import messages
from django.utils.html import strip_tags
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext
from django.views import generic

from oscar.core.loading import get_class, get_model
from oscar.core.utils import redirect_to_referrer
from oscar.views.generic import BulkEditMixin

PageTitleMixin = get_class('customer.mixins', 'PageTitleMixin')
Notification = get_model('communication', 'Notification')


class NotificationListView(PageTitleMixin, generic.ListView):
    model = Notification
    template_name = 'oscar/communication/notifications/list.html'
    context_object_name = 'notifications'
    paginate_by = settings.OSCAR_NOTIFICATIONS_PER_PAGE
    page_title = _("Notifications")
    active_tab = 'notifications'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['list_type'] = self.list_type
        return ctx


class InboxView(NotificationListView):
Ejemplo n.º 56
0
from urllib import unquote, urlencode

import pytz
from django.conf import settings
from django.contrib import messages
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from oscar.core.loading import get_class, get_model

from ecommerce.courses.utils import mode_for_product
from ecommerce.extensions.order.exceptions import AlreadyPlacedOrderException
from ecommerce.extensions.order.utils import UserAlreadyPlacedOrder
from ecommerce.extensions.payment.utils import embargo_check
from ecommerce.referrals.models import Referral

Applicator = get_class('offer.applicator', 'Applicator')
Basket = get_model('basket', 'Basket')
BasketAttribute = get_model('basket', 'BasketAttribute')
BasketAttributeType = get_model('basket', 'BasketAttributeType')
BUNDLE = 'bundle_identifier'
ORGANIZATION_ATTRIBUTE_TYPE = 'organization'
StockRecord = get_model('partner', 'StockRecord')
OrderLine = get_model('order', 'Line')
Refund = get_model('refund', 'Refund')

logger = logging.getLogger(__name__)


def add_utm_params_to_url(url, params):
    # utm_params is [(u'utm_content', u'course-v1:IDBx IDB20.1x 1T2017'),...
    utm_params = [item for item in params if 'utm_' in item[0]]
Ejemplo n.º 57
0
from django.views.generic import DeleteView, FormView, ListView

from oscar.core.loading import get_class, get_classes, get_model
from oscar.views import sort_queryset

ConditionalOffer = get_model('offer', 'ConditionalOffer')
Condition = get_model('offer', 'Condition')
Range = get_model('offer', 'Range')
Product = get_model('catalogue', 'Product')
OrderDiscount = get_model('order', 'OrderDiscount')
Benefit = get_model('offer', 'Benefit')
MetaDataForm, ConditionForm, BenefitForm, RestrictionsForm, OfferSearchForm \
    = get_classes('dashboard.offers.forms',
                  ['MetaDataForm', 'ConditionForm', 'BenefitForm',
                   'RestrictionsForm', 'OfferSearchForm'])
OrderDiscountCSVFormatter = get_class('dashboard.offers.reports',
                                      'OrderDiscountCSVFormatter')


class OfferListView(ListView):
    model = ConditionalOffer
    context_object_name = 'offers'
    template_name = 'oscar/dashboard/offers/offer_list.html'
    form_class = OfferSearchForm
    paginate_by = settings.OSCAR_DASHBOARD_ITEMS_PER_PAGE

    def get_queryset(self):
        self.search_filters = []
        qs = self.model._default_manager.all()
        qs = sort_queryset(qs, self.request, [
            'name', 'offer_type', 'start_datetime', 'end_datetime',
            'num_applications', 'total_discount'
Ejemplo n.º 58
0
from django.conf import settings
from django.contrib.sites.models import Site
from django.db import transaction
from django.utils.translation import gettext_lazy as _

from oscar.apps.order.signals import order_placed
from oscar.core.loading import get_class, get_model

from . import exceptions

Order = get_model('order', 'Order')
Line = get_model('order', 'Line')
OrderDiscount = get_model('order', 'OrderDiscount')
CommunicationEvent = get_model('order', 'CommunicationEvent')
CommunicationEventType = get_model('communication', 'CommunicationEventType')
Dispatcher = get_class('communication.utils', 'Dispatcher')
Surcharge = get_model('order', 'Surcharge')


class OrderNumberGenerator(object):
    """
    Simple object for generating order numbers.

    We need this as the order number is often required for payment
    which takes place before the order model has been created.
    """
    def order_number(self, basket):
        """
        Return an order number for a given basket
        """
        return 100000 + basket.id
Ejemplo n.º 59
0
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from django import forms
from django.db.models import get_model
from django.contrib.auth.models import User
from django.contrib.auth import forms as auth_forms
from django.conf import settings
from django.core import validators
from django.core.exceptions import ValidationError
from django.contrib.sites.models import get_current_site
from django.contrib.auth.tokens import default_token_generator

from oscar.core.loading import get_profile_class, get_class
from oscar.apps.customer.utils import get_password_reset_url

Dispatcher = get_class('customer.utils', 'Dispatcher')
CommunicationEventType = get_model('customer', 'communicationeventtype')
ProductAlert = get_model('customer', 'ProductAlert')


def generate_username():
    uname = ''.join([random.choice(string.letters + string.digits + '_') for i in range(30)])
    try:
        User.objects.get(username=uname)
        return generate_username()
    except User.DoesNotExist:
        return uname


class PasswordResetForm(auth_forms.PasswordResetForm):
    communication_type_code = "PASSWORD_RESET"
Ejemplo n.º 60
0
from oscar.core.loading import get_class, get_model
from oscar.test.factories import (CategoryFactory, PartnerFactory,
                                  ProductAttributeFactory, ProductFactory,
                                  create_product)
from oscar.test.testcases import WebTestCase, add_permissions

Product = get_model('catalogue', 'Product')
ProductClass = get_model('catalogue', 'ProductClass')
ProductCategory = get_model('catalogue', 'ProductCategory')
Category = get_model('catalogue', 'Category')
StockRecord = get_model('partner', 'stockrecord')
AttributeOptionGroup = get_model('catalogue', 'AttributeOptionGroup')
AttributeOption = get_model('catalogue', 'AttributeOption')

AttributeOptionGroupForm = get_class('dashboard.catalogue.forms',
                                     'AttributeOptionGroupForm')
AttributeOptionFormSet = get_class('dashboard.catalogue.formsets',
                                   'AttributeOptionFormSet')
RelatedFieldWidgetWrapper = get_class('dashboard.widgets',
                                      'RelatedFieldWidgetWrapper')


class TestCatalogueViews(WebTestCase):
    is_staff = True

    def test_exist(self):
        urls = [
            reverse('dashboard:catalogue-product-list'),
            reverse('dashboard:catalogue-category-list'),
            reverse('dashboard:stock-alert-list')
        ]