def test_view_default_columns(rf, admin_user): shop = get_default_shop() view = ProductListView.as_view() request = apply_request_middleware(rf.get("/", { "jq": json.dumps({"perPage": 100, "page": 1}) }), user=admin_user) response = view(request) assert 200 <= response.status_code < 300 listview = ProductListView() assert listview.settings.default_columns == listview.default_columns column_names = [c.id for c in sorted(listview.columns, key=lambda x: x.id)] default_column_names = [c.id for c in sorted(listview.default_columns, key=lambda x: x.id)] assert column_names == default_column_names assert configuration.get(None, "view_configuration_shopproduct_name") # name is configured assert listview.settings.view_configured() assert listview.settings.get_settings_key("name") == "view_configuration_shopproduct_name" # we are attached to product view settings_view = ListSettingsView.as_view() view_data = {"model": "ShopProduct", "module": "wshop.core.models", "return_url": "shop_product"} request = rf.get("/", view_data) response = settings_view(request) assert 200 <= response.status_code < 300 # Change configuration by posting form request = rf.post("/?" + urlencode(view_data), {"view_configuration_shopproduct_name": False}) response = settings_view(request) assert response.status_code == 302 assert listview.settings.get_config("name") == configuration.get(None, "view_configuration_shopproduct_name") assert not configuration.get(None, "view_configuration_shopproduct_name").get("active")
def test_behavior_form(): shop = get_default_shop() assert Script.objects.count() == 0 assert configuration.get(shop, BEHAVIOR_ORDER_CONFIRM_KEY) is None form = BehaviorWizardForm(shop=shop, data={"order_confirm_notification": True}) assert form._get_saved_script() is None form.save() # check if the form creates a order notification correctely script = Script.objects.first() assert script.pk == configuration.get(shop, BEHAVIOR_ORDER_CONFIRM_KEY) assert form._get_saved_script().pk == script.pk assert len(script.get_steps()) == 1 step = script.get_steps()[0] step_data = step.serialize() assert step_data["next"] == StepNext.STOP.value action = step._actions[0] assert isinstance(action, SendEmail) action_data = action.serialize() assert action_data["recipient"]["variable"] == "customer_email" assert action_data["language"]["variable"] == "language" lang = translation.get_language() assert action_data["fallback_language"]["constant"] == lang assert action_data["template_data"][lang]["content_type"] == "html" assert action_data["template_data"][lang]["subject"] == force_text( data.ORDER_CONFIRMATION["subject"]) context = {"shop": shop} content = loader.render_to_string(data.ORDER_CONFIRMATION["body_template"], context).strip() assert action_data["template_data"][lang]["body"] == content # the widget must be disabled form = BehaviorWizardForm(shop=shop, data={"order_confirm_notification": True}) assert form.fields["order_confirm_notification"].widget.attrs[ "disabled"] is True # clear scripts Script.objects.all().delete() configuration.set(shop, BEHAVIOR_ORDER_CONFIRM_KEY, None) # save the form but do not create the order confirmation notification form = BehaviorWizardForm(shop=shop, data={"order_confirm_notification": False}) form.save() # nothing created assert Script.objects.count() == 0 assert configuration.get(shop, BEHAVIOR_ORDER_CONFIRM_KEY) is None
def is_valid(self): shipping_required = configuration.get( self.request.shop, SHIPPING_METHOD_REQUIRED_CONFIG_KEY, True) payment_required = configuration.get( self.request.shop, PAYMENT_METHOD_REQUIRED_CONFIG_KEY, True) if shipping_required and not self.storage.get("shipping_method_id"): return False elif payment_required and not self.storage.get("payment_method_id"): return False return self.storage.has_any( ["shipping_method_id", "payment_method_id"])
def test_order_configuration(rf, admin_user): shop = get_default_shop() # clear shop configurations ConfigurationItem.objects.filter(shop=shop).delete() client = SmartClient() client.login(username="******", password="******") url = reverse("wshop_admin:shop.edit", kwargs={"pk": shop.pk}) response, soup = client.response_and_soup(url) assert response.status_code == 200 length_form_field = "order_configuration-%s" % consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD prefix_form_field = "order_configuration-%s" % consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD length_field = soup.find("input", attrs={"id": "id_%s" % length_form_field}) prefix_field = soup.find("input", attrs={"id": "id_%s" % prefix_form_field}) assert length_field assert prefix_field assert length_field["value"] == str( settings.WSHOP_REFERENCE_NUMBER_LENGTH ) # default value because nothing set yet assert "value" not in prefix_field # field empty data = get_base_form_data(shop) data[length_form_field] = "18" data[prefix_form_field] = "123" response, soup = client.response_and_soup(url, data=data, method="post") assert "is required" not in soup.prettify() assert response.status_code == 302 # redirect after success assert configuration.get(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD) == 18 # set global system settings # TODO: Enable this before 1.3 # set_reference_method(rf, admin_user, OrderReferenceNumberMethod.RUNNING) data[length_form_field] = "19" data[prefix_form_field] = "0" client.post(url, data=data) assert configuration.get(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD) == 19 assert not configuration.get(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD ) # None because disabled line 104, else 0
def save(self, commit=True): company = self.forms['company'].save(commit=False) billing_address = self.forms['billing'].save(commit=False) person = self.forms['contact_person'].save(commit=False) user = self.forms['user_account'].save(commit=False) company.default_billing_address = billing_address company.default_shipping_address = billing_address for field in ['name', 'name_ext', 'email', 'phone']: setattr(billing_address, field, getattr(company, field)) person.user = user user.first_name = person.first_name user.last_name = person.last_name user.email = person.email # If company registration requires approval, # company and person contacts will be created as inactive if configuration.get(None, "company_registration_requires_approval"): company.is_active = False person.is_active = False if commit: user.save() person.user = user person.save() billing_address.save() company.default_billing_address = billing_address company.default_shipping_address = billing_address company.save() company.members.add(person) return user
def form_valid(self, form): company = form["contact"].save(commit=False) is_new = not bool(company.pk) company.save() user = self.request.user person = get_person_contact(user) company.members.add(person) billing_address = form["billing"].save() shipping_address = form["shipping"].save() if billing_address.pk != company.default_billing_address_id: # Identity changed due to immutability company.default_billing_address = billing_address if shipping_address.pk != company.default_shipping_address_id: # Identity changed due to immutability company.default_shipping_address = shipping_address message = _("Company information saved successfully.") # If company registration requires activation, # company will be created as inactive. if is_new and configuration.get( None, "company_registration_requires_approval"): company.is_active = False message = _( "Company information saved successfully. " "Please follow the instructions sent to your email address.") company.save() if is_new: user_registered.send(sender=self.__class__, user=self.request.user, request=self.request) CompanyAccountCreated( contact=company, customer_email=company.email).run(shop=self.request.shop) messages.success(self.request, message) return redirect("wshop:company_edit")
def get_running_reference_number(order): from wshop import configuration from wshop.admin.modules.settings.consts import ( ORDER_REFERENCE_NUMBER_PREFIX_FIELD, ORDER_REFERENCE_NUMBER_LENGTH_FIELD) value = Counter.get_and_increment(CounterType.ORDER_REFERENCE) prefix = "%s" % configuration.get(order.shop, ORDER_REFERENCE_NUMBER_PREFIX_FIELD, settings.WSHOP_REFERENCE_NUMBER_PREFIX) ref_length = configuration.get(order.shop, ORDER_REFERENCE_NUMBER_LENGTH_FIELD, settings.WSHOP_REFERENCE_NUMBER_LENGTH) padded_value = force_text(value).rjust(ref_length - len(prefix), "0") reference_no = "%s%s" % (prefix, padded_value) return reference_no + calc_reference_number_checksum(reference_no)
def has_permission(self, request, view): try: permission = int( configuration.get(None, make_permission_config_key(view), DEFAULT_PERMISSION)) except ValueError: permission = DEFAULT_PERMISSION # god mode - just works if API is not disabled if request.user.is_superuser: return (permission <= PermissionLevel.ADMIN) # safe requests: GET, HEAD, OPTIONS if request.method in permissions.SAFE_METHODS: # to READ, the permissions can be WRITE or READ return ((request.user.is_authenticated() and permission <= PermissionLevel.AUTHENTICATED_WRITE) or permission <= PermissionLevel.PUBLIC_WRITE) # NOT safe: POST, PUT, DELETE else: # to change data, permission must be exactly WRITE if request.user.is_authenticated(): return permission in (PermissionLevel.AUTHENTICATED_WRITE, PermissionLevel.PUBLIC_WRITE) return (permission == PermissionLevel.PUBLIC_WRITE)
def _handle_xtheme_save(self): svc_pk = config.get(self.shop, CONTENT_FOOTER_KEY) svc = SavedViewConfig.objects.filter(pk=svc_pk).first() theme = get_current_theme(self.shop) if not svc and theme: context = {"shop": self.shop} rendered_content = template_loader.render_to_string( content_data.FOOTER_TEMPLATE, context).strip() layout = Layout(theme, "footer-bottom") # adds the footer template layout.begin_row() layout.begin_column({"md": 12}) layout.add_plugin(SnippetsPlugin.identifier, {"in_place": rendered_content}) svc = SavedViewConfig(theme_identifier=theme.identifier, shop=self.shop, view_name=XTHEME_GLOBAL_VIEW_NAME, status=SavedViewConfigStatus.CURRENT_DRAFT) svc.set_layout_data(layout.placeholder_name, layout) svc.save() svc.publish() config.set(self.shop, CONTENT_FOOTER_KEY, svc.pk)
def get_methods_validation_errors(self): shipping_methods = self.get_available_shipping_methods() payment_methods = self.get_available_payment_methods() advice = _( "Try to remove some products from the basket " "and order them separately.") if (self.has_shippable_lines() and not shipping_methods and configuration.get(self.shop, SHIPPING_METHOD_REQUIRED_CONFIG_KEY, True)): msg = _("Products in basket cannot be shipped together. %s") yield ValidationError(msg % advice, code="no_common_shipping") if not payment_methods and configuration.get(self.shop, PAYMENT_METHOD_REQUIRED_CONFIG_KEY, True): msg = _("Products in basket have no common payment method. %s") yield ValidationError(msg % advice, code="no_common_payment")
def toggle_all_seeing(request): return_url = request.META["HTTP_REFERER"] if not is_admin_user(request): return HttpResponseRedirect(return_url) all_seeing_key = "is_all_seeing:%d" % request.user.pk is_all_seeing = not configuration.get(None, all_seeing_key, False) configuration.set(None, all_seeing_key, is_all_seeing) return HttpResponseRedirect(return_url)
def test_consolidate_objects(rf): get_default_shop() # just visit to make sure GET is ok request = apply_request_middleware(rf.get("/")) response = APIPermissionView.as_view()(request) assert response.status_code == 200 perm_key = make_permission_config_key(UserViewSet()) assert configuration.get(None, perm_key) is None # now post the form to see what happens request = apply_request_middleware( rf.post("/", {perm_key: PermissionLevel.ADMIN})) response = APIPermissionView.as_view()(request) assert response.status_code == 302 # good assert int(configuration.get(None, perm_key)) == PermissionLevel.ADMIN
def get_form_defs(self): if not self.object.pk: return initial = { "shipping_method_required": configuration.get(self.object, SHIPPING_METHOD_REQUIRED_CONFIG_KEY, True), "payment_method_required": configuration.get(self.object, PAYMENT_METHOD_REQUIRED_CONFIG_KEY, True) } yield TemplatedFormDef( name=self.name, form_class=self.form, template_name="wshop/front/admin/checkout.jinja", required=False, kwargs={"initial": initial})
def get_global_configuration(name, default=None): """ Get global configuration variable value. :type name: str :type default: Any """ from wshop import configuration return configuration.get(None, name, default)
def test_permission_form(): form_data = {} form = APIPermissionForm() # extract fields for field in form.fields.keys(): # make sure that nothing is saved in configs assert configuration.get(None, field) is None # disable the API form_data[field] = PermissionLevel.DISABLED form = APIPermissionForm(data=form_data) form.save() # now check if the values were save for field in form.fields.keys(): assert int(configuration.get(None, field)) == PermissionLevel.DISABLED
def is_tour_complete(tour_key): """ Check if the tour is complete :param tour_key: The tour key. :type field: str :return: whether tour is complete :rtype: Boolean """ return configuration.get(None, "wshop_%s_tour_complete" % tour_key, False)
def get_unique_reference_number(shop, id): from wshop import configuration from wshop.admin.modules.settings.consts import ORDER_REFERENCE_NUMBER_LENGTH_FIELD now = datetime.datetime.now() ref_length = configuration.get(shop, ORDER_REFERENCE_NUMBER_LENGTH_FIELD, settings.WSHOP_REFERENCE_NUMBER_LENGTH) dt = ("%06s%07d%04d" % (now.strftime("%y%m%d"), now.microsecond, id % 1000)).rjust( ref_length, "0") return dt + calc_reference_number_checksum(dt)
def get_shop_configuration(context, name, default=None): """ Get configuration variable value for the current shop. :type context: jinja2.runtime.Context :type name: str :type default: Any """ from wshop import configuration return configuration.get(context.get("request").shop, name, default)
def __init__(self, *args, **kwargs): from wshop.admin.modules.settings import consts from wshop.admin.modules.settings.enums import OrderReferenceNumberMethod shop = kwargs.pop("shop") kwargs["initial"] = { consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD: configuration.get(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD, settings.WSHOP_REFERENCE_NUMBER_LENGTH), consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD: configuration.get(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, settings.WSHOP_REFERENCE_NUMBER_PREFIX), } super(ShopOrderConfigurationForm, self).__init__(*args, **kwargs) reference_method = configuration.get( shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, settings.WSHOP_REFERENCE_NUMBER_METHOD) self.prefix_disabled = (reference_method in [ OrderReferenceNumberMethod.UNIQUE.value, OrderReferenceNumberMethod.SHOP_RUNNING.value ]) self.fields[ consts. ORDER_REFERENCE_NUMBER_PREFIX_FIELD].disabled = self.prefix_disabled decimal_places = 2 # default if shop.currency in babel.core.get_global('currency_fractions'): decimal_places = babel.core.get_global('currency_fractions')[ shop.currency][0] self.fields[ORDER_MIN_TOTAL_CONFIG_KEY] = FormattedDecimalFormField( label=_("Order minimum total"), decimal_places=decimal_places, max_digits=FORMATTED_DECIMAL_FIELD_MAX_DIGITS, min_value=0, required=False, initial=configuration.get(shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0)), help_text=_( "The minimum sum that an order needs to reach to be created."))
def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") self.basket = kwargs.pop("basket") self.shop = kwargs.pop("shop") super(MethodsForm, self).__init__(*args, **kwargs) self.fields["shipping_method"] = forms.ModelChoiceField( queryset=ShippingMethod.objects.all(), widget=MethodWidget(), label=_('shipping method'), required=configuration.get(self.shop, SHIPPING_METHOD_REQUIRED_CONFIG_KEY, True)) self.fields["payment_method"] = forms.ModelChoiceField( queryset=PaymentMethod.objects.all(), widget=MethodWidget(), label=_('payment method'), required=configuration.get(self.shop, PAYMENT_METHOD_REQUIRED_CONFIG_KEY, True)) self.limit_method_fields()
def __init__(self, name, form_class, template_name, request, extra_js=""): shop = request.shop form_def_kwargs = { "name": name, "kwargs": { "instance": form_class._meta.model.objects.first(), "languages": configuration.get(shop, "languages", settings.LANGUAGES) } } super(ServiceWizardFormDef, self).__init__(form_class=form_class, template_name=template_name, extra_js=extra_js, **form_def_kwargs)
def setup_wizard_complete(request): """ Check if shop wizard should be run. :return: whether setup wizard needs to be run :rtype: boolean """ if getattr(settings, "WSHOP_ENABLE_MULTIPLE_SHOPS", False): # setup wizard is only applicable in single shop mode return True shop = request.shop complete = configuration.get(shop, "setup_wizard_complete") if complete is None: return not setup_wizard_visible_panes(shop) return complete
def set_reference_method(rf, admin_user, reference_method, shop=None): if not shop: shop = get_default_shop() request = apply_request_middleware(rf.get("/"), user=admin_user) view_func = SystemSettingsView.as_view() response = view_func(request) assert response.status_code == 200 data = { "order_settings-order_reference_number_method": reference_method.value } request = apply_request_middleware(rf.post("/", data=data)) view_func(request) assert configuration.get( None, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD) == reference_method.value return shop
def get_validation_errors(self): # noqa (C901) # check for the minimum sum of order total min_total = configuration.get(self.shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0)) total = (self.taxful_total_price.value if self.shop.prices_include_tax else self.taxless_total_price.value) if total < min_total: min_total_price = format_money(self.shop.create_price(min_total)) yield ValidationError( _("The total should be greater than {} to be ordered.").format( min_total_price), code="order_total_too_low") shipping_method = self.shipping_method payment_method = self.payment_method if shipping_method: for error in shipping_method.get_unavailability_reasons( source=self): yield error if payment_method: for error in payment_method.get_unavailability_reasons( source=self): yield error for supplier in self._get_suppliers(): for product, quantity in iteritems( self._get_products_and_quantities(supplier)): try: shop_product = product.get_shop_instance(shop=self.shop) except ShopProduct.DoesNotExist: yield ValidationError(_("%s not available in this shop") % product.name, code="product_not_available_in_shop") continue for error in shop_product.get_orderability_errors( supplier=supplier, quantity=quantity, customer=self.customer): error.message = "%s: %s" % (product.name, error.message) yield error
def _send_telemetry(request, max_age_hours, force_send=False): if not is_telemetry_enabled(): raise TelemetryNotSent("Telemetry not enabled", "disabled") if not force_send: if is_opt_out(): raise TelemetryNotSent("Telemetry is opted-out", "optout") if is_in_grace_period(): raise TelemetryNotSent("Telemetry in grace period", "grace") if max_age_hours is not None: last_send_time = get_last_submission_time() if last_send_time and (now() - last_send_time ).total_seconds() <= max_age_hours * 60 * 60: raise TelemetryNotSent("Trying to resend too soon", "age") data = get_telemetry_data(request) try: resp = requests.post(url=settings.WSHOP_TELEMETRY_URL, data=data, timeout=5) if (not settings.DEBUG and resp.status_code == 200 and resp.json().get("support_id") and not configuration.get(None, "wshop_support_id")): configuration.set(None, "wshop_support_id", resp.json().get("support_id")) except Exception as exc: data = { "data": data, "error": force_text(exc), } else: data = { "data": data, "response": force_text(resp.content, errors="replace"), "status": resp.status_code, } save_telemetry_submission(data) return data
def get_reference_number(order): from wshop import configuration from wshop.admin.modules.settings.consts import ORDER_REFERENCE_NUMBER_METHOD_FIELD if order.reference_number: raise ValueError( "Order passed to get_reference_number() already has a reference number" ) reference_number_method = configuration.get( order.shop, ORDER_REFERENCE_NUMBER_METHOD_FIELD, settings.WSHOP_REFERENCE_NUMBER_METHOD) if reference_number_method == "unique": return get_unique_reference_number_for_order(order) elif reference_number_method == "running": return get_running_reference_number(order) elif reference_number_method == "shop_running": return get_shop_running_reference_number(order) elif callable(reference_number_method): return reference_number_method(order) else: getter = load(reference_number_method, "Reference number generator") return getter(order)
def __init__(self, **kwargs): super(APIPermissionForm, self).__init__(**kwargs) # create a choice field for each entry in the router # this way it will be easy to set permisions based on each viewset # but they must be beautifully configured with name and description # to become more presentable to the merchant for __, viewset, basename in api_urls.router.registry: viewset_instance = viewset() field_name = make_permission_config_key(viewset_instance) initial = configuration.get(None, field_name, DEFAULT_PERMISSION) if issubclass(viewset, PermissionHelperMixin): help_text = viewset.get_help_text() else: help_text = viewset_instance.get_view_description() self.fields[field_name] = forms.ChoiceField( label=(viewset_instance.get_view_name() or basename), help_text=help_text, initial=initial, required=False, choices=self.API_PERMISSION_CHOICES)
def assert_config_value(rf, admin_user, form_id, key, value, expected_value, shop=None): if not shop: shop = get_default_shop() request = apply_request_middleware(rf.get("/"), user=admin_user) view_func = SystemSettingsView.as_view() response = view_func(request) assert response.status_code == 200 form_field = "%s-%s" % (form_id, key) data = {form_field: value} request = apply_request_middleware(rf.post("/", data=data)) response = view_func(request) assert response.status_code == 302 if expected_value == "unset": expected_value = value assert configuration.get(None, key) == expected_value return shop
def get_config(self, value): val = configuration.get(None, self.get_settings_key(value), {}) return val
def dispatch(self, request, *args, **kwargs): if not configuration.get(request.shop, "allow_company_registration"): return HttpResponseNotFound() return super(CompanyEditView, self).dispatch(request, *args, **kwargs)