class AttributeModule(AdminModule): name = _("Attributes") breadcrumbs_menu_entry = MenuEntry(text=name, url="shoop_admin:attribute.list") def get_urls(self): return [ admin_url( "^attributes/(?P<pk>\d+)/$", "shoop.admin.modules.attributes.views.AttributeEditView", name="attribute.edit"), admin_url( "^attributes/new/$", "shoop.admin.modules.attributes.views.AttributeEditView", kwargs={"pk": None}, name="attribute.new" ), admin_url( "^attributes/$", "shoop.admin.modules.attributes.views.AttributeListView", name="attribute.list" ), ] def get_menu_category_icons(self): return {self.name: "fa fa-tags"} def get_menu_entries(self, request): return [ MenuEntry( text=_("Attributes"), icon="fa fa-tags", url="shoop_admin:attribute.list", category=self.name ) ] def get_model_url(self, object, kind): return derive_model_url(Attribute, "shoop_admin:attribute", object, kind)
class ShopModule(AdminModule): name = _("Shops") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:shop.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^shops", view_template="shoop.admin.modules.shops.views.Shop%sView", name_template="shop.%s") def get_menu_entries(self, request): category = _( "System" ) # NB: To clutter the menu a little less, shops live under System return [ MenuEntry(text=self.name, icon="fa fa-house", url="shoop_admin:shop.list", category=category), ] def get_model_url(self, object, kind): return derive_model_url(Shop, "shoop_admin:shop", object, kind)
class ContactGroupModule(AdminModule): name = _("Contact Groups") category = _("Contacts") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:contact-group.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^contact-groups", view_template= "shoop.admin.modules.contact_groups.views.ContactGroup%sView", name_template="contact-group.%s") def get_menu_entries(self, request): return [ MenuEntry(text=self.name, icon="fa fa-asterisk", url="shoop_admin:contact-group.list", category=self.category), ] def get_model_url(self, object, kind): return derive_model_url(ContactGroup, "shoop_admin:contact-group", object, kind)
class SalesUnitModule(AdminModule): name = _("Sales Units") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:sales-unit.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^sales-units", view_template="shoop.admin.modules.sales_units.views.SalesUnit%sView", name_template="sales-unit.%s" ) def get_menu_entries(self, request): category = _("Products") return [ MenuEntry( text=self.name, icon="fa fa-asterisk", url="shoop_admin:sales-unit.list", category=category ), ] def get_model_url(self, object, kind): return derive_model_url(SalesUnit, "shoop_admin:sales-unit", object, kind)
class ProductTypeModule(AdminModule): name = _("Product Types") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:product-type.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^product-types", view_template= "shoop.admin.modules.product_types.views.ProductType%sView", name_template="product-type.%s") def get_menu_entries(self, request): category = _("Products") return [ MenuEntry(text=_("Product types"), icon="fa fa-asterisk", url="shoop_admin:product-type.list", category=category), ] def get_model_url(self, object, kind): return derive_model_url(ProductType, "shoop_admin:product-type", object, kind)
class ManufacturerModule(AdminModule): name = _("Manufacturers") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:manufacturers.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^Manufacturers", view_template= "shoop.admin.modules.manufacturers.views.Manufacturer%sView", name_template="manufacturers.%s") def get_menu_entries(self, request): category = _("Products") return [ MenuEntry(text=_("Manufacturers"), icon="fa fa-building", url="shoop_admin:manufacturers.list", category=category), ] def get_model_url(self, object, kind): return derive_model_url(Manufacturer, "shoop_admin:manufacturers", object, kind)
class CategoryModule(AdminModule): name = _("Products") category = name breadcrumbs_menu_entry = MenuEntry(text=name, url="shoop_admin:category.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^categories", view_template="shoop.admin.modules.categories.views.Category%sView", name_template="category.%s") def get_menu_entries(self, request): return [ MenuEntry(text=_("Categories"), icon="fa fa-sitemap", url="shoop_admin:category.list", category=self.category) ] def get_search_results(self, request, query): minimum_query_length = 3 if len(query) >= minimum_query_length: categories = Category.objects.filter( Q(translations__name__icontains=query) | Q(identifier__icontains=query)).distinct().order_by( "tree_id", "lft") for i, category in enumerate(categories[:10]): relevance = 100 - i yield SearchResult(text=six.text_type(category), url=get_model_url(category), category=self.category, relevance=relevance) def get_model_url(self, object, kind): return derive_model_url(Category, "shoop_admin:category", object, kind)
class TaxRulesAdminModule(AdminModule): name = _("Tax Rules") category = _("Taxes") breadcrumbs_menu_entry = MenuEntry( name, "shoop_admin:default_tax.tax_rule.list") def get_urls(self): return get_edit_and_list_urls( url_prefix="^default-tax/rules", view_template="shoop.default_tax.admin_module.views.TaxRule%sView", name_template="default_tax.tax_rule.%s") def get_menu_entries(self, request): return [ MenuEntry(text=_("Tax Rules"), icon="fa fa-file-text", url="shoop_admin:default_tax.tax_rule.list", category=self.category, aliases=[_("Show tax rules")]) ] def get_model_url(self, object, kind): return derive_model_url(TaxRule, "shoop_admin:default_tax.tax_rule", object, kind)
class TaxModule(AdminModule): name = _("Taxes") category = name breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:tax_class.list") def get_urls(self): return [ # TODO: Add url for tax dashboard? # urls for Tax admin_url("^taxes/tax/(?P<pk>\d+)/$", "shoop.admin.modules.taxes.views.edit.TaxEditView", name="tax.edit"), admin_url("^taxes/tax/new/$", "shoop.admin.modules.taxes.views.edit.TaxEditView", kwargs={"pk": None}, name="tax.new"), admin_url("^taxes/tax/$", "shoop.admin.modules.taxes.views.list.TaxListView", name="tax.list"), # urls for CustomerTaxGroup admin_url( "^taxes/customer-tax-group/(?P<pk>\d+)/$", "shoop.admin.modules.taxes.views.edit.CustomerTaxGroupEditView", name="customer_tax_group.edit"), admin_url( "^taxes/customer-tax-group/new/$", "shoop.admin.modules.taxes.views.edit.CustomerTaxGroupEditView", kwargs={"pk": None}, name="customer_tax_group.new"), admin_url( "^taxes/customer-tax-group/$", "shoop.admin.modules.taxes.views.list.CustomerTaxGroupListView", name="customer_tax_group.list"), # urls for TaxClass admin_url("^taxes/tax-class/(?P<pk>\d+)/$", "shoop.admin.modules.taxes.views.edit.TaxClassEditView", name="tax_class.edit"), admin_url("^taxes/tax-class/new/$", "shoop.admin.modules.taxes.views.edit.TaxClassEditView", kwargs={"pk": None}, name="tax_class.new"), admin_url("^taxes/tax-class/$", "shoop.admin.modules.taxes.views.list.TaxClassListView", name="tax_class.list"), ] def get_menu_category_icons(self): return {self.category: "fa fa-pie-chart"} def get_menu_entries(self, request): return [ MenuEntry(text=_("List Taxes"), icon="fa fa-list", url="shoop_admin:tax.list", category=self.category), MenuEntry(text=_("List Customer Tax Groups"), icon="fa fa-list", url="shoop_admin:customer_tax_group.list", category=self.category), MenuEntry(text=_("List Tax Classes"), icon="fa fa-list", url="shoop_admin:tax_class.list", category=self.category) ] def get_model_url(self, object, kind): return (derive_model_url(Tax, "shoop_admin:tax", object, kind) or derive_model_url(TaxClass, "shoop_admin:tax_class", object, kind) or derive_model_url(CustomerTaxGroup, "shoop_admin:customer_tax_group", object, kind))
class OrderModule(AdminModule): name = _("Orders") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:order.list") def get_urls(self): return [ admin_url( "^orders/(?P<pk>\d+)/create-shipment/$", "shoop.admin.modules.orders.views.OrderCreateShipmentView", name="order.create-shipment"), admin_url("^orders/(?P<pk>\d+)/set-status/$", "shoop.admin.modules.orders.views.OrderSetStatusView", name="order.set-status"), admin_url("^orders/(?P<pk>\d+)/$", "shoop.admin.modules.orders.views.OrderDetailView", name="order.detail"), admin_url("^orders/$", "shoop.admin.modules.orders.views.OrderListView", name="order.list"), ] def get_menu_category_icons(self): return {self.name: "fa fa-inbox"} def get_menu_entries(self, request): category = _("Orders") return [ MenuEntry(text=_("Orders"), icon="fa fa-inbox", url="shoop_admin:order.list", category=category, aliases=[_("Show orders")]), ] def get_search_results(self, request, query): minimum_query_length = 3 if len(query) >= minimum_query_length: orders = Order.objects.filter( Q(identifier__istartswith=query) | Q(reference_number__istartswith=query) | Q(email__icontains=query) | Q(phone__icontains=query)).order_by("-id")[:15] for i, order in enumerate(orders): relevance = 100 - i yield SearchResult(text=six.text_type(order), url=get_model_url(order), category=_("Orders"), relevance=relevance) def get_dashboard_blocks(self, request): import shoop.admin.modules.orders.dashboard as dashboard yield dashboard.get_sales_of_the_day_block(request) yield dashboard.get_lifetime_sales_block(request) yield dashboard.get_avg_purchase_size_block(request) yield dashboard.get_open_orders_block(request) yield dashboard.get_order_value_chart_dashboard_block(request) def get_notifications(self, request): old_open_orders = Order.objects.filter( status__role=OrderStatusRole.INITIAL, order_date__lt=now() - timedelta(days=4)).count() if old_open_orders: yield Notification(title=_("Outstanding Orders"), text=_("%d outstanding orders") % old_open_orders, kind="danger") def get_model_url(self, object, kind): return derive_model_url(Order, "shoop_admin:order", object, kind)
class NotifyAdminModule(AdminModule): name = _(u"Notifications") breadcrumbs_menu_entry = MenuEntry(name, "shoop_admin:notify.script.list") def get_urls(self): return [ admin_url("notify/script-item-editor/", "shoop.notify.admin_module.views.script_item_editor", name="notify.script-item-editor"), admin_url("notify/script/content/(?P<pk>\d+)/", "shoop.notify.admin_module.views.EditScriptContentView", name="notify.script.edit-content"), admin_url("notify/mark-read/(?P<pk>\d+)/$", self.mark_notification_read_view, name="notify.mark-read"), ] + get_edit_and_list_urls( url_prefix="^notify/script", view_template="shoop.notify.admin_module.views.Script%sView", name_template="notify.script.%s") def get_menu_category_icons(self): return {self.name: "fa fa-envelope-o"} def get_menu_entries(self, request): category = _("Notifications") return [ MenuEntry(text=_("Notification scripts"), icon="fa fa-code", url="shoop_admin:notify.script.list", category=category, aliases=[_("Show notification scripts")]) ] @csrf_exempt def mark_notification_read_view(self, request, pk): if request.method == "POST": try: notif = NotificationModel.objects.for_user( request.user).get(pk=pk) except ObjectDoesNotExist: return JsonResponse({"error": "no such notification"}) notif.mark_read(request.user) return JsonResponse({"ok": True}) return JsonResponse({"error": "POST only"}) def get_notifications(self, request): notif_qs = NotificationModel.objects.unread_for_user( request.user).order_by("-id")[:15] for notif in notif_qs: if notif.priority == Priority.HIGH: kind = "warning" elif notif.priority == Priority.CRITICAL: kind = "danger" else: kind = "info" yield Notification(text=notif.message, url=notif.url, kind=kind, dismissal_url=reverse( "shoop_admin:notify.mark-read", kwargs={"pk": notif.pk}), datetime=notif.created_on) def get_model_url(self, object, kind): return derive_model_url(Script, "shoop_admin:notify.script", object, kind)
def get_breadcrumb_parents(self): return [ MenuEntry(text=force_text( self.model._meta.verbose_name_plural).title(), url="shoop_admin:service_provider.list") ]
def get_breadcrumb_parents(self): return [MenuEntry(text=self.parent_name, url=self.parent_url)]
def get_breadcrumb_parents(self): return [ MenuEntry(text="%s" % self.object, url=get_model_url(self.object)) ]
def infer(cls, context): """ Infer breadcrumbs from the rendering context. :param context: Jinja Context :type context: jinja2.runtime.Context :return: Breadcrumbs object or None if things fail :rtype: Breadcrumbs|None """ request = context["request"] if not getattr(request, "resolver_match", None): # If we don't have a resolver match, we can't infer anything. return None url_names = ( request.resolver_match.url_name, "%s:%s" % (request.resolver_match.app_name, request.resolver_match.url_name) ) url_admin_module = _get_admin_module_for_url(url_names) # Synthesize a menu entry for the current view. current_view_entry = MenuEntry(url=request.path, text="") if url_admin_module: # See if we have an idea for the title of this view from the menu entries for entry in url_admin_module.get_menu_entries(request): if entry.original_url in url_names: current_view_entry.text = entry.text break # See if we have a title for the synthesized entry in the context. view = context.get("view") # This should be the CBV view object. title = ( context.get("title") or context.get("breadcrumb_title") or (view and getattr(view, "title", None)) ) if title: current_view_entry.text = force_text(title) # Begin building the entries... entries = [] # See if we have the top level menu entry ("Contacts" for example). if url_admin_module and url_admin_module.breadcrumbs_menu_entry: # (But don't duplicate steps) if url_admin_module.breadcrumbs_menu_entry.url != request.path or not current_view_entry.text: entries.append(url_admin_module.breadcrumbs_menu_entry) # See if the view declares parents... parent_getter = getattr(view, "get_breadcrumb_parents", None) if parent_getter: entries.extend(parent_getter() or ()) # If the current entry seems valid (would be visible), then go for it! if current_view_entry.text: entries.append(current_view_entry) return cls(entries)
class UserModule(AdminModule): name = _("Users") category = _("Contacts") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:user.list") def get_urls(self): return [ admin_url( "^users/(?P<pk>\d+)/change-password/$", "shoop.admin.modules.users.views.UserChangePasswordView", name="user.change-password" ), admin_url( "^users/(?P<pk>\d+)/reset-password/$", "shoop.admin.modules.users.views.UserResetPasswordView", name="user.reset-password" ), admin_url( "^users/(?P<pk>\d+)/change-permissions/$", "shoop.admin.modules.users.views.UserChangePermissionsView", name="user.change-permissions" ), admin_url( "^users/(?P<pk>\d+)/$", "shoop.admin.modules.users.views.UserDetailView", name="user.detail" ), admin_url( "^users/new/$", "shoop.admin.modules.users.views.UserDetailView", kwargs={"pk": None}, name="user.new" ), admin_url( "^users/$", "shoop.admin.modules.users.views.UserListView", name="user.list" ), ] def get_menu_category_icons(self): return {self.category: "fa fa-users"} def get_menu_entries(self, request): return [ MenuEntry( text=_("Users"), icon="fa fa-users", url="shoop_admin:user.list", category=self.category ) ] def get_search_results(self, request, query): minimum_query_length = 3 if len(query) >= minimum_query_length: users = get_user_model().objects.filter( Q(username__icontains=query) | Q(email=query) ) for i, user in enumerate(users[:10]): relevance = 100 - i yield SearchResult( text=six.text_type(user), url=get_model_url(user), category=self.category, relevance=relevance ) def get_model_url(self, object, kind): return derive_model_url(get_user_model(), "shoop_admin:user", object, kind)
def get_breadcrumb_parents(self): return [ MenuEntry(text=force_text( self.model._meta.verbose_name_plural).title(), url="shoop_admin:%s.list" % self.action_url_name_prefix) ]
class ProductModule(AdminModule): name = _("Products") breadcrumbs_menu_entry = MenuEntry(name, url="shoop_admin:product.list") def get_urls(self): return [ admin_url( "^products/(?P<pk>\d+)/delete/$", "shoop.admin.modules.products.views.ProductDeleteView", name="product.delete" ), admin_url( "^products/(?P<pk>\d+)/media/$", "shoop.admin.modules.products.views.ProductMediaEditView", name="product.edit_media" ), admin_url( "^products/(?P<pk>\d+)/crosssell/$", "shoop.admin.modules.products.views.ProductCrossSellEditView", name="product.edit_cross_sell" ), admin_url( "^products/(?P<pk>\d+)/variation/$", "shoop.admin.modules.products.views.ProductVariationView", name="product.edit_variation" ), ] + get_edit_and_list_urls( url_prefix="^products", view_template="shoop.admin.modules.products.views.Product%sView", name_template="product.%s" ) def get_menu_category_icons(self): return {self.name: "fa fa-cube"} def get_menu_entries(self, request): category = _("Products") return [ MenuEntry( text=_("Products"), icon="fa fa-cube", url="shoop_admin:product.list", category=category ) ] def get_search_results(self, request, query): minimum_query_length = 3 skus_seen = set() if len(query) >= minimum_query_length: pk_counter = Counter() pk_counter.update(Product.objects.filter(sku__startswith=query).values_list("pk", flat=True)) name_q = Q() for part in split_query(query, minimum_query_length): name_q &= Q(name__icontains=part) pk_counter.update( Product._parler_meta.root_model.objects.filter(name_q).values_list("master_id", flat=True) ) pks = [pk for (pk, count) in pk_counter.most_common(10)] for product in Product.objects.filter(pk__in=pks): relevance = 100 - pk_counter.get(product.pk, 0) skus_seen.add(product.sku.lower()) yield SearchResult( text=force_text(product), url=get_model_url(product), category=_("Products"), relevance=relevance ) if len(query) >= minimum_query_length: url = reverse("shoop_admin:product.new") if " " in query: yield SearchResult( text=_("Create Product Called \"%s\"") % query, url=manipulate_query_string(url, name=query), is_action=True ) else: if query.lower() not in skus_seen: yield SearchResult( text=_("Create Product with SKU \"%s\"") % query, url=manipulate_query_string(url, sku=query), is_action=True ) def get_model_url(self, object, kind): return derive_model_url(Product, "shoop_admin:product", object, kind)
def get_menu_entries(self, request): return [MenuEntry(text="OK", url="/OK", category="Test", aliases=("spooky",))]