Esempio n. 1
0
    def _get_column(self, model, field, known_names, identifier):
        if not self._valid_field(field.name):
            return None

        field_name = field.verbose_name.title()
        if field_name in known_names:
            field_name = "%s %s" % (model.__name__, field_name)

        display = "%s__%s" % (identifier, field.name) if identifier else field.name

        column = Column(
            "%s_%s" % (model.__name__.lower(), field.name),
            field_name,
            display=display
        )

        column, is_special = self.handle_special_column(field, column)
        if not is_special:
            if isinstance(field, CharField):
                column.filter_config = TextFilter(placeholder=field_name)
            if isinstance(field, EnumIntegerField):
                column.filter_config = ChoicesFilter(field.choices)
            if isinstance(field, BooleanField):
                column.filter_config = true_or_false_filter
        return column
Esempio n. 2
0
 def _get_column(self, field):
     field_name = field.verbose_name.title()
     if not self._valid_field(field.name):
         return None
     column = Column(field.name, field_name, display=field.name)
     column, is_special = self.handle_special_column(field, column)
     if not is_special:
         if isinstance(field, CharField):
             column.filter_config = TextFilter(placeholder=field_name)
         if isinstance(field, EnumIntegerField):
             column.filter_config = ChoicesFilter(field.choices)
         if isinstance(field, BooleanField):
             column.filter_config = true_or_false_filter
     return column
def test_mptt_filter(rf, admin_user):
    parent_category = Category.objects.create(name="parent")
    child_category = Category.objects.create(name="child")
    parent_category.children.add(child_category)
    columns = [
        Column(
            "name", "name",
            filter_config=MPTTFilter(
                choices=Category.objects.all(),
                filter_field="id"
            )
        )
    ]
    pico = get_pico(rf, admin_user, model=Category, columns=columns)
    data = pico.get_data({"perPage": 100, "page": 1, "filters": {"id": parent_category.id}})
    assert len(data["items"]) == 2

    data = pico.get_data({"perPage": 100, "page": 1, "filters": {"name": child_category.id}})
    assert len(data["items"]) == 1
Esempio n. 4
0
class ProductReviewListView(BaseProductReviewListView):
    model = ProductReview
    url_identifier = "product_reviews"

    default_columns = [
        Column("product",
               _("Product"),
               filter_config=TextFilter(
                   filter_field="product__translations__name",
                   placeholder=_("Filter by product...")))
    ] + BaseProductReviewListView.default_columns

    mass_actions = [
        "shuup_product_reviews.admin_module.mass_actions.ApproveProductReviewMassAction",
        "shuup_product_reviews.admin_module.mass_actions.RejectProductReviewMassAction"
    ]

    def get_queryset(self):
        return ProductReview.objects.filter(shop=get_shop(self.request))
def test_choice_filter_with_default(rf, admin_user, regular_user):
    columns = [
        Column("id", "Id", filter_config=Filter(), display=instance_id),
        Column("username", "Username", sortable=False, filter_config=MultiFieldTextFilter(filter_fields=("username", "email"), operator="iregex")),
        Column("email", "Email", sortable=False, filter_config=TextFilter()),
        Column("is_superuser", "Is Superuser", display="superuser_display", filter_config=ChoicesFilter(choices=false_and_true())),
        Column("date_joined", "Date Joined", filter_config=DateRangeFilter())
    ]

    is_active = [Column("is_active", "Is Active", filter_config=ChoicesFilter(choices=false_and_true))]
    is_active_with_default = [Column("is_active", "Is Active", filter_config=ChoicesFilter(choices=false_and_true, default=True))]

    query = {"perPage": 100, "page": 1, "sort": "+id"}

    pico_no_defaults = get_pico(rf, admin_user, columns=(columns + is_active))
    data = pico_no_defaults.get_data(query)

    superuser_field = data["columns"][3]
    assert superuser_field["id"] == "is_superuser"
    assert len(superuser_field["filter"]["choices"]) == 3
    assert superuser_field["filter"]["defaultChoice"] == "_all"
    assert superuser_field["filter"]["choices"][0][0] == superuser_field["filter"]["defaultChoice"]

    user_data = data["items"][0]
    user = get_user_model().objects.get(id=user_data["id"])
    assert user.is_active

    pico_with_defaults = get_pico(rf, admin_user, columns=(columns + is_active_with_default))
    data = pico_with_defaults.get_data(query)
    user_data = data["items"][0]
    user_with_defaults = get_user_model().objects.get(id=user_data["id"])
    assert user_with_defaults == user

    user.is_active = False
    user.save()

    data = pico_no_defaults.get_data(query)
    user_data = data["items"][0]
    new_user = get_user_model().objects.get(id=user_data["id"])
    assert new_user == user

    data = pico_with_defaults.get_data(query)
    user_data = data["items"][0]
    new_user_with_defaults = get_user_model().objects.get(id=user_data["id"])
    assert new_user_with_defaults != user_with_defaults
