def get_form_parts(self, object): form_parts = super(ServiceEditView, self).get_form_parts(object) if not object.pk: return form_parts for form in get_provide_objects(self.form_provide_key): form_parts.append(self._get_behavior_form_part(form, object)) for form_class in get_provide_objects(self.form_part_provide_key): form_parts.append(form_class(self.request, object)) return form_parts
def get_form_parts(self, object): form_parts = super(CampaignEditView, self).get_form_parts(object) if not object.pk: return form_parts for form in get_provide_objects(self.condition_key): form_parts.append(self._get_rules_form_part(form, object)) for form in get_provide_objects(self.effect_key): form_parts.append(self._get_effects_form_part(form, object)) return form_parts
def get_context_data(self, **kwargs): context = super(ThemeConfigView, self).get_context_data(**kwargs) context["theme_classes"] = sorted( [t for t in get_provide_objects("xtheme") if t.identifier], key=lambda t: (t.name or t.identifier)) context["current_theme"] = get_current_theme() return context
def form_valid(self, form): product_ids_to_quantities = dict( (int(key.replace("q_", "")), value) for (key, value) in six.iteritems(form.cleaned_data) if key.startswith("q_") and value > 0) order = self.object product_map = Product.objects.in_bulk( set(product_ids_to_quantities.keys())) products_to_quantities = dict( (product_map[product_id], quantity) for (product_id, quantity) in six.iteritems(product_ids_to_quantities)) unsaved_shipment = Shipment(order=order, supplier=form.cleaned_data["supplier"]) for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): extend_class().form_valid_hook(form, unsaved_shipment) try: shipment = order.create_shipment( product_quantities=products_to_quantities, shipment=unsaved_shipment) except NoProductsToShipException: messages.error(self.request, _("No products to ship.")) return self.form_invalid(form) else: messages.success(self.request, _("Shipment %s created.") % shipment.id) return HttpResponseRedirect(get_model_url(order))
def _postprocess(self, context, content): for inject_func in get_provide_objects("xtheme_resource_injection"): if callable(inject_func): inject_func(context, content) add_edit_resources(context) content = inject_resources(context, content) return content
def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") super(CampaignFormMixin, self).__init__(*args, **kwargs) for provide_key in self.provide_keys: for cls in sorted(get_provide_objects(provide_key), key=lambda x: x.name): obj = cls() if obj.identifier in self.fields: continue for field in obj._meta.get_fields(include_parents=False): if isinstance(field, OneToOneField): continue self.rule_ids.add(obj.identifier) kwargs = { "initial": self._get_initial_value(obj), "required": False, # rules are not required by default, validation is made later on "help_text": obj.description } if isinstance(field, ManyToManyField): kwargs.update({ "widget": Select2Multiple(model=obj.model) }) formfield = forms.CharField(**kwargs) value = kwargs.get("initial") if value: formfield.widget.choices = [ (object.pk, force_text(object)) for object in obj.model.objects.filter(pk__in=value)] else: formfield = field.formfield(**kwargs) self.fields[obj.identifier] = formfield
def get_form(self, form_class=None): form_classes = list(get_provide_objects(self.form_provide_key)) form_infos = _FormInfoMap(form_classes) if self.object and self.object.pk: return self._get_concrete_form(form_infos) else: return self._get_type_choice_form(form_infos)
def get_toolbar(self): order = self.object toolbar = Toolbar() toolbar.append(URLActionButton( text=_("Create Shipment"), icon="fa fa-truck", disable_reason=_("There are no products to ship") if not order.get_unshipped_products() else None, url=reverse("shoop_admin:order.create-shipment", kwargs={"pk": order.pk}), extra_css_class="btn-info" )) toolbar.append(PostActionButton( post_url=reverse("shoop_admin:order.set-status", kwargs={"pk": order.pk}), name="status", value=OrderStatus.objects.get_default_complete().pk, text=_("Set Complete"), icon="fa fa-check-circle", disable_reason=( _("This order can not be set as complete at this point") if not order.can_set_complete() else None ), extra_css_class="btn-success" )) for button in get_provide_objects("admin_order_toolbar_button"): toolbar.append(button(order)) return toolbar
def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") super(CampaignFormMixin, self).__init__(*args, **kwargs) for provide_key in self.provide_keys: for cls in sorted(get_provide_objects(provide_key), key=lambda x: x.name): obj = cls() if obj.identifier in self.fields: continue for field in obj._meta.get_fields(include_parents=False): if isinstance(field, OneToOneField): continue self.rule_ids.add(obj.identifier) kwargs = { "required": False, # rules are not required by default, validation is made later on "help_text": obj.description } if isinstance(field, ManyToManyField): kwargs.update({ "initial": self._get_many_to_many_initial_values(obj), "widget": Select2Multiple(model=obj.model) }) formfield = forms.CharField(**kwargs) value = kwargs.get("initial") if value: formfield.widget.choices = [ (object.pk, force_text(object)) for object in obj.model.objects.filter(pk__in=value)] else: kwargs.update({ "initial": self.get_initial_value(obj.identifier) }) formfield = field.formfield(**kwargs) self.fields[obj.identifier] = formfield
def get_context_data(self, **kwargs): context = super(ThemeConfigView, self).get_context_data(**kwargs) context["theme_classes"] = sorted( [t for t in get_provide_objects("xtheme") if t.identifier], key=lambda t: (t.name or t.identifier) ) context["current_theme"] = get_current_theme() return context
def get_form_parts(self, object): form_parts = super(CatalogCampaignEditView, self).get_form_parts(object) if not object.pk: return form_parts for form in get_provide_objects(self.filter_key): form_parts.append(self._get_filters_form_part(form, object)) return form_parts
def get_module_choices(cls, empty_label=None): if empty_label is None: empty_label = _("No Choice") choices = [("", empty_label)] for module in get_provide_objects(cls.module_provides_key): if module.identifier: choices.append((module.identifier, getattr(module, "name", None) or module.identifier)) choices.sort() return choices
def test_provides(): IDENTIFIED_OBJECT_SPEC = "%s:IdentifiedObject" % __name__ category = str(uuid.uuid4()) with override_provides(category, [ IDENTIFIED_OBJECT_SPEC, "%s:UnidentifiedObject" % __name__, "%s:VeryUnidentifiedObject" % __name__, ]): objects = get_provide_objects(category) assert set(objects) == set((IdentifiedObject, UnidentifiedObject, VeryUnidentifiedObject)) assert get_identifier_to_object_map(category)["identifier"] == IdentifiedObject assert get_identifier_to_spec_map(category)["identifier"] == IDENTIFIED_OBJECT_SPEC assert get_provide_specs_and_objects(category)[IDENTIFIED_OBJECT_SPEC] == IdentifiedObject # Test the context manager clears things correctly assert empty_iterable(get_provide_objects(category)) assert empty_iterable(get_provide_specs_and_objects(category)) assert empty_iterable(get_identifier_to_object_map(category)) assert empty_iterable(get_identifier_to_spec_map(category))
def get_module_choices(cls, empty_label=None): if empty_label is None: empty_label = _('No Choice') choices = [("", empty_label)] for module in get_provide_objects(cls.module_provides_key): if module.identifier: choices.append( (module.identifier, getattr(module, "name", None) or module.identifier)) choices.sort() return choices
def _save_effects(self, effect_key, instance): for cls in get_provide_objects(effect_key): if not self.cleaned_data[cls.identifier]: continue field_value = self.cleaned_data[cls.identifier] effect = cls.objects.create(campaign=instance) if effect.model: effect.values = effect.model.objects.filter(pk__in=ast.literal_eval(field_value)) else: effect.value = field_value effect.campaign = instance effect.save()
def _save_effects(self, effect_key, instance): for cls in get_provide_objects(effect_key): if not self.cleaned_data[cls.identifier]: continue field_value = self.cleaned_data[cls.identifier] effect = cls.objects.create(campaign=instance) if effect.model: effect.values = effect.model.objects.filter( pk__in=ast.literal_eval(field_value)) else: effect.value = field_value effect.campaign = instance effect.save()
def _get_helpers(): helpers = HelpersNamespace() from shoop.front.template_helpers import general, product, category, urls helpers.general = general helpers.product = product helpers.category = category helpers.urls = urls for namespace in get_provide_objects("front_template_helper_namespace"): if namespace and getattr(namespace, "name", None): if callable(namespace): # If it's a class, instantiate it namespace = namespace() setattr(helpers, namespace.name, namespace) return helpers
def get_theme_by_identifier(identifier, settings_obj=None): """ Get an instantiated theme by identifier. :param identifier: Theme identifier :type identifier: str :param settings_obj: Optional ThemeSettings object for the theme constructor :type settings_obj: shoop.xtheme.models.ThemeSettings :return: Theme object or None :rtype: Theme """ for theme_cls in get_provide_objects("xtheme"): if theme_cls.identifier == identifier: return theme_cls(settings_obj=settings_obj) return None # No such thing.
def get_context_data(self, **kwargs): context = super(OrderDetailView, self).get_context_data(**kwargs) context["toolbar"] = self.get_toolbar() context["title"] = force_text(self.object) context["order_sections"] = [] order_sections_provides = sorted(get_provide_objects("admin_order_section"), key=lambda x: x.order) for admin_order_section in order_sections_provides: # Check whether the OrderSection should be visible for the current object if admin_order_section.visible_for_order(self.object): context["order_sections"].append(admin_order_section) # add additional context data where the key is the order_section identifier context[admin_order_section.identifier] = admin_order_section.get_context_data(self.object) return context
def _save_conditions_and_filters(self, provide_key, instance): for cls in get_provide_objects(provide_key): if not self.cleaned_data[cls.identifier]: continue field_value = self.cleaned_data[cls.identifier] rule = cls.objects.create() if rule.model: rule.values = rule.model.objects.filter(pk__in=ast.literal_eval(field_value)) else: rule.value = field_value rule.save() if "condition" in cls.identifier: # a bit weak but to rely this instance.conditions.add(rule) else: instance.filters.add(rule)
def get_checkout_phases_for_service(checkout_process, service): """ Get checkout phases for given service. :type checkout_process: shoop.front.checkout.CheckoutProcess :type service: shoop.core.models.Service :rtype: Iterable[shoop.front.checkout.CheckoutPhaseViewMixin] """ classes = get_provide_objects("front_service_checkout_phase_provider") for provider_cls in classes: provider = provider_cls() assert isinstance(provider, ServiceCheckoutPhaseProvider) phase = provider.get_checkout_phase(checkout_process, service) if phase: assert isinstance(phase, CheckoutPhaseViewMixin) yield phase
def _save_conditions_and_filters(self, provide_key, instance): for cls in get_provide_objects(provide_key): if not self.cleaned_data[cls.identifier]: continue field_value = self.cleaned_data[cls.identifier] rule = cls.objects.create() if rule.model: rule.values = rule.model.objects.filter( pk__in=ast.literal_eval(field_value)) else: rule.value = field_value rule.save() if "condition" in cls.identifier: # a bit weak but to rely this instance.conditions.add(rule) else: instance.filters.add(rule)
def _add_fields(self, provide_key, is_provide=True): for cls in sorted(get_provide_objects(provide_key), key=lambda x: x.name): obj = cls() if obj.identifier in self.fields: continue for field in obj._meta.get_fields(include_parents=False): if isinstance(field, OneToOneField): continue if is_provide: self.rule_ids.add(obj.identifier) else: self.effect_ids.add(obj.identifier) kwargs = { "required": False, # rules are not required by default, validation is made later on "help_text": obj.description } if hasattr(obj, "admin_form_class") and obj.admin_form_class: kwargs.update({"form_class": obj.admin_form_class}) if isinstance(field, ManyToManyField): kwargs.update({ "initial": self._get_many_to_many_initial_values(obj), "widget": Select2Multiple(model=obj.model) }) formfield = forms.CharField(**kwargs) value = kwargs.get("initial") if value: formfield.widget.choices = [ (object.pk, force_text(object)) for object in obj.model.objects.filter( pk__in=value) ] else: kwargs.update( {"initial": self.get_initial_value(obj.identifier)}) formfield = field.formfield(**kwargs) self.fields[obj.identifier] = formfield
def test_theme_selection(): """ Test that a theme with a `template_dir` actually affects template directory selection. """ with override_current_theme_class(), override_provides("xtheme", [ "shoop_tests.xtheme.utils:FauxTheme", "shoop_tests.xtheme.utils:FauxTheme2", "shoop_tests.xtheme.utils:H2G2Theme", ]): ThemeSettings.objects.all().delete() for theme in get_provide_objects("xtheme"): set_current_theme(theme.identifier) je = get_jinja2_engine() wrapper = (noop() if theme.identifier == "h2g2" else pytest.raises(TemplateDoesNotExist)) with wrapper: t = je.get_template("42.jinja") content = t.render().strip() assert "a slice of lemon wrapped around a large gold brick" in content.replace("\n", " ")
def _add_fields(self, provide_key, is_provide=True): for cls in sorted(get_provide_objects(provide_key), key=lambda x: x.name): obj = cls() if obj.identifier in self.fields: continue for field in obj._meta.get_fields(include_parents=False): if isinstance(field, OneToOneField): continue if is_provide: self.rule_ids.add(obj.identifier) else: self.effect_ids.add(obj.identifier) kwargs = { "required": False, # rules are not required by default, validation is made later on "help_text": obj.description } if hasattr(obj, "admin_form_class") and obj.admin_form_class: kwargs.update({ "form_class": obj.admin_form_class }) if isinstance(field, ManyToManyField): kwargs.update({ "initial": self._get_many_to_many_initial_values(obj), "widget": Select2Multiple(model=obj.model) }) formfield = forms.CharField(**kwargs) value = kwargs.get("initial") if value: formfield.widget.choices = [ (object.pk, force_text(object)) for object in obj.model.objects.filter(pk__in=value)] else: kwargs.update({ "initial": self.get_initial_value(obj.identifier) }) formfield = field.formfield(**kwargs) self.fields[obj.identifier] = formfield
def clean(self): data = super(CampaignFormMixin, self).clean() # Ensure at least 1 effect is set effect_count = 0 for key in self.effect_keys: for cls in get_provide_objects(key): if data[cls.identifier]: effect_count += 1 if effect_count > 1: raise ValidationError(_("You should only define one effect.")) if not effect_count: raise ValidationError(_("At least one effect must be defined.")) start_datetime = data.get("start_datetime") end_datetime = data.get("end_datetime") if start_datetime and end_datetime and end_datetime < start_datetime: raise ValidationError(_("Campaign end date can't be before start date."), code="end_is_before_start") return data
def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") super(CampaignFormMixin, self).__init__(*args, **kwargs) for provide_key in self.provide_keys: for cls in sorted(get_provide_objects(provide_key), key=lambda x: x.name): obj = cls() if obj.identifier in self.fields: continue for field in obj._meta.get_fields(include_parents=False): if isinstance(field, OneToOneField): continue kwargs = { "initial": self.get_initial_value(obj.identifier), "required": False, # rules are not required by default, validation is made later on "help_text": obj.description } self.rule_ids.add(obj.identifier) self.fields[obj.identifier] = field.formfield(**kwargs)
def get_form(self, form_class): default_field_keys = set() form = super(OrderCreateShipmentView, self).get_form(form_class) order = self.object form.fields["supplier"] = forms.ModelChoiceField( queryset=Supplier.objects.all(), initial=Supplier.objects.first(), label=_("Supplier")) default_field_keys.add("supplier") form.product_summary = order.get_product_summary() form.product_names = dict( (product_id, text) for (product_id, text) in order.lines.exclude( product=None).values_list("product_id", "text")) for product_id, info in sorted(six.iteritems(form.product_summary)): product_name = form.product_names.get(product_id, "Product %s" % product_id) unshipped_count = info["unshipped"] attrs = { "data-max": unshipped_count, "class": "form-control text-right", } if unshipped_count == 0: attrs["disabled"] = "disabled" field = forms.DecimalField(required=bool(unshipped_count != 0), min_value=0, max_value=unshipped_count, initial=0, label=product_name, widget=forms.TextInput(attrs=attrs)) field_key = "q_%s" % product_id form.fields[field_key] = field default_field_keys.add(field_key) for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): for field_key, field in extend_class().get_extra_fields( order) or []: form.fields[field_key] = field form.default_field_keys = default_field_keys return form
def save(self, commit=True): instance = super(CampaignFormMixin, self).save(commit) if self.cleaned_data.get("coupon"): instance.coupon = Coupon.objects.get( pk=self.cleaned_data.get("coupon")) if hasattr(instance, "conditions"): instance.conditions.clear() if hasattr(instance, "filters"): instance.filters.clear() instance.save() for provide_key in self.provide_keys: for cls in get_provide_objects(provide_key): if not self.cleaned_data[cls.identifier]: continue field_value = self.cleaned_data[cls.identifier] rule = cls.objects.create() if rule.model: rule.values = rule.model.objects.filter( pk__in=ast.literal_eval(field_value)) else: rule.value = field_value rule.save() if "condition" in cls.identifier: # a bit weak but to rely this instance.conditions.add(rule) else: instance.filters.add(rule) instance.save() if not instance.created_by: instance.created_by = self.request.user instance.modified_by = self.request.user instance.save() return instance
def get_plugin_choices(cls, empty_label=None): """ Get a sorted list of 2-tuples (identifier and name) of available Xtheme plugins. Handy for `<select>` boxen. :param empty_label: Label for the "empty" choice. If falsy, no empty choice is prepended :type empty_label: str|None :return: List of 2-tuples :rtype: Iterable[tuple[str, str]] """ choices = [] if empty_label: choices.append(("", empty_label)) for plugin in get_provide_objects("xtheme_plugin"): if plugin.identifier: choices.append( (plugin.identifier, getattr(plugin, "name", None) or plugin.identifier)) choices.sort() return choices
def save(self, commit=True): instance = super(CampaignFormMixin, self).save(commit) if self.cleaned_data.get("coupon"): instance.coupon = Coupon.objects.get(pk=self.cleaned_data.get("coupon")) if hasattr(instance, "conditions"): instance.conditions.clear() if hasattr(instance, "filters"): instance.filters.clear() instance.save() for provide_key in self.provide_keys: for cls in get_provide_objects(provide_key): if not self.cleaned_data[cls.identifier]: continue field_value = self.cleaned_data[cls.identifier] rule = cls.objects.create() if rule.model: rule.values = rule.model.objects.filter(pk__in=field_value) else: rule.value = field_value rule.save() if "condition" in cls.identifier: # a bit weak but to rely this instance.conditions.add(rule) else: instance.filters.add(rule) instance.save() if not instance.created_by: instance.created_by = self.request.user instance.modified_by = self.request.user instance.save() return instance
def form_valid(self, form): product_ids_to_quantities = dict( (int(key.replace("q_", "")), value) for (key, value) in six.iteritems(form.cleaned_data) if key.startswith("q_") and value > 0 ) order = self.object product_map = Product.objects.in_bulk(set(product_ids_to_quantities.keys())) products_to_quantities = dict( (product_map[product_id], quantity) for (product_id, quantity) in six.iteritems(product_ids_to_quantities) ) unsaved_shipment = Shipment(order=order, supplier=form.cleaned_data["supplier"]) for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): extend_class().form_valid_hook(form, unsaved_shipment) try: shipment = order.create_shipment(product_quantities=products_to_quantities, shipment=unsaved_shipment) except NoProductsToShipException: messages.error(self.request, _("No products to ship.")) return self.form_invalid(form) else: messages.success(self.request, _("Shipment %s created.") % shipment.id) return HttpResponseRedirect(get_model_url(order))
def get_plugin_choices(cls, empty_label=None): """ Get a sorted list of 2-tuples (identifier and name) of available Xtheme plugins. Handy for `<select>` boxen. :param empty_label: Label for the "empty" choice. If falsy, no empty choice is prepended :type empty_label: str|None :return: List of 2-tuples :rtype: Iterable[tuple[str, str]] """ choices = [] if empty_label: choices.append(("", empty_label)) for plugin in get_provide_objects("xtheme_plugin"): if plugin.identifier: choices.append(( plugin.identifier, getattr(plugin, "name", None) or plugin.identifier )) choices.sort() return choices
def get_form(self, form_class): default_field_keys = set() form = super(OrderCreateShipmentView, self).get_form(form_class) order = self.object form.fields["supplier"] = forms.ModelChoiceField( queryset=Supplier.objects.all(), initial=Supplier.objects.first(), label=_("Supplier") ) default_field_keys.add("supplier") form.product_summary = order.get_product_summary() form.product_names = dict( (product_id, text) for (product_id, text) in order.lines.exclude(product=None).values_list("product_id", "text") ) for product_id, info in sorted(six.iteritems(form.product_summary)): product_name = form.product_names.get(product_id, "Product %s" % product_id) unshipped_count = info["unshipped"] attrs = {"data-max": unshipped_count, "class": "form-control text-right"} if unshipped_count == 0: attrs["disabled"] = "disabled" field = forms.DecimalField( required=bool(unshipped_count != 0), min_value=0, max_value=unshipped_count, initial=0, label=product_name, widget=forms.TextInput(attrs=attrs), ) field_key = "q_%s" % product_id form.fields[field_key] = field default_field_keys.add(field_key) for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): for field_key, field in extend_class().get_extra_fields(order) or []: form.fields[field_key] = field form.default_field_keys = default_field_keys return form
def clean(self): data = super(CampaignFormMixin, self).clean() # Ensure at least 1 effect is set effect_count = 0 for key in self.effect_keys: for cls in get_provide_objects(key): if data[cls.identifier]: effect_count += 1 if effect_count > 1: raise ValidationError( _("You should only define one effect.")) if not effect_count: raise ValidationError(_("At least one effect must be defined.")) start_datetime = data.get("start_datetime") end_datetime = data.get("end_datetime") if start_datetime and end_datetime and end_datetime < start_datetime: raise ValidationError( _("Campaign end date can't be before start date."), code="end_is_before_start") return data
def get_form_part_classes(self): form_part_classes = ( list(self.base_form_part_classes) + list(get_provide_objects(self.form_part_class_provide_key)) ) return form_part_classes
def get_name_map(category_key): return sorted( [(force_text(obj.identifier), force_text(obj.name)) for obj in get_provide_objects(category_key) if obj.identifier], key=lambda t: t[1].lower())
def populate(self): for func in get_provide_objects("api_populator"): func(router=self)
def discover(): for obj in get_provide_objects("admin_module"): register(obj)
def clean(self): cleaned_data = super(ShipmentForm, self).clean() for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): extend_class().clean_hook(self) return cleaned_data
def _get_extension_urlpatterns(provide_category): return chain(*get_provide_objects(provide_category))
def get_form_part_classes(self): form_part_classes = ( list(self.base_form_part_classes) + list(get_provide_objects(self.form_part_class_provide_key))) return form_part_classes
def get_name_map(category_key): return sorted([ (force_text(obj.identifier), force_text(obj.name)) for obj in get_provide_objects(category_key) if obj.identifier ], key=lambda t: t[1].lower())