def _get_shop_product_sample_data(): return { "shop": get_default_shop().id, "suppliers": [ get_default_supplier().id ], "visibility": ShopProductVisibility.ALWAYS_VISIBLE.value, "purchasable": False, "visibility_limit": ProductVisibility.VISIBLE_TO_ALL.value, "visibility_groups": [ create_random_contact_group().id, create_random_contact_group().id, ], "backorder_maximum": 0, "purchase_multiple": 1, "minimum_purchase_quantity": 1, "limit_shipping_methods": False, "limit_payment_methods": False, "shipping_methods": [], "payment_methods": [], "primary_category": get_default_category().id, "categories": [ get_default_category().id, CategoryFactory().id ], "default_price_value": 12.45, "minimum_price_value": 5.35 }
def test_product_descriptions(browser, live_server, settings): activate("en") cache.clear() shop = get_default_shop() product = create_product("product1", shop=shop, description="<b>My HTML description</b>", short_description="some short of description instead", supplier=get_default_supplier()) sp = ShopProduct.objects.get(product=product, shop=shop) sp.primary_category = get_default_category() sp.categories.add(get_default_category()) sp.save() # initialize test and go to front page browser = initialize_front_browser_test(browser, live_server) # view product detail page url = reverse("shuup:product", kwargs={"pk": product.pk, "slug": product.slug}) browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, lambda x: x.is_text_present(product.short_description)) assert product.description in browser.html # ensure the version is in static files assert "style.css?v=%s" % shuup.__version__ in browser.html # product preview url = reverse("shuup:xtheme_extra_view", kwargs={"view": "products"}) browser.visit("%s%s" % (live_server, url)) product_div_name = "product-{}".format(product.pk) wait_until_condition(browser, lambda x: x.find_by_css("#{} button.btn".format(product_div_name))) browser.execute_script("$('#{} button.btn').click();".format(product_div_name)) assert product.short_description == browser.find_by_css("#{} p.description".format(product_div_name))[0].html
def test_carousel_create(browser, admin_user, live_server, settings): shop = factories.get_default_shop() filer_image = factories.get_random_filer_image() factories.get_default_category() initialize_admin_browser_test(browser, live_server, settings, shop=shop) wait_until_condition(browser, lambda x: x.is_text_present("Welcome!")) assert not Carousel.objects.exists() browser.visit(live_server + "/sa/carousels/new") wait_until_condition(browser, lambda x: x.is_text_present("New Carousel")) browser.fill("base-name", "Carrot") click_element(browser, "button[form='carousel_form']") wait_until_appeared(browser, "div[class='message success']") assert Carousel.objects.count() == 1 carousel = Carousel.objects.first() browser.visit(live_server + "/sa/carousels/%d/" % carousel.pk) wait_until_condition(browser, lambda x: x.is_text_present(carousel.name)) click_element(browser, "a[href='#slides-section']") wait_until_appeared(browser, ".slide-add-new-panel") # add 1 slide click_element(browser, ".slide-add-new-panel") wait_until_condition(browser, lambda x: x.is_text_present("Slide 1")) wait_until_appeared(browser, "a[href='#collapse1']") click_element(browser, "a[href='#collapse1']") browser.find_by_css("#slide_1-en [name='slides-__slide_prefix__-caption__en']").fill("New Slide") click_element(browser, "[name='slides-__slide_prefix__-category_link'] + .select2") wait_until_appeared(browser, ".select2-container #select2-id_slides-__slide_prefix__-category_link-results li") click_element(browser, ".select2-container #select2-id_slides-__slide_prefix__-category_link-results li:last-child") browser.find_by_css("#slide_1-en [data-dropzone='true']").click() wait_until_condition(browser, lambda b: len(b.windows) == 2) # change to the media browser window browser.windows.current = browser.windows[1] # click to select the picture wait_until_appeared(browser, "a.file-preview") click_element(browser, "a.file-preview") # back to the main window wait_until_condition(browser, lambda b: len(b.windows) == 1) browser.windows.current = browser.windows[0] wait_until_appeared(browser, ".dz-image img[alt='%s']" % filer_image.name) click_element(browser, "button[form='carousel_form']") wait_until_appeared(browser, "div[class='message success']")
def test_manufacturer_filter_get_fields(rf): shop = factories.get_default_shop() request = apply_request_middleware(rf.get("/")) assert ManufacturerProductListFilter().get_fields(request, None) is None manufacturer = Manufacturer.objects.create(name="Random Brand Inc") assert ManufacturerProductListFilter().get_fields(request, None) is None category = factories.get_default_category() product = factories.create_product("sku", shop=shop) shop_product = product.get_shop_instance(shop=shop) shop_product.primary_category = category shop_product.save() assert ManufacturerProductListFilter().get_fields(request, category) is None # Now once we link manufacturer to product we should get # form field for manufacturer product.manufacturer = manufacturer product.save() form_field = ManufacturerProductListFilter().get_fields(request, category)[0][1] assert form_field is not None assert form_field.label == "Manufacturers" assert len(form_field.queryset) == 1 with override_settings(SHUUP_FRONT_OVERRIDE_SORTS_AND_FILTERS_LABELS_LOGIC={"manufacturers": "Brands"}): form_field = ManufacturerProductListFilter().get_fields(request, category)[0][1] assert form_field is not None assert form_field.label == "Brands" assert len(form_field.queryset) == 1
def test_category_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() category = get_default_category() product = create_product("The Product", shop=shop, default_price="200", supplier=supplier) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) shop_product = product.get_shop_instance(shop) assert category not in shop_product.categories.all() condition = CategoryProductsBasketCondition.objects.create( category=category, operator=ComparisonOperator.EQUALS, quantity=1) # No match the product does not have the category assert not condition.matches(basket, []) shop_product.categories.add(category) assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, []) condition.operator = ComparisonOperator.GTE condition.save() assert condition.matches(basket, [])
def test_products_form_add_multiple_products(): shop = get_default_shop() category = get_default_category() category.shops.add(shop) product_ids = [] for x in range(0, 15): product = create_product("%s" % x, shop=shop) product_ids.append(product.id) for x in range(0, 5): product = create_product("parent_%s" % x, shop=shop, mode=ProductMode.SIMPLE_VARIATION_PARENT) for y in range(0, 3): child_product = create_product("child_%s_%s" % (x, y), shop=shop) child_product.link_to_parent(product) product_ids.append(product.id) assert (category.shop_products.count() == 0) data = { "additional_products": ["%s" % product_id for product_id in product_ids] } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() category.refresh_from_db() assert (category.shop_products.count() == 35) # 15 normal products and 5 parents with 3 children each
def test_sorts_and_filter_in_category_edit(rf, admin_user): get_default_shop() cache.clear() activate("en") with override_provides("front_extend_product_list_form", DEFAULT_FORM_MODIFIERS): category = get_default_category() view = CategoryEditView.as_view() assert get_configuration(category=category) == settings.SHUUP_FRONT_DEFAULT_SORT_CONFIGURATION data = { "base-name__en": category.name, "base-status": category.status.value, "base-visibility": category.visibility.value, "base-ordering": category.ordering, "product_list_facets-sort_products_by_name": True, "product_list_facets-sort_products_by_name_ordering": 6, "product_list_facets-sort_products_by_price": False, "product_list_facets-sort_products_by_price_ordering": 32, "product_list_facets-filter_products_by_manufacturer": True, "product_list_facets-filter_products_by_manufacturer_ordering": 1 } request = apply_request_middleware(rf.post("/", data=data), user=admin_user) response = view(request, pk=category.pk) if hasattr(response, "render"): response.render() assert response.status_code in [200, 302] expected_configurations = { "sort_products_by_name": True, "sort_products_by_name_ordering": 6, "sort_products_by_price": False, "sort_products_by_price_ordering": 32, "filter_products_by_manufacturer": True, "filter_products_by_manufacturer_ordering": 1 } assert get_configuration(category=category) == expected_configurations
def test_products_form_add(): shop = get_default_shop() category = get_default_category() category.visibility = CategoryVisibility.VISIBLE_TO_LOGGED_IN category.status = CategoryStatus.INVISIBLE category.shops.add(shop) category.save() product = create_product("test_product", shop=shop) shop_product = product.get_shop_instance(shop) product_category = product.category assert (product_category is None) assert (category not in shop_product.categories.all()) data = { "primary_products": ["%s" % product.id] } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() shop_product.refresh_from_db() product.refresh_from_db(()) assert (shop_product.primary_category == category) assert (category in shop_product.categories.all()) assert (shop_product.visibility_limit.value == category.visibility.value) assert (shop_product.visible == False) assert (product.category is None)
def test_products_form_remove(): shop = get_default_shop() category = get_default_category() category.shops.add(shop) product = create_product("test_product", shop=shop) shop_product = product.get_shop_instance(shop) shop_product.primary_category = category shop_product.save() shop_product.categories.add(category) shop_product.refresh_from_db() assert (shop_product.primary_category == category) assert (shop_product.categories.count() == 1) assert (shop_product.categories.first() == category) data = { "remove_products": ["%s" % shop_product.id] } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() category.refresh_from_db() assert (category.shop_products.count() == 0) shop_product.refresh_from_db() assert (shop_product.primary_category is None) assert (shop_product.categories.count() == 0)
def test_category_filter(rf): request, shop, group = initialize_test(rf, False) cat = get_default_category() cat_filter = CategoryFilter.objects.create() cat_filter.categories.add(cat) cat_filter.save() assert cat_filter.values.first() == cat category = Category.objects.create( parent=None, identifier="testcat", name="catcat", ) cat_filter.values = [cat, category] cat_filter.save() assert cat_filter.values.count() == 2 product = create_product("Just-A-Product-Too", shop, default_price="200") shop_product = product.get_shop_instance(shop) shop_product.categories.add(cat) shop_product.save() assert cat_filter.filter_queryset(ShopProduct.objects.all()).exists() # filter matches
def test_category_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() category = get_default_category() product = create_product("The Product", shop=shop, default_price="200", supplier=supplier) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) basket.shipping_method = get_shipping_method(shop=shop) shop_product = product.get_shop_instance(shop) assert category not in shop_product.categories.all() condition = CategoryProductsBasketCondition.objects.create(operator=ComparisonOperator.EQUALS, quantity=1) condition.categories.add(category) # No match the product does not have the category assert not condition.matches(basket, []) category.shop_products.add(shop_product) assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, []) condition.operator = ComparisonOperator.GTE condition.save() assert condition.matches(basket, []) condition.excluded_categories.add(category) assert not condition.matches(basket, []) with pytest.raises(CampaignsInvalidInstanceForCacheUpdate): update_filter_cache("test", shop)
def test_all_categories_view(rf, admin_user): shop = get_default_shop() supplier = get_default_supplier() category = get_default_category() product = get_default_product() request = apply_request_middleware(rf.get("/")) _check_product_count(request, 0) shop_product = product.get_shop_instance(shop) shop_product.categories.add(category) _check_product_count(request, 1) # Create few categories for better test results for i in range(10): cat = Category.objects.create(name=printable_gibberish()) cat.shops.add(shop) new_product_count = random.randint(1, 3) + 1 for i in range(1, new_product_count): product = create_product("sku-%s" % i, shop=shop, supplier=supplier, default_price=10) shop_product = product.get_shop_instance(shop) # Add random categories expect default category which we will make # hidden to make sure that products linked to hidden categories are # not listed shop_product.categories = Category.objects.exclude(id=category.pk).order_by("?")[:i] _check_product_count(request, new_product_count) category.status = CategoryStatus.INVISIBLE category.save() _check_product_count(request, new_product_count - 1)
def test_category_create_with_parent(rf, admin_user): shop = get_default_shop() default_category = get_default_category() default_category.shops.clear() assert shop not in default_category.shops.all() with override_settings(LANGUAGES=[("en", "en")]): view = CategoryEditView.as_view() cat_name = "Random name" data = { "base-name__en": cat_name, "base-status": CategoryStatus.VISIBLE.value, "base-visibility": CategoryVisibility.VISIBLE_TO_ALL.value, "base-ordering": 1, "base-parent": default_category.pk } assert Category.objects.count() == 1 request = apply_request_middleware(rf.post("/", data=data), user=admin_user, shop=shop) response = view(request, pk=None) if hasattr(response, "render"): response.render() assert response.status_code in [200, 302] assert Category.objects.count() == 1 default_category.shops.add(shop) request = apply_request_middleware(rf.post("/", data=data), user=admin_user, shop=shop) response = view(request, pk=None) if hasattr(response, "render"): response.render() assert response.status_code in [200, 302] assert Category.objects.count() == 2
def test_category_deletion(admin_user): admin = get_person_contact(admin_user) category = get_default_category() category.children.create(identifier="foo") shop_product = get_default_shop_product() shop_product.categories.add(category) shop_product.primary_category = category shop_product.save() configuration.set(None, get_all_seeing_key(admin), True) assert category.status == CategoryStatus.VISIBLE assert category.children.count() == 1 with pytest.raises(NotImplementedError): category.delete() category.soft_delete() shop_product.refresh_from_db() shop_product.product.refresh_from_db() assert shop_product.categories.count() == 0 assert shop_product.primary_category is None assert category.status == CategoryStatus.DELETED assert category.children.count() == 0 # the child category still exists assert Category.objects.all_visible(customer=admin).count() == 1 assert Category.objects.all_except_deleted().count() == 1 configuration.set(None, get_all_seeing_key(admin), False)
def test_category_links_plugin_with_customer(rf, show_all_categories): """ Test plugin for categories that is visible for certain group """ shop = get_default_shop() group = get_default_customer_group() customer = create_random_person() customer.groups.add(group) customer.save() request = rf.get("/") request.shop = get_default_shop() apply_request_middleware(request) request.customer = customer category = get_default_category() category.status = CategoryStatus.VISIBLE category.visibility = CategoryVisibility.VISIBLE_TO_GROUPS category.visibility_groups.add(group) category.shops.add(shop) category.save() vars = {"request": request} context = get_jinja_context(**vars) plugin = CategoryLinksPlugin({"categories": [category.pk], "show_all_categories": show_all_categories}) assert category.is_visible(customer) assert category in plugin.get_context_data(context)["categories"] customer_without_groups = create_random_person() customer_without_groups.groups.clear() assert not category.is_visible(customer_without_groups) request.customer = customer_without_groups context = get_jinja_context(**vars) assert category not in plugin.get_context_data(context)["categories"]
def test_category_removal(): product = get_product() category = get_default_category() product.category = category product.save() with pytest.raises(NotImplementedError): category.delete() assert Product.objects.filter(pk=product.pk).exists()
def test_shopproduct_primary_category_removal(): product = get_product() category = get_default_category() sp = product.get_shop_instance(get_default_shop()) sp.primary_category = category sp.save() with pytest.raises(NotImplementedError): category.delete() assert ShopProduct.objects.filter(pk=sp.pk).exists()
def test_list_view(rf, admin_user): shop = factories.get_default_shop() product = factories.create_product(sku="test", shop=shop) shop_product = product.get_shop_instance(shop) shop_product.primary_category = factories.get_default_category() shop_product.save() shop_product.categories.add(shop_product.primary_category) view = load("shuup.admin.modules.products.views: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 data = json.loads(response.content.decode("utf-8")) product_data = [item for item in data["items"] if item["_id"] == shop_product.pk][0] assert product_data["primary_category"] == factories.get_default_category().name assert product_data["categories"] == factories.get_default_category().name
def test_default_layout(): vc = _get_basic_view_config() product = factories.create_product("test", name="Test product name") category = factories.get_default_category() placeholder_name = "wildhorse" context = {"request": get_request(), "product": product, "category": category} layout = vc.get_placeholder_layout(Layout, placeholder_name) assert isinstance(layout, Layout) assert layout.get_help_text({}) == layout.get_help_text(context) _add_plugin_and_test_save(vc, layout, placeholder_name, context)
def test_price_info_cache_bump(rf): initial_price = 10 shop = factories.get_default_shop() tax = factories.get_default_tax() tax_class = factories.get_default_tax_class() product = factories.create_product( "product", shop=shop, supplier=factories.get_default_supplier(), default_price=initial_price ) request = apply_request_middleware(rf.get("/")) def assert_cache_product(): cache_price_info(request, product, 1, product.get_price_info(request)) assert get_cached_price_info(request, product, 1).price == shop.create_price(initial_price) def assert_nothing_is_cached(): # nothing is cached assert get_cached_price_info(request, product, 1) is None # cache the item assert_nothing_is_cached() assert_cache_product() # cache bumped - the cache should be dropped - then, cache again tax.save() assert_nothing_is_cached() assert_cache_product() # cache bumped - the cache should be dropped - then, cache again tax_class.save() assert_nothing_is_cached() assert_cache_product() # cache bumped - the cache should be dropped - then, cache again product.save() assert_nothing_is_cached() assert_cache_product() shop_product = product.get_shop_instance(shop) # cache bumped - the cache should be dropped - then, cache again shop_product.save() assert_nothing_is_cached() assert_cache_product() category = factories.get_default_category() # cache bumped - the cache should be dropped - then, cache again shop_product.categories.add(category) assert_nothing_is_cached() assert_cache_product()
def test_category_layout(): vc = _get_basic_view_config() category = factories.get_default_category() placeholder_name = "japanese" context = {"category": category} layout = vc.get_placeholder_layout(CategoryLayout, placeholder_name, context=context) assert isinstance(layout, CategoryLayout) assert layout.get_help_text({}) == "" # Invalid context for help text assert category.name in layout.get_help_text(context) _assert_empty_layout(layout, placeholder_name) _add_plugin_and_test_save(vc, layout, placeholder_name, context)
def test_ajax_select_view_with_categories(rf): activate("en") view = MultiselectAjaxView.as_view() results = _get_search_results(rf, view, "shuup.Category", "some str") assert len(results) == 0 category = get_default_category() results = _get_search_results(rf, view, "shuup.Category", category.name) assert len(results) == 1 category.soft_delete() results = _get_search_results(rf, view, "shuup.Category", category.name) assert len(results) == 0
def test_supplier_filter_get_fields(rf): shop = factories.get_default_shop() request = apply_request_middleware(rf.get("/")) category = factories.get_default_category() supplier = Supplier.objects.create(name="Mike Inc") supplier.shops.add(shop) assert SupplierProductListFilter().get_fields(request, None) is None product = factories.create_product("sku", shop=shop) shop_product = product.get_shop_instance(shop=shop) shop_product.primary_category = category shop_product.save() assert SupplierProductListFilter().get_fields(request, category) is None # Now once we link manufacturer to product we should get # form field for manufacturer shop_product.suppliers.add(supplier) form_field = SupplierProductListFilter().get_fields(request, category)[0][1] assert form_field is not None assert form_field.label == "Suppliers" assert len(form_field.queryset) == 1 # Add second supplier for new product supplier2 = Supplier.objects.create(name="K Inc") supplier2.shops.add(shop) new_product = factories.create_product("sku1", shop=shop) new_shop_product = new_product.get_shop_instance(shop=shop) new_shop_product.suppliers.add(supplier2) # Still one with category since shop product not linked to category form_field = SupplierProductListFilter().get_fields(request, category)[0][1] assert form_field is not None assert len(form_field.queryset) == 1 # Without category we get two results form_field = SupplierProductListFilter().get_fields(request, None)[0][1] assert form_field is not None assert len(form_field.queryset) == 2 new_shop_product.categories.add(category) # primary category shouldn't be required # Now with or without category we get 2 results form_field = SupplierProductListFilter().get_fields(request, category)[0][1] assert form_field is not None assert len(form_field.queryset) == 2 form_field = SupplierProductListFilter().get_fields(request, None)[0][1] assert form_field is not None assert len(form_field.queryset) == 2
def test_product_from_category_plugin(rf): shop = get_default_shop() category1 = get_default_category() category2 = CategoryFactory(status=CategoryStatus.VISIBLE) category1.shops.add(shop) category2.shops.add(shop) p1 = create_product("p1", shop, get_default_supplier(), "10") p2 = create_product("p2", shop, get_default_supplier(), "20") p3 = create_product("p3", shop, get_default_supplier(), "30") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) sp1.categories.add(category1) sp2.categories.add(category1) sp3.categories.add(category2) context = get_context(rf) plugin = ProductsFromCategoryPlugin({ "category": category1.pk }) context_products = plugin.get_context_data(context)["products"] assert p1 in context_products assert p2 in context_products assert p3 not in context_products # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductsFromCategoryPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-count": 4, "plugin-category": category2.pk }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() lcfg.save() assert cell.config["category"] == str(category2.pk)
def test_category_links_plugin_show_all(rf): """ Test that show_all_categories forces plugin to return all visible categories """ category = get_default_category() category.status = CategoryStatus.VISIBLE category.shops.add(get_default_shop()) category.save() context = get_context(rf) plugin = CategoryLinksPlugin({"show_all_categories": False}) assert context["request"].customer.is_anonymous assert context["request"].shop in category.shops.all() assert not plugin.get_context_data(context)["categories"] plugin = CategoryLinksPlugin({"show_all_categories": True}) assert category in plugin.get_context_data(context)["categories"]
def _get_custom_order(regular_user, **kwargs): prices_include_tax = kwargs.pop("prices_include_tax", False) include_basket_campaign = kwargs.pop("include_basket_campaign", False) include_catalog_campaign = kwargs.pop("include_catalog_campaign", False) shop = get_shop(prices_include_tax=prices_include_tax) supplier = get_simple_supplier() if include_basket_campaign: _add_basket_campaign(shop) if include_catalog_campaign: _add_catalog_campaign(shop) _add_taxes() contact = get_person_contact(regular_user) source = BasketishOrderSource(shop) source.status = get_initial_order_status() source.customer = contact ctx = get_pricing_module().get_context_from_data(shop, contact) for product_data in _get_product_data(): quantity = product_data.pop("quantity") product = create_product( sku=product_data.pop("sku"), shop=shop, supplier=supplier, stock_behavior=StockBehavior.STOCKED, tax_class=get_default_tax_class(), **product_data) shop_product = product.get_shop_instance(shop) shop_product.categories.add(get_default_category()) shop_product.save() supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY) pi = product.get_price_info(ctx) source.add_line( type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, base_unit_price=pi.base_unit_price, discount_amount=pi.discount_amount ) oc = OrderCreator() order = oc.create_order(source) return order
def test_slide_links(): test_carousel = Carousel.objects.create(name="test") test_image_1 = Image.objects.create(original_filename="slide1.jpg") with translation.override("en"): test_slide = Slide.objects.create(carousel=test_carousel, name="test", image=test_image_1) # Test external link assert len(test_carousel.slides.all()) == 1 test_link = "http://example.com" test_slide.external_link = test_link test_slide.save() assert test_slide.get_translated_field("external_link") == test_link assert test_slide.get_link_url() == test_link # Test Product url and link priorities test_product = get_default_product() test_slide.product_link = test_product test_slide.save() assert test_slide.get_link_url() == test_link test_slide.external_link = None test_slide.save() assert test_slide.get_link_url().startswith("/p/") # Close enough... # Test Category url and link priorities test_category = get_default_category() test_slide.category_link = test_category test_slide.save() assert test_slide.get_link_url().startswith("/p/") # Close enough... test_slide.product_link = None test_slide.save() assert test_slide.get_link_url().startswith("/c/") # Close enough... # Test CMS page url and link priorities attrs = {"url": "test", "shop": get_default_shop()} test_page = create_page(**attrs) test_slide.cms_page_link = test_page test_slide.save() assert test_slide.get_link_url().startswith("/c/") # Close enough... test_slide.category_link = None test_slide.save() assert test_slide.get_link_url().startswith("/test/") # Check that external link overrides everything test_slide.external_link = test_link test_slide.save() assert test_slide.get_link_url() == test_link
def test_products_form_update_default_category(): shop = get_default_shop() category = get_default_category() category.shops.add(shop) product = create_product("test_product", shop=shop) shop_product = product.get_shop_instance(shop) assert (category not in shop_product.categories.all()) data = { "primary_products": ["%s" % product.id], "update_product_category": True } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() shop_product.refresh_from_db() product.refresh_from_db() assert (shop_product.primary_category == category) assert (category in shop_product.categories.all())
def test_category_links_plugin(rf): """ Test that the plugin only displays visible categories with shop (since we can't have a request without shop or customer) """ category = get_default_category() context = get_context(rf) plugin = CategoryLinksPlugin({"show_all_categories": True}) assert context["request"].customer.is_anonymous assert category not in plugin.get_context_data(context)["categories"] category.status = CategoryStatus.VISIBLE category.shops.add(get_default_shop()) category.save() assert context["request"].customer.is_anonymous assert context["request"].shop in category.shops.all() assert category in plugin.get_context_data(context)["categories"]
def test_recently_viewed_products(browser, live_server, settings): shop = get_default_shop() category = get_default_category() category.shops.add(shop) category.status = CategoryStatus.VISIBLE category.save() category_url = reverse("shuup:category", kwargs={"pk": category.pk, "slug": category.slug}) browser = initialize_front_browser_test(browser, live_server) for i in range(1, 7): product = new_product(i, shop, category) product_url = reverse("shuup:product", kwargs={"pk": product.pk, "slug": product.slug}) browser.visit(live_server + product_url) wait_until_appeared(browser, ".product-main") browser.visit(live_server + category_url) wait_until_appeared(browser, ".categories-nav") items = browser.find_by_css(".recently-viewed li") assert items.first.text == product.name, "recently clicked product on top" assert len(items) == min(i, 5)
def test_all_categories_view(rf, reindex_catalog): shop = get_default_shop() supplier = get_default_supplier() category = get_default_category() product = get_default_product() request = apply_request_middleware(rf.get("/")) reindex_catalog() _check_product_count(request, 0) shop_product = product.get_shop_instance(shop) shop_product.categories.add(category) reindex_catalog() _check_product_count(request, 1) # Create few categories for better test results for i in range(10): cat = Category.objects.create(name=printable_gibberish()) cat.shops.add(shop) new_product_count = random.randint(1, 3) + 1 for i in range(1, new_product_count): product = create_product("sku-%s" % i, shop=shop, supplier=supplier, default_price=10) shop_product = product.get_shop_instance(shop) # Add random categories expect default category which we will make # hidden to make sure that products linked to hidden categories are # not listed shop_product.categories.set( Category.objects.exclude(id=category.pk).order_by("?")[:i]) reindex_catalog() _check_product_count(request, new_product_count) category.status = CategoryStatus.INVISIBLE category.save() reindex_catalog() _check_product_count(request, new_product_count - 1)
def test_slide_admin_form(rf, admin_user): translation.activate("en") shop = get_default_shop() category = get_default_category() assert category.shops.first() == shop page = create_page(**{"url": "test", "shop": shop}) assert page.shop == shop test_carousel = Carousel.objects.create(name="test") request = apply_request_middleware(rf.get("/")) request.user = admin_user request.shop = shop slide_form = SlideForm( carousel=test_carousel, languages=settings.LANGUAGES, default_language=settings.PARLER_DEFAULT_LANGUAGE_CODE, request=request) soup = BeautifulSoup(slide_form.as_table()) options = soup.find(id="id_category_link").find_all("option") assert len(options) == 2 assert options[0]["value"] == "" assert options[1]["value"] == "%s" % category.pk options = soup.find(id="id_cms_page_link").find_all("option") assert len(options) == 2 assert options[0]["value"] == "" assert options[1]["value"] == "%s" % page.pk new_shop = get_shop(identifier="second-shop") category.shops = [new_shop] page.shop = new_shop page.save() soup = BeautifulSoup(slide_form.as_table()) options = soup.find(id="id_category_link").find_all("option") assert len(options) == 1 assert options[0]["value"] == "" options = soup.find(id="id_cms_page_link").find_all("option") assert len(options) == 1 assert options[0]["value"] == ""
def test_list_view(rf, admin_user): shop = factories.get_default_shop() supplier = get_simple_supplier() product = factories.create_product(sku="test", shop=shop, supplier=supplier) shop_product = product.get_shop_instance(shop) shop_product.primary_category = factories.get_default_category() shop_product.save() shop_product.categories.add(shop_product.primary_category) view = load("shuup.simple_supplier.admin_module.views:StocksListView").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 data = json.loads(response.content.decode("utf-8")) for item in data["items"]: assert item["_url"] == ""
def test_products_form_add(): shop = get_default_shop() category = get_default_category() category.visibility = CategoryVisibility.VISIBLE_TO_LOGGED_IN category.status = CategoryStatus.INVISIBLE category.shops.add(shop) category.save() product = create_product("test_product", shop=shop) shop_product = product.get_shop_instance(shop) assert (category not in shop_product.categories.all()) data = {"primary_products": ["%s" % product.id]} form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() shop_product.refresh_from_db() product.refresh_from_db(()) assert (shop_product.primary_category == category) assert (category in shop_product.categories.all()) assert (shop_product.visibility_limit.value == category.visibility.value) assert (shop_product.visibility == ShopProductVisibility.NOT_VISIBLE)
def test_products_form_add_multiple_products(): shop = get_default_shop() category = get_default_category() category.shops.add(shop) product_ids = [] for x in range(0, 15): product = create_product("%s" % x, shop=shop) product_ids.append(product.id) assert (category.shop_products.count() == 0) data = { "additional_products": ["%s" % product_id for product_id in product_ids] } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() category.refresh_from_db() assert (category.shop_products.count() == len(product_ids))
def test_generate_slugs_for_category(): activate("en") category = get_default_category() assert category.slug == slugify(category.name) default_slug = category.slug # Test that slug is only generated when it's empty on save new_name = "Some new cat name" category.name = new_name category.save() assert category.slug == default_slug, "Old slug" category.slug = "" category.save() assert category.slug == slugify(new_name), "New slug generated" # Check that slug is not generated to other languages with pytest.raises(ObjectDoesNotExist): translation = category.get_translation("fi") translation.refresh_from_db( ) # If the translation object was returned from cache
def test_products_for_category_cache_bump(): from shuup.front.template_helpers import general supplier = get_default_supplier() shop = get_default_shop() category = get_default_category() products = [ create_product("sku-%d" % x, supplier=supplier, shop=shop) for x in range(2) ] children = [ create_product("SimpleVarChild-%d" % x, supplier=supplier, shop=shop) for x in range(2) ] category.shops.add(shop) for child in children: child.link_to_parent(products[0]) context = get_jinja_context() for product in products: product.get_shop_instance(shop).categories.add(category) cache.clear() set_cached_value_mock = mock.Mock(wraps=context_cache.set_cached_value) with mock.patch.object(context_cache, "set_cached_value", new=set_cached_value_mock): assert set_cached_value_mock.call_count == 0 assert general.get_products_for_categories(context, [category]) assert set_cached_value_mock.call_count == 1 # call again, the cache should be returned instead and the set_cached_value shouldn't be called again assert general.get_products_for_categories(context, [category]) assert set_cached_value_mock.call_count == 1 # change a shop product, the cache should be bumped ShopProduct.objects.filter(shop=shop).first().save() assert general.get_products_for_categories(context, [category]) assert set_cached_value_mock.call_count == 2
def test_category_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() category = get_default_category() product = create_product("The Product", shop=shop, default_price="200", supplier=supplier) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) basket.shipping_method = get_shipping_method(shop=shop) shop_product = product.get_shop_instance(shop) assert category not in shop_product.categories.all() condition = CategoryProductsBasketCondition.objects.create( operator=ComparisonOperator.EQUALS, quantity=1) condition.categories.add(category) # No match the product does not have the category assert not condition.matches(basket, []) shop_product.categories.add(category) assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, []) condition.operator = ComparisonOperator.GTE condition.save() assert condition.matches(basket, []) condition.excluded_categories.add(category) assert not condition.matches(basket, [])
def test_sorts_and_filter_in_category_edit(rf, admin_user): get_default_shop() cache.clear() activate("en") with override_settings(SHUUP_ENABLE_MULTIPLE_SHOPS=False): with override_provides("front_extend_product_list_form", DEFAULT_FORM_MODIFIERS): category = get_default_category() view = CategoryEditView.as_view() assert get_configuration( category=category ) == settings.SHUUP_FRONT_DEFAULT_SORT_CONFIGURATION data = { "base-name__en": category.name, "base-status": category.status.value, "base-visibility": category.visibility.value, "base-ordering": category.ordering, "product_list_facets-sort_products_by_name": True, "product_list_facets-sort_products_by_name_ordering": 6, "product_list_facets-sort_products_by_price": False, "product_list_facets-sort_products_by_price_ordering": 32, "product_list_facets-filter_products_by_manufacturer": True, "product_list_facets-filter_products_by_manufacturer_ordering": 1 } request = apply_request_middleware(rf.post("/", data=data), user=admin_user) response = view(request, pk=category.pk) if hasattr(response, "render"): response.render() assert response.status_code in [200, 302] expected_configurations = { "sort_products_by_name": True, "sort_products_by_name_ordering": 6, "sort_products_by_price": False, "sort_products_by_price_ordering": 32, "filter_products_by_manufacturer": True, "filter_products_by_manufacturer_ordering": 1 } assert get_configuration( category=category) == expected_configurations
def test_category_selection_excluded(rf): default_price = 10 request, product = _init_test_for_product(rf, default_price) category = factories.get_default_category() product_discount_amount = 4 Discount.objects.create( shop=request.shop, active=True, exclude_selected_category=True, category=category, discount_amount_value=product_discount_amount, ) # applies to all products, except the selected category assert product.get_price_info(request).price == request.shop.create_price( default_price - product_discount_amount) # Setting default category for product disables the discount product.get_shop_instance(request.shop).categories.add(category) assert product.get_price_info(request).price == request.shop.create_price( default_price)
def test_products_form_update_default_category(): shop = get_default_shop() category = get_default_category() category.shops.add(shop) product = create_product("test_product", shop=shop) shop_product = product.get_shop_instance(shop) product_category = product.category assert (product_category is None) assert (category not in shop_product.categories.all()) data = { "primary_products": ["%s" % product.id], "update_product_category": True } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() shop_product.refresh_from_db() product.refresh_from_db() assert (shop_product.primary_category == category) assert (category in shop_product.categories.all()) assert (product.category == category)
def test_recently_viewed_products(browser, live_server, settings): shop = get_default_shop() category = get_default_category() category.shops.add(shop) category.status = CategoryStatus.VISIBLE category.save() category_url = reverse("shuup:category", kwargs={"pk": category.pk, "slug": category.slug}) products = [] for i in range(1, 7): products.append(new_product(i, shop, category)) browser = initialize_front_browser_test(browser, live_server) for i, product in enumerate(products, 1): product_url = reverse("shuup:product", kwargs={"pk": product.pk, "slug": product.slug}) browser.visit(live_server + product_url) wait_until_appeared(browser, ".product-main") browser.visit(live_server + category_url) wait_until_appeared(browser, ".categories-nav") items = browser.find_by_css(".recently-viewed li") assert items.first.text == product.name, "recently clicked product on top" assert len(items) == min(i, 5)
def _get_order(prices_include_tax=False, include_basket_campaign=False, include_catalog_campaign=False): shop = get_shop(prices_include_tax=prices_include_tax) supplier = get_simple_supplier() if include_basket_campaign: _add_basket_campaign(shop) if include_catalog_campaign: _add_catalog_campaign(shop) _add_taxes() source = BasketishOrderSource(shop) source.status = get_initial_order_status() ctx = get_pricing_module().get_context_from_data(shop, AnonymousContact()) for product_data in _get_product_data(): quantity = product_data.pop("quantity") product = create_product( sku=product_data.pop("sku"), shop=shop, supplier=supplier, stock_behavior=StockBehavior.STOCKED, tax_class=get_default_tax_class(), **product_data) shop_product = product.get_shop_instance(shop) shop_product.categories.add(get_default_category()) shop_product.save() supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY) pi = product.get_price_info(ctx) source.add_line( type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, base_unit_price=pi.base_unit_price, discount_amount=pi.discount_amount ) oc = OrderCreator() order = oc.create_order(source) return order
def test_slug_is_generate_from_translation(): activate("en") category = get_default_category() assert category.slug == slugify(category.name) default_slug = category.slug activate("fi") category.set_current_language("fi") name_fi = "Joku nimi" category.name = name_fi category.save() assert category.slug == slugify(name_fi) # Make sure english still have default slug activate("en") category.set_current_language("en") assert category.slug == default_slug # Make sure Japanese does not have translations generated # Check that slug is not generated to other languages with pytest.raises(ObjectDoesNotExist): translation = category.get_translation("ja") translation.refresh_from_db() # If the translation object was returned from cache
def test_mass_edit_products(rf, admin_user): shop = get_default_shop() supplier = get_default_supplier() product1 = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price="50") product2 = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price="501") category = get_default_category() shop_product1 = product1.get_shop_instance(shop) shop_product2 = product2.get_shop_instance(shop) # ensure no categories set assert shop_product1.primary_category is None assert shop_product2.primary_category is None request = apply_request_middleware(rf.post("/", data={"primary_category": category.pk}), user=admin_user) request.session["mass_action_ids"] = [shop_product1.pk, shop_product2.pk] view = ProductMassEditView.as_view() response = view(request=request) assert response.status_code == 302 for product in Product.objects.all(): assert product.get_shop_instance(shop).primary_category == category
def test_category_copy_visibility(rf, admin_user): shop = get_default_shop() group = get_default_customer_group() category = get_default_category() category.status = CategoryStatus.INVISIBLE category.visibility = CategoryVisibility.VISIBLE_TO_GROUPS category.shops.add(shop) category.visibility_groups.add(group) category.save() product = create_product("test_product", shop=shop) shop_product = product.get_shop_instance(shop) shop_product.primary_category = category shop_product.save() view = CategoryCopyVisibilityView.as_view() request = apply_request_middleware(rf.post("/"), user=admin_user) response = view(request, pk=category.pk) shop_product.refresh_from_db() assert response.status_code == 200 assert shop_product.visibility == ShopProductVisibility.NOT_VISIBLE assert shop_product.visibility_limit.value == category.visibility.value assert shop_product.visibility_groups.count() == category.visibility_groups.count() assert set(shop_product.visibility_groups.all()) == set(category.visibility_groups.all())
def test_category_products_effect_with_amount(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) category = get_default_category() supplier = get_default_supplier() single_product_price = "50" discount_amount_value = "10" quantity = 5 product = create_product("The product", shop=shop, supplier=supplier, default_price=single_product_price) shop_product = product.get_shop_instance(shop) shop_product.categories.add(category) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=quantity) basket.shipping_method = get_shipping_method(shop=shop) basket.save() rule = CategoryProductsBasketCondition.objects.create(operator=ComparisonOperator.EQUALS, quantity=quantity) rule.categories.add(category) campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test") campaign.conditions.add(rule) DiscountFromCategoryProducts.objects.create( campaign=campaign, category=category, discount_amount=discount_amount_value) assert rule.matches(basket, []) basket.uncache() final_lines = basket.get_final_lines() assert len(final_lines) == 2 # no new lines since the effect touches original lines expected_discount_amount = quantity * basket.create_price(discount_amount_value) original_price = basket.create_price(single_product_price) * quantity line = final_lines[0] assert line.discount_amount == expected_discount_amount assert basket.total_price == original_price - expected_discount_amount
def test_category_links_plugin_with_customer(rf, show_all_categories): """ Test plugin for categories that is visible for certain group """ shop = get_default_shop() group = get_default_customer_group() customer = create_random_person() customer.groups.add(group) customer.save() request = rf.get("/") request.shop = get_default_shop() apply_request_middleware(request) request.customer = customer category = get_default_category() category.status = CategoryStatus.VISIBLE category.visibility = CategoryVisibility.VISIBLE_TO_GROUPS category.visibility_groups.add(group) category.shops.add(shop) category.save() vars = {"request": request} context = get_jinja_context(**vars) plugin = CategoryLinksPlugin({ "categories": [category.pk], "show_all_categories": show_all_categories }) assert category.is_visible(customer) assert category in plugin.get_context_data(context)["categories"] customer_without_groups = create_random_person() customer_without_groups.groups.clear() assert not category.is_visible(customer_without_groups) request.customer = customer_without_groups context = get_jinja_context(**vars) assert category not in plugin.get_context_data(context)["categories"]
def test_products_form_remove_with_parent(): shop = get_default_shop() category = get_default_category() category.shops.add(shop) product = create_product("test_product", shop=shop, mode=ProductMode.SIMPLE_VARIATION_PARENT) shop_product = product.get_shop_instance(shop) shop_product.primary_category = category shop_product.save() shop_product.categories.add(category) child_product = create_product("child_product", shop=shop) child_product.link_to_parent(product) child_shop_product = child_product.get_shop_instance(shop) child_shop_product.primary_category = category child_shop_product.save() child_shop_product.categories.add(category) shop_product.refresh_from_db() assert (shop_product.primary_category == category) assert (shop_product.categories.count() == 1) assert (shop_product.categories.first() == category) assert (category.shop_products.count() == 2) data = { "remove_products": ["%s" % shop_product.id] } form = CategoryProductForm(shop=shop, category=category, data=data) form.full_clean() form.save() category.refresh_from_db() assert (category.shop_products.count() == 0) shop_product.refresh_from_db() assert (shop_product.primary_category is None) assert (shop_product.categories.count() == 0)
def test_products_for_category(): from shuup.front.template_helpers import general supplier = get_default_supplier() shop = get_default_shop() category = get_default_category() products = [create_product("sku-%d" % x, supplier=supplier, shop=shop) for x in range(2)] children = [create_product("SimpleVarChild-%d" % x, supplier=supplier, shop=shop) for x in range(2)] category.shops.add(shop) for child in children: child.link_to_parent(products[0]) context = get_jinja_context() for product in products: product.get_shop_instance(shop).categories.add(category) category_products = list(general.get_products_for_categories(context, [category])) assert len(category_products) == 2 assert products[0] in category_products assert products[1] in category_products
def test_manufacturer_filter_get_fields(rf): cache.clear() shop = factories.get_default_shop() request = apply_request_middleware(rf.get("/")) assert ManufacturerProductListFilter().get_fields(request, None) is None manufacturer = Manufacturer.objects.create(name="Random Brand Inc") assert ManufacturerProductListFilter().get_fields(request, None) is None category = factories.get_default_category() product = factories.create_product("sku", shop=shop) shop_product = product.get_shop_instance(shop=shop) shop_product.primary_category = category shop_product.save() assert ManufacturerProductListFilter().get_fields(request, category) is None # Now once we link manufacturer to product we should get # form field for manufacturer product.manufacturer = manufacturer product.save() form_field = ManufacturerProductListFilter().get_fields(request, category)[0][1] assert form_field is not None assert form_field.label == "Manufacturers" with override_settings( SHUUP_FRONT_OVERRIDE_SORTS_AND_FILTERS_LABELS_LOGIC={ "manufacturers": "Brands" }): form_field = ManufacturerProductListFilter().get_fields( request, category)[0][1] assert form_field is not None assert form_field.label == "Brands"
def test_category_detail(client): shop = factories.get_default_shop() # Activate show supplier info for front assert ThemeSettings.objects.count() == 1 theme_settings = ThemeSettings.objects.first() theme_settings.update_settings({"show_supplier_info": True}) # Activate supplier filters to prove they don't effect results # without actually filtering something. There is separate tests # to do the more closer tests. set_configuration( shop=shop, data={ "filter_products_by_supplier": True, "filter_products_by_supplier_ordering": 1, } ) category = factories.get_default_category() product_data = [ ("laptop", 1500), ("keyboard", 150), ("mouse", 150) ] products = [] for sku, price_value in product_data: products.append(factories.create_product(sku, shop=shop, default_price=price_value)) supplier_data = [ ("Johnny Inc", 0.5), ("Mike Inc", 0.9), ("Simon Inc", 0.8), ] for name, percentage_from_original_price in supplier_data: supplier = Supplier.objects.create(name=name) for product in products: shop_product = product.get_shop_instance(shop) shop_product.suppliers.add(supplier) shop_product.primary_category = category shop_product.save() supplier_price = ( percentage_from_original_price * [price for sku, price in product_data if product.sku == sku][0]) SupplierPrice.objects.create(supplier=supplier, shop=shop, product=product, amount_value=supplier_price) strategy = "shuup.testing.supplier_pricing.supplier_strategy:CheapestSupplierPriceSupplierStrategy" with override_settings(SHUUP_PRICING_MODULE="supplier_pricing", SHUUP_SHOP_PRODUCT_SUPPLIERS_STRATEGY=strategy): with override_current_theme_class(ClassicGrayTheme, shop): # Ensure settings is refreshed from DB soup = _get_category_detail_soup(client, category) # Johnny Inc has the best prices for everything laptop = [product for product in products if product.sku == "laptop"][0] laptop_product_box = soup.find("div", {"id": "product-%s" % laptop.pk}) _assert_supplier_info(laptop_product_box, "Johnny Inc") _assert_product_price(laptop_product_box, 750) keyboard = [product for product in products if product.sku == "keyboard"][0] keyboard_product_box = soup.find("div", {"id": "product-%s" % keyboard.pk}) _assert_supplier_info(keyboard_product_box, "Johnny Inc") _assert_product_price(keyboard_product_box, 75) mouse = [product for product in products if product.sku == "mouse"][0] mouse_product_box = soup.find("div", {"id": "product-%s" % mouse.pk}) _assert_supplier_info(mouse_product_box, "Johnny Inc") _assert_product_price(mouse_product_box, 75) # Ok competition has done it job and the other suppliers # has to start adjust their prices. # Let's say Mike has the cheapest laptop mike_supplier = Supplier.objects.filter(name="Mike Inc") SupplierPrice.objects.filter(supplier=mike_supplier, shop=shop, product=laptop).update(amount_value=333) soup = _get_category_detail_soup(client, category) laptop_product_box = soup.find("div", {"id": "product-%s" % laptop.pk}) _assert_supplier_info(laptop_product_box, "Mike Inc") _assert_product_price(laptop_product_box, 333) # Just to make sure Simon takes over the mouse biz simon_supplier = Supplier.objects.filter(name="Simon Inc") SupplierPrice.objects.filter(supplier=simon_supplier, shop=shop, product=mouse).update(amount_value=1) soup = _get_category_detail_soup(client, category) mouse_product_box = soup.find("div", {"id": "product-%s" % mouse.pk}) _assert_supplier_info(mouse_product_box, "Simon Inc") _assert_product_price(mouse_product_box, 1)
def test_many_price_info_cache_bump(rf): initial_price = 10 shop = factories.get_default_shop() tax = factories.get_default_tax() tax_class = factories.get_default_tax_class() product = factories.create_product( "product", shop=shop, supplier=factories.get_default_supplier(), default_price=initial_price ) child1 = factories.create_product("child1", shop=shop, supplier=factories.get_default_supplier(), default_price=5) child2 = factories.create_product("child2", shop=shop, supplier=factories.get_default_supplier(), default_price=9) child1.link_to_parent(product, variables={"color": "red"}) child2.link_to_parent(product, variables={"color": "blue"}) request = apply_request_middleware(rf.get("/")) child1_pi = child1.get_price_info(request) child2_pi = child1.get_price_info(request) def assert_cache_products(): cache_many_price_info(request, product, 1, [child1_pi, child2_pi]) assert get_many_cached_price_info(request, product, 1)[0].price == child1_pi.price assert get_many_cached_price_info(request, product, 1)[1].price == child2_pi.price def assert_nothing_is_cached(): # nothing is cached assert get_many_cached_price_info(request, product, 1) is None # cache the item assert_nothing_is_cached() assert_cache_products() # cache bumped - the cache should be dropped - then, cache again tax.save() assert_nothing_is_cached() assert_cache_products() # cache bumped - the cache should be dropped - then, cache again tax_class.save() assert_nothing_is_cached() assert_cache_products() # cache bumped - the cache should be dropped - then, cache again product.save() assert_nothing_is_cached() assert_cache_products() shop_product = product.get_shop_instance(shop) # cache bumped - the cache should be dropped - then, cache again shop_product.save() assert_nothing_is_cached() assert_cache_products() category = factories.get_default_category() # cache bumped - the cache should be dropped - then, cache again shop_product.categories.add(category) assert_nothing_is_cached() assert_cache_products() # cache bumped - the cache should be dropped - then, cache again supplier = shop_product.suppliers.first() supplier.enabled = False supplier.save() assert_nothing_is_cached() assert_cache_products()
def test_category_detail_multiselect_supplier_filters(client): shop = factories.get_default_shop() # Activate show supplier info for front assert ThemeSettings.objects.count() == 1 theme_settings = ThemeSettings.objects.first() theme_settings.update_settings({"show_supplier_info": True}) category = factories.get_default_category() # Important! Activate supplier filter. set_configuration(shop=shop, data={ "filter_products_by_supplier": True, "filter_products_by_supplier_ordering": 1, "filter_products_by_supplier_multiselect_enabled": True }) supplier_data = [ ("Johnny Inc", 0.5), ("Mike Inc", 0.9), ("Simon Inc", 0.8), ] for name, percentage_from_original_price in supplier_data: supplier = Supplier.objects.create(name=name) supplier.shops.add(shop) sku = name price_value = 10 product = factories.create_product(sku, shop=shop, default_price=price_value) shop_product = product.get_shop_instance(shop) shop_product.suppliers.add(supplier) shop_product.primary_category = category shop_product.categories.add(category) shop_product.save() supplier_price = (percentage_from_original_price * price_value) SupplierPrice.objects.create(supplier=supplier, shop=shop, product=product, amount_value=supplier_price) strategy = "shuup.testing.supplier_pricing.supplier_strategy:CheapestSupplierPriceSupplierStrategy" with override_settings(SHUUP_PRICING_MODULE="supplier_pricing", SHUUP_SHOP_PRODUCT_SUPPLIERS_STRATEGY=strategy): with override_current_theme_class( ClassicGrayTheme, shop): # Ensure settings is refreshed from DB johnny_supplier = Supplier.objects.filter( name="Johnny Inc").first() mike_supplier = Supplier.objects.filter(name="Mike Inc").first() simon_supplier = Supplier.objects.filter(name="Simon Inc").first() soup = _get_category_detail_soup_multiselect( client, category, [johnny_supplier.pk]) assert len(soup.findAll("div", {"class": "single-product"})) == 1 soup = _get_category_detail_soup_multiselect( client, category, [johnny_supplier.pk, mike_supplier.pk]) assert len(soup.findAll("div", {"class": "single-product"})) == 2 soup = _get_category_detail_soup_multiselect( client, category, [johnny_supplier.pk, mike_supplier.pk, simon_supplier.pk]) assert len(soup.findAll("div", {"class": "single-product"})) == 3
def test_product_price_range_filter(reindex_catalog): shop = factories.get_default_shop() product = factories.get_default_product() category = factories.get_default_category() shop_product = product.get_shop_instance(shop) shop_product.default_price_value = 10 shop_product.save() shop_product.categories.add(category) reindex_catalog() client = SmartClient() config = { "filter_products_by_price": True, "filter_products_by_price_range_min": 5, "filter_products_by_price_range_max": 15, "filter_products_by_price_range_size": 5, } set_configuration(category=category, data=config) url = reverse("shuup:category", kwargs={ "pk": category.pk, "slug": category.slug }) response, soup = client.response_and_soup(url) assert response.status_code == 200 assert soup.find(id="product-%d" % product.id) price_range_select = soup.find(id="id_price_range") # as the configuration is not set to override shop default configuration # this field shouldn't be there.. assert price_range_select is None # make the category configuration override the shop's default config config.update({"override_default_configuration": True}) set_configuration(category=category, data=config) url = reverse("shuup:category", kwargs={ "pk": category.pk, "slug": category.slug }) response, soup = client.response_and_soup(url) assert response.status_code == 200 assert soup.find(id="product-%d" % product.id) price_range_select = soup.find(id="id_price_range") price_ranges = price_range_select.find_all("option") assert len(price_ranges) == 4 # filter products with prices above $15 filtered_url = "{}?price_range={}".format(url, price_ranges[-1].attrs["value"]) response, soup = client.response_and_soup(filtered_url) assert response.status_code == 200 assert not soup.find(id="product-%d" % product.id) # explicitly disable the override config.update({"override_default_configuration": False}) set_configuration(category=category, data=config) url = reverse("shuup:category", kwargs={ "pk": category.pk, "slug": category.slug }) response, soup = client.response_and_soup(url) assert response.status_code == 200 assert soup.find(id="product-%d" % product.id) price_range_select = soup.find(id="id_price_range") assert price_range_select is None
def test_categories_shopproducts_manytomany(): shop_product = get_default_shop_product() category = get_default_category() category.shop_products.set([shop_product]) assert category.shop_products.first() == shop_product assert shop_product.categories.first() == category
def test_category_detail_filters(client): shop = factories.get_default_shop() # Activate show supplier info for front assert ThemeSettings.objects.count() == 1 theme_settings = ThemeSettings.objects.first() theme_settings.update_settings({"show_supplier_info": True}) category = factories.get_default_category() # Important! Activate supplier filter. set_configuration( shop=shop, data={ "filter_products_by_supplier": True, "filter_products_by_supplier_ordering": 1, }, ) product_data = [("laptop", 1500), ("keyboard", 150), ("mouse", 150)] products = [] for sku, price_value in product_data: products.append(factories.create_product(sku, shop=shop, default_price=price_value)) supplier_data = [ ("Johnny Inc", 0.5), ("Mike Inc", 0.9), ("Simon Inc", 0.8), ] for name, percentage_from_original_price in supplier_data: supplier = Supplier.objects.create(name=name) supplier.shops.add(shop) for product in products: shop_product = product.get_shop_instance(shop) shop_product.suppliers.add(supplier) shop_product.primary_category = category shop_product.categories.add(category) shop_product.save() supplier_price = ( percentage_from_original_price * [price for sku, price in product_data if product.sku == sku][0] ) SupplierPrice.objects.create(supplier=supplier, shop=shop, product=product, amount_value=supplier_price) strategy = "shuup.testing.supplier_pricing.supplier_strategy:CheapestSupplierPriceSupplierStrategy" with override_settings(SHUUP_PRICING_MODULE="supplier_pricing", SHUUP_SHOP_PRODUCT_SUPPLIERS_STRATEGY=strategy): with override_current_theme_class(ClassicGrayTheme, shop): # Ensure settings is refreshed from DB laptop = [product for product in products if product.sku == "laptop"][0] keyboard = [product for product in products if product.sku == "keyboard"][0] mouse = [product for product in products if product.sku == "mouse"][0] # Let's get products for Johnny supplier_johnny = Supplier.objects.filter(name="Johnny Inc").first() soup = _get_category_detail_soup(client, category, supplier_johnny.pk) laptop_product_box = soup.find("div", {"id": "product-%s" % laptop.pk}) _assert_supplier_info(laptop_product_box, "Johnny Inc") _assert_product_price(laptop_product_box, 750) # Now here when the category view is filtered based on supplier # the product urls should lead to supplier product url so we # can show details and prices for correct supplier. _assert_product_url(laptop_product_box, supplier_johnny, laptop) # Let's test rest of the products and suppliers keyboard_product_box = soup.find("div", {"id": "product-%s" % keyboard.pk}) _assert_supplier_info(keyboard_product_box, "Johnny Inc") _assert_product_price(keyboard_product_box, 75) _assert_product_url(keyboard_product_box, supplier_johnny, keyboard) mike_supplier = Supplier.objects.filter(name="Mike Inc").first() soup = _get_category_detail_soup(client, category, mike_supplier.pk) keyboard_product_box = soup.find("div", {"id": "product-%s" % keyboard.pk}) _assert_supplier_info(keyboard_product_box, "Mike Inc") _assert_product_price(keyboard_product_box, 135) _assert_product_url(keyboard_product_box, mike_supplier, keyboard) simon_supplier = Supplier.objects.filter(name="Simon Inc").first() soup = _get_category_detail_soup(client, category, simon_supplier.pk) mouse_product_box = soup.find("div", {"id": "product-%s" % mouse.pk}) _assert_supplier_info(mouse_product_box, "Simon Inc") _assert_product_price(mouse_product_box, 120) _assert_product_url(mouse_product_box, simon_supplier, mouse)
def test_catalog_campaign_sync(): shop = factories.get_default_shop() supplier = factories.get_default_supplier() default_price = 100 product1 = factories.create_product("test1", shop=shop, supplier=supplier, default_price=default_price) product2 = factories.create_product("test2", shop=shop, supplier=supplier, default_price=default_price) product3 = factories.create_product("test3", shop=shop, supplier=supplier, default_price=default_price) category = factories.get_default_category() shop_product = product1.get_shop_instance(shop) shop_product.primary_category = category shop_product.save() shop_product.categories.add(category) contact1 = factories.create_random_person() contact2 = factories.create_random_person() contact_group = factories.get_default_customer_group() contact2.groups.add(contact_group) happy_hour1_weekdays = "0,1" # Mon, Tue happy_hour1_start = datetime.time(21) happy_hour1_end = datetime.time(3) happy_hour1_condition = HourCondition.objects.create( days=happy_hour1_weekdays, hour_start=happy_hour1_start, hour_end=happy_hour1_end) happy_hour2_weekdays = "2,6" # Wed, Sun happy_hour2_start = datetime.time(14) happy_hour2_end = datetime.time(16) happy_hour2_condition = HourCondition.objects.create( days=happy_hour2_weekdays, hour_start=happy_hour2_start, hour_end=happy_hour2_end) discount_amount_value = 50 discount_percentage = decimal.Decimal("0.35") _create_catalog_campaign_for_products(shop, [product1], discount_amount_value, happy_hour1_condition) _create_catalog_campaign_for_products(shop, [product2, product3], discount_amount_value) _create_catalog_campaign_for_category(shop, category, discount_percentage) _create_catalog_campaign_for_contact(shop, product1, contact1, discount_amount_value) _create_catalog_campaign_for_contact_group(shop, [product1, product2, product3], contact_group, discount_percentage, happy_hour2_condition) call_command("import_catalog_campaigns", *[], **{}) # From first campaign we should get 1 discount with happy hour # From second campaign we should get 2 discounts # From third campaign we should get 1 discount # From fourth campaign we should get also 1 discount # From last campaign we should get 3 discounts with happy hour assert Discount.objects.count() == 8 # There should be 2 happy hours in total assert HappyHour.objects.count() == 2 # From first happy hour there should be 4 ranges # Mon 21-23, Tue 0-3, Tue 21-23, Wed 0-3 # From second happy hour there should be 2 ranges # Wed 14-16 and Sun 14-16 assert TimeRange.objects.count() == 6 # Let's go through all our 8 discounts to make sure all is good first_discount = Discount.objects.filter( product=product1, category__isnull=True, contact__isnull=True, contact_group__isnull=True).first() assert first_discount.happy_hours.count() == 1 assert first_discount.discount_amount_value == discount_amount_value second_discount = Discount.objects.filter( product=product2, category__isnull=True, contact__isnull=True, contact_group__isnull=True).first() assert second_discount.happy_hours.count() == 0 assert second_discount.discount_amount_value == discount_amount_value third_discount = Discount.objects.filter( product=product3, category__isnull=True, contact__isnull=True, contact_group__isnull=True).first() assert third_discount.happy_hours.count() == 0 assert third_discount.discount_amount_value == discount_amount_value category_discount = Discount.objects.filter( product__isnull=True, category=category, contact__isnull=True, contact_group__isnull=True).first() assert category_discount.happy_hours.count() == 0 assert category_discount.discount_percentage == discount_percentage contact_discount = Discount.objects.filter( product=product1, category__isnull=True, contact=contact1, contact_group__isnull=True).first() assert contact_discount.discount_amount_value == discount_amount_value product1_contact_group_discount = Discount.objects.filter( product=product1, category__isnull=True, contact__isnull=True, contact_group=contact_group).first() assert product1_contact_group_discount.happy_hours.count() == 1 assert product1_contact_group_discount.discount_percentage == discount_percentage product2_contact_group_discount = Discount.objects.filter( product=product2, category__isnull=True, contact__isnull=True, contact_group=contact_group).first() assert product2_contact_group_discount.happy_hours.count() == 1 assert product2_contact_group_discount.discount_percentage == discount_percentage product3_contact_group_discount = Discount.objects.filter( product=product3, category__isnull=True, contact__isnull=True, contact_group=contact_group).first() assert product3_contact_group_discount.happy_hours.count() == 1 assert product3_contact_group_discount.discount_percentage == discount_percentage
def _add_catalog_campaign(shop): campaign = CatalogCampaign.objects.create(shop=shop, name="test", public_name="test", active=True) category_filter = CategoryFilter.objects.create() category_filter.categories.add(get_default_category()) category_filter.save() ProductDiscountAmount.objects.create(campaign=campaign, discount_amount=5)
def test_product_from_category_plugin(rf): shop = get_default_shop() category1 = get_default_category() category2 = CategoryFactory(status=CategoryStatus.VISIBLE) category1.shops.add(shop) category2.shops.add(shop) p1 = create_product("p1", shop, get_default_supplier(), "10") p2 = create_product("p2", shop, get_default_supplier(), "20") p3 = create_product("p3", shop, get_default_supplier(), "30") sp1 = p1.get_shop_instance(shop) sp2 = p2.get_shop_instance(shop) sp3 = p3.get_shop_instance(shop) sp1.categories.add(category1) sp2.categories.add(category1) sp3.categories.add(category2) plugin = ProductsFromCategoryPlugin({ "category": category1.pk, "cache_timeout": 120 }) plugin_context = plugin.get_context_data(get_context(rf, is_ajax=False)) context_products = plugin_context["products"] assert len(context_products) == 0 plugin_context = plugin.get_context_data(get_context(rf)) context_data_url = plugin_context["data_url"] context_products = plugin_context["products"] assert p1 in context_products assert p2 in context_products assert p3 not in context_products check_expected_product_count(context_data_url, 2) check_expected_product_count(context_data_url, 2) # one for checking it is cached # test the plugin form with override_current_theme_class(None): theme = get_current_theme(get_default_shop()) cell = LayoutCell(theme, ProductsFromCategoryPlugin.identifier, sizes={"md": 8}) lcfg = LayoutCellFormGroup(layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/"))) assert not lcfg.is_valid() lcfg = LayoutCellFormGroup( data={ "general-cell_width": "8", "general-cell_align": "pull-right", "plugin-count": 4, "plugin-category": category2.pk, "plugin-cache_timeout": 3600 }, layout_cell=cell, theme=theme, request=apply_request_middleware(rf.get("/")) ) assert lcfg.is_valid() lcfg.save() assert cell.config["category"] == str(category2.pk)