Esempio n. 6
0
class ContactListView(PicotableListView):
    model = Contact
    columns = [
        Column("name", _(u"Name"), linked=True, filter_config=TextFilter()),
        Column("type", _(u"Type"), display="get_type_display", sortable=False),  # TODO: Add a filter
        Column("email", _(u"Email"), filter_config=TextFilter()),
        Column("phone", _(u"Phone"), filter_config=TextFilter()),
        Column(
            "is_active",
            _(u"Active"),
            filter_config=ChoicesFilter([(False, _("no")), (True, _("yes"))], default=True)
        ),
        Column("n_orders", _(u"# Orders"), class_name="text-right", filter_config=RangeFilter(step=1)),
        Column("groups", _("Groups"), filter_config=ChoicesFilter(ContactGroup.objects.all(), "groups"))
    ]

    def get_queryset(self):
        groups = self.get_filter().get("groups")
        query = Q(groups__in=groups) if groups else Q()
        return super(ContactListView, self).get_queryset().filter(query).annotate(n_orders=Count("customer_orders"))

    def get_type_display(self, instance):
        if isinstance(instance, PersonContact):
            return _(u"Person")
        elif isinstance(instance, CompanyContact):
            return _(u"Company")
        else:
            return _(u"Contact")

    def get_object_abstract(self, instance, item):
        """
        :type instance: shuup.core.models.Contact
        """
        bits = filter(None, [
            item["type"],
            _("Active") if instance.is_active else _("Inactive"),
            _("Email: %s") % (instance.email or "\u2014"),
            _("Phone: %s") % (instance.phone or "\u2014"),
            _("%d orders") % instance.n_orders,
        ])
        return [
            {"text": instance.name or _("Contact"), "class": "header"},
            {"text": ", ".join(bits)}
        ]
Esempio n. 7
0
class UserListView(PicotableListView):
    model = settings.AUTH_USER_MODEL
    default_columns = [
        Column("username", _(u"Username"), filter_config=TextFilter()),
        Column("email", _(u"Email"), filter_config=TextFilter()),
        Column("first_name", _(u"First Name"), filter_config=TextFilter()),
        Column("last_name", _(u"Last Name"), filter_config=TextFilter()),
        Column(
            "is_active",
            _(u"Active"),
            filter_config=ChoicesFilter([(False, _("no")), (True, _("yes"))], default=True)
        ),
        Column("is_staff", _(u"Staff"), filter_config=true_or_false_filter),
        Column("is_superuser", _(u"Superuser"), filter_config=true_or_false_filter),
    ]

    def get_model(self):
        return get_user_model()

    def get_queryset(self):
        model = self.get_model()
        qs = self.get_model().objects.all()
        if "date_joined" in model._meta.get_all_field_names():
            qs = qs.order_by("-date_joined")
        return qs

    def get_context_data(self, **kwargs):
        context = super(UserListView, self).get_context_data(**kwargs)
        context["title"] = force_text(self.get_model()._meta.verbose_name_plural).title()
        return context

    def get_object_abstract(self, instance, item):
        bits = filter(None, [
            _("First Name: %s") % (getattr(instance, 'first_name', None) or "\u2014"),
            _("Last Name: %s") % (getattr(instance, 'last_name', None) or "\u2014"),
            _("Active") if instance.is_active else _(u"Inactive"),
            _("Email: %s") % (getattr(instance, 'email', None) or "\u2014"),
            _("Staff") if getattr(instance, 'is_staff', None) else None,
            _("Superuser") if getattr(instance, 'is_superuser', None) else None
        ])
        return [
            {"text": instance.get_username() or _("User"), "class": "header"},
            {"text": ", ".join([force_text(bit) for bit in bits])}
        ]
Esempio n. 8
0
    def __init__(self):
        def get_suppliers_column(iterable):
            return first([col for col in iterable if col.id in ["suppliers", "shopproduct_suppliers"]], default=None)

        def get_suppliers_filter():
            return TextFilter(filter_field="suppliers__name", placeholder=_("Filter by supplier name..."))

        if settings.SHUUP_ENABLE_MULTIPLE_SUPPLIERS and not get_suppliers_column(self.default_columns):
            self.default_columns.append(
                Column(
                    "suppliers",
                    _("Suppliers"),
                    display="format_suppliers",
                    ordering=8,
                    filter_config=get_suppliers_filter(),
                )
            )
        super(ProductListView, self).__init__()
        suppliers_column = get_suppliers_column(self.columns)
        if suppliers_column:
            suppliers_column.filter_config = get_suppliers_filter()
Esempio n. 9
0
class CouponListView(PicotableListView):
    model = Coupon
    default_columns = [
        Column("code",
               _(u"Code"),
               sort_field="code",
               display="code",
               linked=True,
               filter_config=TextFilter(operator="startswith")),
        Column("usages", _("Usages"), display="get_usages"),
        Column("usage_limit_customer", _("Usages Limit per contact")),
        Column("usage_limit", _("Usage Limit")),
        Column("active", _("Active")),
        Column("created_by", _(u"Created by")),
        Column("created_on", _(u"Date created")),
    ]

    def get_usages(self, instance, *args, **kwargs):
        return instance.usages.count()

    def get_context_data(self, **kwargs):
        context = super(CouponListView, self).get_context_data(**kwargs)
        if self.request.user.is_superuser:
            settings_button = SettingsActionButton.for_model(
                self.model, return_url="coupon")
        else:
            settings_button = None
        context["toolbar"] = Toolbar([
            NewActionButton("shuup_admin:coupon.new",
                            text=_("Create new Coupon")), settings_button
        ],
                                     view=self)
        return context

    def get_queryset(self):
        queryset = super(CouponListView, self).get_queryset()
        if not self.request.user.is_superuser:
            queryset = queryset.filter(shop=get_shop(self.request))

        supplier = get_supplier(self.request)
        if supplier:
            queryset = queryset.filter(supplier=supplier)
        return queryset
