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
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
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
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)} ]
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])} ]
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()
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
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
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() )
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]
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") }, ]
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 ) ]
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"))
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))
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
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)
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) )
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")} ]
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))
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"))])), ]
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") }]
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") }, ]
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))
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") }]
def get_column(self, model, known_names, identifier): return Column("custom_product_info", u"CustomProductInfo", display="get_custom_product_info_display")
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") }, ]
def test_column_is_user_friendly(): with pytest.raises(NameError): Column(id="foo", title="bar", asdf=True)
def __init__(self, **kwargs): self.default_columns = self.base_columns + [ Column("carrier", _("Carrier")) ] super(ShippingMethodListView, self).__init__(**kwargs)
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)
def __init__(self, **kwargs): self.default_columns = self.base_columns + [ Column("payment_processor", _("Payment Processor")) ] super(PaymentMethodListView, self).__init__(**kwargs)