Esempio n. 10
0
class PermissionGroupListView(PicotableListView):
    model = PermissionGroup
    default_columns = [
        Column("name",
               _(u"Name"),
               sort_field="name",
               display="name",
               filter_config=TextFilter(filter_field="name",
                                        placeholder=_("Filter by name..."))),
    ]

    def get_context_data(self, **kwargs):
        context = super(PermissionGroupListView,
                        self).get_context_data(**kwargs)
        context["title"] = _("Permission Groups")
        context["toolbar"] = Toolbar([
            NewActionButton("shuup_admin:permission_group.new",
                            text=_("Create new Permission Group")),
            SettingsActionButton.for_model(self.model,
                                           return_url="permission_group")
        ])
        return context
Esempio n. 11
0
def get_pico(rf, model=None, columns=None):
    model = model or get_user_model()
    columns = columns or [
        Column("id", "Id", filter_config=Filter(), display=instance_id),
        Column("username", "Username", sortable=False, filter_config=MultiFieldTextFilter(filter_fields=("username", "email"), operator="iregex")),
        Column("email", "Email", sortable=False, filter_config=TextFilter()),
        Column("is_superuser", "Is Superuser", display="superuser_display", filter_config=ChoicesFilter(choices=false_and_true())),
        Column("is_active", "Is Active", filter_config=ChoicesFilter(choices=false_and_true)),  # `choices` callable
        Column("date_joined", "Date Joined", filter_config=DateRangeFilter())
    ]

    return Picotable(
        request=rf.get("/"),
        columns=columns,
        queryset=model.objects.all(),
        context=PicoContext()
    )
Esempio n. 12
0
    def _get_translated_column(self, model, field, known_names, identifier):
        field_name = field.verbose_name.title()
        if identifier:
            field_name = "%s %s" % (identifier.replace("_", " ").capitalize(), field_name)

        # take the first extension, usually we should not have more then one
        translation_rel_name = model._parler_meta._extensions[0].rel_name

        if model != self.model:
            filter_field = "%s__%s__%s" % (identifier, translation_rel_name, field.name) if identifier else field.name
        else:
            filter_field = "%s__%s" % (translation_rel_name, field.name)

        display = "%s__%s" % (identifier, field.name) if identifier else field.name

        column = Column(
            "%s_%s" % ((identifier if identifier else model.__name__.lower()), field.name),
            field_name,
            sort_field=display,
            display=display,
            filter_config=TextFilter(filter_field=filter_field, placeholder=field_name)
        )
        return self.handle_special_column(field, column)[0]
Esempio n. 13
0
class CategoryListView(PicotableListView):
    model = Category
    default_columns = [
        Column("name",
               _(u"Name"),
               sortable=False,
               display="format_name",
               linked=True,
               filter_config=MPTTFilter(choices="get_name_filter_choices",
                                        filter_field="id"))
    ]

    def get_name_filter_choices(self):
        choices = []
        for c in Category.objects.all_except_deleted():
            name = self.format_name(c)
            choices.append((c.pk, name))
        return choices

    def get_queryset(self):
        return Category.objects.all_except_deleted()

    def format_name(self, instance, *args, **kwargs):
        level = getattr(instance, instance._mptt_meta.level_attr)
        return ('---' * level) + ' ' + instance.name

    def get_object_abstract(self, instance, item):
        return [
            {
                "text": "%s" % instance,
                "class": "header"
            },
            {
                "title": _(u"Status"),
                "text": item.get("status")
            },
        ]
Esempio n. 14
0
class SupplierReviewOptionsModule(AdminModule):
    name = _("Vendor Review Options")
    breadcrumbs_menu_entry = MenuEntry(name, url="shuup_admin:vendor_reviews_options.list")

    default_columns = [
        Column("name", _(u"Name"), linked=True, filter_config=TextFilter()),
    ]

    def get_urls(self):
        return [
            admin_url(
                r"^vendor_reviews_options/(?P<pk>\d+)/delete/$",
                "shuup_vendor_reviews.admin_module.views.VendorReviewOptionDeleteView",
                name="vendor_reviews_options.delete"
            ),

        ] + get_edit_and_list_urls(
            url_prefix="^vendor_reviews_options",
            view_template="shuup_vendor_reviews.admin_module.views.VendorReviewOption%sView",
            name_template="vendor_reviews_options.%s"
        )

    def get_model_url(self, object, kind, shop=None):
        return derive_model_url(VendorReviewOption, "shuup_admin:vendor_reviews_options", object, kind)

    def get_menu_entries(self, request):
        return [
            MenuEntry(
                text=self.name,
                icon="fa fa-star",
                url="shuup_admin:vendor_reviews_options.list",
                category=STOREFRONT_MENU_CATEGORY,
                subcategory="other_settings",
                ordering=6
            )
        ]
Esempio n. 15
0
class AttributeListView(PicotableListView):
    model = Attribute
    default_columns = [
        Column("identifier", _("Identifier"), filter_config=TextFilter(
            filter_field="identifier",
            placeholder=_("Filter by identifier...")
        )),
        Column("name", _("Name"), sort_field="translations__name", display="name", filter_config=TextFilter(
            filter_field="translations__name",
            placeholder=_("Filter by name...")
        )),
        Column("type", _("Type"), filter_config=ChoicesFilter(AttributeType.choices)),
        Column("visibility_mode", _("Visibility Mode"), filter_config=ChoicesFilter(AttributeVisibility.choices)),
        Column("searchable", _("Searchable")),
        Column("n_product_types", _("Used in # Product Types")),
    ]

    def get_queryset(self):
        return Attribute.objects.all().annotate(n_product_types=Count("product_types"))
Esempio n. 16
0
class CouponCodeListView(PicotableListView):
    model = CouponCode
    url_identifier = "discounts_coupon_codes"

    default_columns = [
        Column("code",
               _("Code"),
               sort_field="code",
               display="code",
               linked=True,
               filter_config=TextFilter(operator="startswith")),
        Column("usages", _("Usages"), display="get_usages"),
        Column("usage_limit_customer", _("Usages Limit per contact")),
        Column("usage_limit", _("Usage Limit")),
        Column("active", _("Active")),
        Column("created_by", _("Created by")),
        Column("created_on", _("Date created")),
    ]

    def get_usages(self, instance, *args, **kwargs):
        return instance.usages.count()

    def get_queryset(self):
        return CouponCode.objects.filter(shops=get_shop(self.request))
Esempio n. 17
0
class CouponListView(PicotableListView):
    model = Coupon
    columns = [
        Column(
            "code", _(u"Code"), sort_field="code", display="code", linked=True,
            filter_config=TextFilter(operator="startswith")
        ),
        Column("usages", _("Usages"), display="get_usages"),
        Column("usage_limit_customer", _("Usages Limit per contact")),
        Column("usage_limit", _("Usage Limit")),
        Column("active", _("Active")),
        Column("created_by", _(u"Created by")),
        Column("created_on", _(u"Date created")),
    ]

    def get_usages(self, instance, *args, **kwargs):
        return instance.usages.count()

    def get_context_data(self, **kwargs):
        context = super(CouponListView, self).get_context_data(**kwargs)
        context["toolbar"] = Toolbar([
            NewActionButton("shuup_admin:coupons.new", text=_("Create new Coupon")),
        ])
        return context
Esempio n. 18
0
class TableListView(PicotableListView):
    model = ShippingTable
    default_columns = [
        Column("name", _("Name"), filter_config=TextFilter()),
        Column("identifier", _("Identifier"), filter_config=TextFilter()),
        Column("enabled", _("Enabled")),
        Column("start_date", _("Start Date"), display="format_start_date"),
        Column("end_date", _("End Date"), display="format_end_date"),
        Column(
            "carrier",
            _("Carrier"),
            filter_config=ChoicesFilter(choices=ShippingCarrier.objects.all()))
    ]

    def format_start_date(self, instance, *args, **kwargs):
        if instance.start_date:
            return get_locally_formatted_datetime(instance.start_date)

    def format_end_date(self, instance, *args, **kwargs):
        if instance.end_date:
            return get_locally_formatted_datetime(instance.end_date)
Esempio n. 19
0
def get_pico(rf, admin_user, model=None, columns=None):
    shop = get_default_shop()
    model = model or get_user_model()
    columns = columns or [
        Column("id", "Id", filter_config=Filter(), display=instance_id),
        Column("username", "Username", sortable=False, filter_config=MultiFieldTextFilter(filter_fields=("username", "email"), operator="iregex")),
        Column("email", "Email", sortable=False, filter_config=TextFilter()),
        Column("is_superuser", "Is Superuser", display="superuser_display", filter_config=ChoicesFilter(choices=false_and_true())),
        Column("is_active", "Is Active", filter_config=ChoicesFilter(choices=false_and_true)),  # `choices` callable
        Column("date_joined", "Date Joined", filter_config=DateRangeFilter())
    ]
    admin_user.is_staff = True
    admin_user.save()
    shop.staff_members.add(admin_user)
    request = apply_request_middleware(rf.get("/"), user=admin_user)
    return Picotable(
        request=request,
        columns=columns,
        mass_actions=[],
        queryset=model.objects.all(),
        context=PicoContext(request)
    )
Esempio n. 20
0
class ProductListView(PicotableListView):
    model = Product
    default_columns = [
        Column("sku", _(u"SKU"), display="sku", filter_config=TextFilter(placeholder=_("Filter by SKU..."))),
        Column("name", _(u"Name"), sort_field="translations__name", display="name", filter_config=TextFilter(
            filter_field="translations__name",
            placeholder=_("Filter by name...")
        )),
        Column("barcode", _(u"Barcode"), display="barcode", filter_config=TextFilter(_("Filter by barcode..."))),
        Column("type", _(u"Type")),
        Column("mode", _(u"Mode"), filter_config=ChoicesFilter(ProductMode.choices)),
        Column("category", _(u"Primary Category"), filter_config=ChoicesFilter(Category.objects.all(), "category")),
    ]

    def get_queryset(self):
        filter = self.get_filter()
        shop_id = filter.get("shop")
        qs = Product.objects.all_except_deleted()
        q = Q()
        for mode in filter.get("modes", []):
            q |= Q(mode=mode)
        manufacturer_ids = filter.get("manufacturers")
        if manufacturer_ids:
            q |= Q(manufacturer_id__in=manufacturer_ids)
        qs = qs.filter(q)
        if shop_id:
            qs = qs.filter(shop_products__shop_id=int(shop_id))
        return qs

    def get_object_abstract(self, instance, item):
        return [
            {"text": "%s" % instance, "class": "header"},
            {"title": _(u"Barcode"), "text": item.get("barcode")},
            {"title": _(u"SKU"), "text": item.get("sku")},
            {"title": _(u"Type"), "text": item.get("type")},
            {"title": _(u"Primary Category"), "text": item.get("category")}
        ]
Esempio n. 21
0
class FontListView(PicotableListView):
    url_identifier = "xtheme.font"
    model = Font
    default_columns = [
        Column(
            "name",
            _("Name"),
            sort_field="name",
            display="name",
            filter_config=TextFilter(filter_field="name",
                                     placeholder=_("Filter by name...")),
        ),
        Column("woff", _("Woff"), display="format_woff"),
        Column("woff2", _("Woff2"), display="format_woff2"),
        Column("ttf", _("TTF"), display="format_ttf"),
        Column("svg", _("SVG"), display="format_svg"),
        Column("eot", _("EOT"), display="format_eot"),
    ]

    def format_eot(self, instance):
        return instance.eot.label if instance.eot else ""

    def format_ttf(self, instance):
        return instance.ttf.label if instance.ttf else ""

    def format_woff(self, instance):
        return instance.woff.label if instance.woff else ""

    def format_woff2(self, instance):
        return instance.woff2.label if instance.woff2 else ""

    def format_svg(self, instance):
        return instance.svg.label if instance.svg else ""

    def get_queryset(self):
        return Font.objects.filter(shop=get_shop(self.request))
Esempio n. 22
0
class OrderStatusListView(PicotableListView):
    model = OrderStatus
    default_columns = [
        Column("identifier",
               _("Identifier"),
               linked=True,
               filter_config=TextFilter(operator="startswith")),
        Column(
            "name",
            _("Name"),
            linked=True,
            filter_config=TextFilter(operator="startswith",
                                     filter_field="translations__name"),
        ),
        Column(
            "public_name",
            _("Public Name"),
            linked=False,
            filter_config=TextFilter(operator="startswith",
                                     filter_field="translations__name"),
        ),
        Column("role",
               _("Role"),
               linked=False,
               filter_config=ChoicesFilter(choices=OrderStatusRole.choices)),
        Column("default",
               _("Default"),
               linked=False,
               filter_config=ChoicesFilter([(False, _("yes")),
                                            (True, _("no"))])),
        Column("is_active",
               _("Active"),
               linked=False,
               filter_config=ChoicesFilter([(False, _("yes")),
                                            (True, _("no"))])),
    ]
Esempio n. 23
0
class OrderListView(PicotableListView):
    model = Order
    default_columns = [
        Column("identifier",
               _(u"Order"),
               linked=True,
               filter_config=TextFilter(operator="startswith")),
        Column("order_date",
               _(u"Order Date"),
               display="format_order_date",
               filter_config=DateRangeFilter()),
        Column("customer",
               _(u"Customer"),
               display="format_customer_name",
               filter_config=MultiFieldTextFilter(
                   filter_fields=("customer__email", "customer__name",
                                  "billing_address__name",
                                  "shipping_address__name", "orderer__name"))),
        Column(
            "status",
            _(u"Status"),
            filter_config=ChoicesFilter(choices=OrderStatus.objects.all()),
        ),
        Column("payment_status",
               _(u"Payment Status"),
               filter_config=ChoicesFilter(choices=PaymentStatus.choices)),
        Column("shipping_status",
               _(u"Shipping Status"),
               filter_config=ChoicesFilter(choices=ShippingStatus.choices)),
        Column("taxful_total_price_value",
               _(u"Total"),
               sort_field="taxful_total_price_value",
               display="format_taxful_total_price",
               class_name="text-right",
               filter_config=RangeFilter(
                   field_type="number",
                   filter_field="taxful_total_price_value")),
    ]
    related_objects = [
        ("shop", "shuup.core.models:Shop"),
        ("billing_address", "shuup.core.models:ImmutableAddress"),
        ("shipping_address", "shuup.core.models:ImmutableAddress"),
    ]
    mass_actions = [
        "shuup.admin.modules.orders.mass_actions:CancelOrderAction",
        "shuup.admin.modules.orders.mass_actions:OrderConfirmationPdfAction",
        "shuup.admin.modules.orders.mass_actions:OrderDeliveryPdfAction",
    ]
    toolbar_buttons_provider_key = "order_list_toolbar_provider"
    mass_actions_provider_key = "order_list_mass_actions_provider"

    def get_toolbar(self):
        toolbar = Toolbar([
            NewActionButton.for_model(Order,
                                      url=reverse("shuup_admin:order.new")),
            SettingsActionButton.for_model(Order, return_url="order")
        ],
                          view=self)
        return toolbar

    def get_queryset(self):
        return super(OrderListView, self).get_queryset().exclude(
            deleted=True).filter(shop=get_shop(self.request))

    def format_customer_name(self, instance, *args, **kwargs):
        return instance.get_customer_name() or ""

    def format_order_date(self, instance, *args, **kwargs):
        return get_locally_formatted_datetime(instance.order_date)

    def format_taxful_total_price(self, instance, *args, **kwargs):
        return escape(format_money(instance.taxful_total_price))

    def label(self, instance, *args, **kwargs):
        # format label to make it human readable
        return instance.label.replace("_", " ").title()

    def get_object_abstract(self, instance, item):
        return [{
            "text": "%s" % instance,
            "class": "header"
        }, {
            "title": _(u"Total"),
            "text": item.get("taxful_total_price_value")
        }, {
            "title": _(u"Status"),
            "text": item.get("status")
        }]
Esempio n. 24
0
class ProductListView(PicotableListView):
    model = ShopProduct
    picotable_class = ProductPicotable

    default_columns = [
        Column("primary_image",
               _(u"Primary Image"),
               display="get_primary_image",
               class_name="text-center",
               raw=True,
               ordering=1,
               sortable=False),
        Column("name",
               _(u"Name"),
               sort_field="product__translations__name",
               display="product__name",
               filter_config=TextFilter(
                   filter_field="product__translations__name",
                   placeholder=_("Filter by name...")),
               ordering=2),
        Column("shop", _("Shop"), ordering=2),
        Column("sku",
               _(u"SKU"),
               display="product__sku",
               filter_config=RangeFilter(filter_field="product__sku"),
               ordering=3),
        Column("barcode",
               _(u"Barcode"),
               display="product__barcode",
               filter_config=TextFilter(placeholder=_("Filter by barcode...")),
               ordering=4),
        Column("type", _(u"Type"), display="product__type", ordering=5),
        Column("mode",
               _(u"Mode"),
               display="product__mode",
               filter_config=ChoicesFilter(ProductMode.choices),
               ordering=6),
    ]

    related_objects = [
        ("product", "shuup.core.models:Product"),
    ]

    mass_actions = [
        "shuup.admin.modules.products.mass_actions:VisibleMassAction",
        "shuup.admin.modules.products.mass_actions:InvisibleMassAction",
        "shuup.admin.modules.products.mass_actions:FileResponseAction",
        "shuup.admin.modules.products.mass_actions:EditProductAttributesAction",
    ]

    def get_columns(self):
        for column in self.columns:
            if column.id == 'shop':
                shops = Shop.objects.get_for_user(
                    self.request.user).prefetch_related('translations')
                column.filter_config = ChoicesFilter(choices=shops)
                break
        return self.columns

    def get_primary_image(self, instance):
        if instance.product.primary_image:
            thumbnail = instance.product.primary_image.get_thumbnail()
            if thumbnail:
                return "<img src='/media/{}'>".format(thumbnail)
        return "<img src='%s'>" % static(
            "shuup_admin/img/no_image_thumbnail.png")

    def get_queryset(self):
        filter = self.get_filter()
        shop = self.request.shop
        qs = ShopProduct.objects.filter(product__deleted=False, shop=shop)
        q = Q()
        for mode in filter.get("modes", []):
            q |= Q(product__mode=mode)
        manufacturer_ids = filter.get("manufacturers")
        if manufacturer_ids:
            q |= Q(product__manufacturer_id__in=manufacturer_ids)
        qs = qs.filter(q)
        return qs

    def get_object_abstract(self, instance, item):
        return [
            {
                "text": "%s" % instance.product,
                "class": "header"
            },
            {
                "title": _(u"Barcode"),
                "text": item.get("product__barcode")
            },
            {
                "title": _(u"SKU"),
                "text": item.get("product__sku")
            },
            {
                "title": _(u"Type"),
                "text": item.get("product__type")
            },
        ]
Esempio n. 25
0
class DiscountListView(PicotableListView):
    model = Discount
    url_identifier = "discounts"

    default_columns = [
        Column("name",
               _("Discount Name"),
               sort_field="name",
               display="name",
               filter_config=TextFilter(filter_field="name",
                                        placeholder=_("Filter by name..."))),
        Column("product__translations__name",
               _("Product"),
               display="product",
               filter_config=TextFilter(
                   filter_field="product__translations__name",
                   placeholder=_("Filter by product..."))),
        Column("category",
               _("Category"),
               display="category",
               filter_config=TextFilter(
                   filter_field="category__translations__name",
                   placeholder=_("Filter by category..."))),
        Column("contact_group",
               _("Contact Group"),
               display="contact_group",
               filter_config=TextFilter(
                   filter_field="contact_group__translations__name",
                   placeholder=_("Filter by contact group..."))),
        Column("contact",
               _("Contact"),
               display="contact",
               filter_config=TextFilter(
                   filter_field="contact__translations__name",
                   placeholder=_("Filter by contact..."))),
        Column("coupon_code",
               _("Coupon code"),
               display="coupon_code",
               filter_config=TextFilter(
                   filter_field="coupon_code__code",
                   placeholder=_("Filter by coupon code..."))),
        Column("discount_effect", _("Effect"), display="get_discount_effect"),
        Column("end_datetime",
               _("End Date and Time"),
               display="format_end_datetime",
               filter_config=DateRangeFilter())
    ]

    mass_actions = ["shuup.discounts.admin.mass_actions:ArchiveMassAction"]

    toolbar_buttons_provider_key = "discount_list_toolbar_provider"
    mass_actions_provider_key = "discount_list_actions_provider"

    def get_discount_effect(self, instance):
        if not (instance.discount_amount_value
                or instance.discounted_price_value
                or instance.discount_percentage):
            return "-"

        effects = []
        shop = get_shop(self.request)
        if instance.discount_amount_value:
            effects.append(
                "- %s" %
                format_money(shop.create_price(instance.discount_amount_value))
                if shop else format_number(instance.discount_amount_value))

        if instance.discounted_price_value:
            effects.append(
                format_money(shop.create_price(instance.discounted_price_value)
                             )
                if shop else format_number(instance.discounted_price_value))

        if instance.discount_percentage:
            effects.append(format_percent(instance.discount_percentage))

        return ','.join(effects)

    def format_end_datetime(self, instance, *args, **kwargs):
        return get_locally_formatted_datetime(
            instance.end_datetime) if instance.end_datetime else ""

    def get_queryset(self):
        return Discount.objects.active(get_shop(self.request))
Esempio n. 26
0
class ShipmentListView(PicotableListView):
    model = Shipment
    template_name = "shuup/admin/orders/shipment_picotable.jinja"
    default_columns = [
        Column("id", _("ID"), linked=True),
        Column("order", _("Order"), display="get_order", raw=True),
        Column("get_content", _("Content"), display="get_content", raw=True),
        Column("supplier", _("Supplier"), display="get_supplier", raw=True),
        Column("tracking_code",
               _("Tracking Code"),
               display="tracking_code_url",
               raw=True),
        Column("status",
               _("Status"),
               display="create_action_buttons",
               raw=True),
    ]

    def tracking_code_url(self, instance):
        if instance.tracking_url:
            return f'<a target="_blank" ref="noopened" href="{instance.tracking_url}">{instance.tracking_code}</a>'
        return instance.tracking_code

    def get_supplier(self, instance):
        return instance.supplier.name

    def get_order(self, instance):
        try:
            order_url = get_model_url(instance.order)
            return f'<a href="{order_url}">{str(instance.order)}</a>'
        except NoModelUrl:
            return str(instance.order)

    def get_content(self, instance):
        shipment_products = ShipmentProduct.objects.filter(
            shipment=instance).select_related("product", "product__sales_unit")
        content = []

        for shipment_product in shipment_products:
            unit = UnitInterface(shipment_product.product.sales_unit)
            quantity = unit.render_quantity(shipment_product.quantity)
            content.append(f"{shipment_product.product} ({quantity})")
        return ", ".join(content)

    def create_action_buttons(self, instance):
        if instance.order.shipping_method and instance.order.shipping_method.carrier.uses_default_shipments_manager:
            if instance.status not in (ShipmentStatus.SENT,
                                       ShipmentStatus.ERROR):
                url = "{base_url}?next={next_url}".format(
                    base_url=reverse("shuup_admin:order.set-shipment-sent",
                                     kwargs={"pk": instance.pk}),
                    next_url=reverse('shuup_admin:order.shipments.list'))
                return render_to_string(
                    "shuup/admin/orders/_set_shipments_status_button.jinja", {
                        "shipment_id": instance.pk,
                        "url": url,
                    })
        return instance.status.label

    def __init__(self):
        super().__init__()
        self.columns = self.default_columns

    def get_queryset(self):
        queryset = super().get_queryset().exclude(
            status=ShipmentStatus.DELETED).select_related(
                "order", "order__shipping_method")
        supplier = get_supplier(self.request)
        if supplier:
            queryset = queryset.filter(supplier=supplier)
        return queryset

    def get_object_abstract(self, instance, item):
        return [{
            "text":
            _("Shipment {shipment_id}").format(shipment_id=item.get("id")),
            "class":
            "header"
        }, {
            "title": _("Order"),
            "text": " ",
            "raw": item.get("order")
        }, {
            "title": _("Supplier"),
            "text": item.get("supplier")
        }, {
            "title": _("Content"),
            "text": item.get("get_content")
        }, {
            "title": _("Tracking code"),
            "text": " ",
            "raw": item.get("tracking_code")
        }, {
            "title": _("Status"),
            "text": " ",
            "raw": item.get("status")
        }]
Esempio n. 27
0
 def get_column(self, model, known_names, identifier):
     return Column("custom_product_info",
                   u"CustomProductInfo",
                   display="get_custom_product_info_display")
Esempio n. 28
0
class CartListView(PicotableListView):
    model = StoredBasket
    default_columns = [
        Column("key", _(u"Key"), filter_config=TextFilter(filter_field="key")),
        Column("updated_on",
               _(u"Last updated on"),
               display="format_updated_date",
               filter_config=DateRangeFilter()),
        Column("finished",
               _("Completed"),
               display="format_finished_status",
               filter_config=ChoicesFilter([(True, _("yes")),
                                            (False, _("no"))],
                                           filter_field="finished",
                                           default=False)),
        Column("shop",
               _("Shop"),
               filter_config=TextFilter(
                   filter_field="shop__translations__public_name")),
        Column("supplier",
               _("Supplier"),
               filter_config=TextFilter(filter_field="supplier__name")),
        Column("customer",
               _(u"Customer"),
               filter_config=MultiFieldTextFilter(
                   filter_fields=("customer__email", "customer__name"))),
        Column("product_count",
               _("Product count"),
               filter_config=RangeFilter()),
        Column("taxful_total_price",
               _(u"Total"),
               sort_field="taxful_total_price_value",
               display="format_taxful_total_price",
               class_name="text-right",
               filter_config=RangeFilter(
                   field_type="number",
                   filter_field="taxful_total_price_value")),
    ]
    toolbar_buttons_provider_key = "cart_list_toolbar_provider"
    mass_actions_provider_key = "cart_list_actions_provider"

    def __init__(self):
        super(CartListView, self).__init__()
        self.columns = self.default_columns

    def get_queryset(self):
        """
        Ignore potentially active carts, displaying only those not updated for at least 2 hours.
        """
        shop = get_shop(self.request)
        filters = {"product_count__gte": 0, "persistent": False, "shop": shop}
        return super(CartListView, self).get_queryset().filter(**filters)

    def format_finished_status(self, instance, *args, **kwargs):
        return "yes" if instance.finished else "no"

    def format_updated_date(self, instance, *args, **kwargs):
        return get_locally_formatted_datetime(instance.updated_on)

    def format_taxful_total_price(self, instance, *args, **kwargs):
        if not instance.taxful_total_price:
            return ""
        return escape(format_money(instance.taxful_total_price))

    def get_context_data(self, **kwargs):
        context = super(CartListView, self).get_context_data(**kwargs)
        context["title"] = _("Carts")
        return context

    def get_object_abstract(self, instance, item):
        return [
            {
                "text": "%s" % instance,
                "class": "header"
            },
            {
                "title": _(u"Created on"),
                "text": item.get("created_on")
            },
            {
                "title": _(u"Last updated on"),
                "text": item.get("updated_on")
            },
            {
                "title": _(u"Ordered"),
                "text": item.get("finished")
            },
            {
                "title": _(u"Total"),
                "text": item.get("taxful_total_price")
            },
        ]
Esempio n. 29
0
def test_column_is_user_friendly():
    with pytest.raises(NameError):
        Column(id="foo", title="bar", asdf=True)
Esempio n. 30
0
 def __init__(self, **kwargs):
     self.default_columns = self.base_columns + [
         Column("carrier", _("Carrier"))
     ]
     super(ShippingMethodListView, self).__init__(**kwargs)
Esempio n. 31
0
class StocksListView(PicotableListView):
    template_name = "shuup/simple_supplier/admin/base_picotable.jinja"
    model = Product
    default_columns = [
        Column(
            "sku",
            _("SKU"),
            sort_field="product__sku",
            display="product__sku",
            linked=True,
            filter_config=TextFilter(filter_field="product__sku",
                                     placeholder=_("Filter by SKU...")),
        ),
        Column(
            "name",
            _("Name"),
            sort_field="product__translations__name",
            display="product__name",
            linked=True,
            filter_config=TextFilter(
                filter_field="product__translations__name",
                placeholder=_("Filter by name...")),
        ),
        Column(
            "supplier",
            _("Supplier"),
            display="supplier",
            linked=False,
            filter_config=ChoicesFilter(Supplier.objects.enabled().filter(
                supplier_modules__module_identifier="simple_supplier")),
        ),
        Column(
            "stock_information",
            _("Stock information"),
            display="get_stock_information",
            linked=False,
            sortable=False,
            raw=True,
        ),
        Column(
            "adjust_stock",
            _("Adjust stock"),
            display="get_stock_adjustment_form",
            sortable=False,
            linked=False,
            raw=True,
        ),
    ]

    def __init__(self):
        super(StocksListView, self).__init__()
        self.columns = self.default_columns

    def get_object_abstract(self, instance, item):
        item.update({"_linked_in_mobile": False, "_url": ""})
        return [
            {
                "text": item.get("name"),
                "class": "header"
            },
            {
                "title": "",
                "text": item.get("sku")
            },
            {
                "title": "",
                "text": " ",
                "raw": item.get("stock_information")
            },
            {
                "title": "",
                "text": " ",
                "raw": item.get("adjust_stock")
            },
        ]

    def get_queryset(self):
        return StockCount.objects.filter(
            supplier__supplier_modules__module_identifier="simple_supplier",
            supplier__enabled=True,
            supplier__stock_managed=True,
            product__deleted=False,
        ).order_by("product__id")

    def get_context_data(self, **kwargs):
        context = super(PicotableListView, self).get_context_data(**kwargs)
        context["toolbar"] = None
        context["title"] = _("Stock management")
        return context

    def get_stock_information(self, instance):
        return get_stock_information_html(instance.supplier, instance.product)

    def get_stock_adjustment_form(self, instance):
        return get_stock_adjustment_div(self.request, instance.supplier,
                                        instance.product)
Esempio n. 32
0
 def __init__(self, **kwargs):
     self.default_columns = self.base_columns + [
         Column("payment_processor", _("Payment Processor"))
     ]
     super(PaymentMethodListView, self).__init__(**kwargs)