def test_summernote_editor_picture(browser, admin_user, live_server, settings): activate("en") factories.get_default_shop() factories.get_default_product_type() factories.get_default_sales_unit() factories.get_default_tax_class() filer_image = factories.get_random_filer_image() initialize_admin_browser_test(browser, live_server, settings) browser.driver.set_window_size(1920, 1080) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, condition=lambda x: x.is_text_present("New shop product")) img_icon_selector = "#id_base-description__en-editor-wrap i[class='note-icon-picture']" move_to_element(browser, img_icon_selector) click_element(browser, img_icon_selector) 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] # make sure the image was added to the editor wait_until_appeared( browser, "#id_base-description__en-editor-wrap .note-editable img[src='%s']" % filer_image.url, timeout=20 )
def test_product_create(browser, admin_user, live_server): activate("en") shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() object_created.connect(_add_custom_product_created_message, sender=Product, dispatch_uid="object_created_signal_test") initialize_admin_browser_test(browser, live_server) url = reverse("shuup_admin:product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("shop%s-default_price_value" % shop.pk, price_value) click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") product = Product.objects.filter(sku=sku).first() assert product.log_entries.filter( identifier=OBJECT_CREATED_LOG_IDENTIFIER).count() == 1 object_created.disconnect(sender=Product, dispatch_uid="object_created_signal_test")
def test_product_create(browser, admin_user, live_server, settings): activate("en") shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() configuration.set(None, "shuup_product_tour_complete", True) object_created.connect(_add_custom_product_created_message, sender=Product, dispatch_uid="object_created_signal_test") initialize_admin_browser_test(browser, live_server, settings) browser.driver.set_window_size(1920, 1080) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) configuration.set(None, "shuup_category_tour_complete", True) _add_primary_category(browser, shop) _add_additional_category(browser, shop) click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") product = Product.objects.filter(sku=sku).first() assert product.log_entries.filter(identifier=OBJECT_CREATED_LOG_IDENTIFIER).count() == 1 object_created.disconnect(sender=Product, dispatch_uid="object_created_signal_test") shop_product = product.get_shop_instance(shop) assert shop_product.categories.count() == 2
def test_sample_import_shop_relation(rf): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", "complex_import.xlsx") transformed_data = transform_file("xlsx", path) importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en")) importer.process_data() importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects for product in products: shop_product = product.get_shop_instance(shop) for category in shop_product.categories.all(): assert shop in category.shops.all() if product.manufacturer: assert shop in product.manufacturer.shops.all()
def import_categoryfile(filename, expected_category_count, map_from=None, map_to=None): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_supplier() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() if map_from: assert len(importer.unmatched_fields) == 1 assert map_from in importer.unmatched_fields importer.manually_match(map_from, map_to) importer.do_remap() else: assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert Category.objects.count() == expected_category_count
def test_admin(rf, admin_user): activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) get_default_tax_class() get_default_product_type() get_default_sales_unit() client = do_importing("123", "test", "en", shop) # change import language and update product client = do_importing("123", "test-fi", "fi", shop, client=client) # update name in english client = do_importing("123", "test-en", "en", shop, client=client) # cannot update client = do_importing("123", "test", "en", shop, import_mode=ImportMode.CREATE, client=client) # can update do_importing("123", "test", "en", shop, import_mode=ImportMode.UPDATE, client=client)
def test_product_create(browser, admin_user, live_server, settings): activate("en") shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() configuration.set(None, "shuup_product_tour_complete", True) object_created.connect(_add_custom_product_created_message, sender=Product, dispatch_uid="object_created_signal_test") initialize_admin_browser_test(browser, live_server, settings) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) configuration.set(None, "shuup_category_tour_complete", True) _add_primary_category(browser, shop) _add_additional_category(browser, shop) click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") product = Product.objects.filter(sku=sku).first() assert product.log_entries.filter(identifier=OBJECT_CREATED_LOG_IDENTIFIER).count() == 1 object_created.disconnect(sender=Product, dispatch_uid="object_created_signal_test") shop_product = product.get_shop_instance(shop) assert shop_product.categories.count() == 2
def test_complex_import(rf): filename = "complex_import.xlsx" activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_supplier() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en")) importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 6 assert ShopProduct.objects.count() == 6 assert Category.objects.count() == 11 assert Manufacturer.objects.count() == 4 for idx, product in enumerate(Product.objects.all().order_by("sku")): shop_product = product.get_shop_instance(shop) data = PRODUCT_DATA[idx] assert product.sku == data["sku"] assert product.name == data["name"] assert shop_product.default_price_value == Decimal(data["price"]) assert product.description == data["description"] if data.get("categories"): all_cats = set(data["categories"]) all_cats.add(data["category"]) for cat in shop_product.categories.all(): assert cat.name in all_cats assert shop_product.categories.count() == len( all_cats) # also add primary category if data.get("category"): assert shop_product.primary_category.name == data["category"] assert force_text( shop_product.visibility.label) == data["visibility"].lower() assert product.tax_class.name == data["tax_class"] if data.get("manufacturer"): assert product.manufacturer.name == data["manufacturer"]
def test_quick_add(browser, admin_user, live_server, settings): shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() configuration.set(None, "shuup_product_tour_complete", True) initialize_admin_browser_test(browser, live_server, settings) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) configuration.set(None, "shuup_category_tour_complete", True) wait_until_appeared(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) click_element(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") with browser.get_iframe('create-object-iframe') as iframe: assert Category.objects.count() == 0 wait_until_appeared(iframe, "input[name='base-name__en']") iframe.fill("base-name__en", "Test Category") time.sleep(3) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(browser, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.count() == 1, timeout=20) assert Category.objects.first().name == "Test Category" # click to edit the button click_element(browser, "#id_shop%d-primary_category ~ .edit-object-btn a.btn" % shop.id) with browser.get_iframe('create-object-iframe') as iframe: wait_until_appeared(iframe, "input[name='base-name__en']") new_cat_name = "Changed Name" iframe.fill("base-name__en", new_cat_name) time.sleep(3) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(iframe, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.first().name == new_cat_name, timeout=20) click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']")
def test_product_create(browser, admin_user, live_server, settings): activate("en") shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() object_created.connect(_add_custom_product_created_message, sender=Product, dispatch_uid="object_created_signal_test") initialize_admin_browser_test(browser, live_server, settings) original_size = browser.driver.get_window_size() browser.driver.set_window_size(1920, 1080) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) wait_until_condition( browser, condition=lambda x: x.is_text_present("New shop product")) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" move_to_element(browser, "#id_base-sku") browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) _add_primary_category(browser, shop) _add_additional_category(browser, shop) move_to_element(browser, "button[form='product_form']") try: click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") except selenium.common.exceptions.WebDriverException as e: # TODO: Revise! # Give a product save second chance it seems that the save can # lag a little and the success message doesn't happen fast # enough every single time. click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") product = Product.objects.filter(sku=sku).first() assert product.log_entries.filter( identifier=OBJECT_CREATED_LOG_IDENTIFIER).count() == 1 object_created.disconnect(sender=Product, dispatch_uid="object_created_signal_test") shop_product = product.get_shop_instance(shop) assert shop_product.categories.count() == 2 browser.driver.set_window_size(original_size["width"], original_size["height"])
def test_quick_add(browser, admin_user, live_server, settings): shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() initialize_admin_browser_test(browser, live_server, settings) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) wait_until_appeared(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) click_element(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") with browser.get_iframe('create-object-iframe') as iframe: assert Category.objects.count() == 0 wait_until_appeared(iframe, "input[name='base-name__en']") iframe.fill("base-name__en", "Test Category") time.sleep(3) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(browser, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.count() == 1, timeout=20) assert Category.objects.first().name == "Test Category" # click to edit the button click_element(browser, "#id_shop%d-primary_category ~ .edit-object-btn a.btn" % shop.id) with browser.get_iframe('create-object-iframe') as iframe: wait_until_appeared(iframe, "input[name='base-name__en']") new_cat_name = "Changed Name" iframe.fill("base-name__en", new_cat_name) time.sleep(3) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(iframe, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.first().name == new_cat_name, timeout=20) click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']")
def test_complex_import(): filename = "complex_import.xlsx" activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_supplier() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 6 assert ShopProduct.objects.count() == 6 assert Category.objects.count() == 11 assert Manufacturer.objects.count() == 4 for idx, product in enumerate(Product.objects.all().order_by("sku")): shop_product = product.get_shop_instance(shop) data = PRODUCT_DATA[idx] assert product.sku == data["sku"] assert product.name == data["name"] assert shop_product.default_price_value == Decimal(data["price"]) assert product.description == data["description"] if data.get("categories"): all_cats = set(data["categories"]) all_cats.add(data["category"]) for cat in shop_product.categories.all(): assert cat.name in all_cats assert shop_product.categories.count() == len(all_cats) # also add primary category if data.get("category"): assert shop_product.primary_category.name == data["category"] assert force_text(shop_product.visibility.label) == data["visibility"].lower() assert product.tax_class.name == data["tax_class"] if data.get("manufacturer"): assert product.manufacturer.name == data["manufacturer"]
def test_sample_ignore_column(): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", "sample_import_ignore.csv") transformed_data = transform_file("csv", path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 2
def test_sample_ignore_column(): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", "sample_import_ignore.csv") transformed_data = transform_file("csv", path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 2
def test_sample_import_no_match(stock_managed): filename = "sample_import_nomatch.xlsx" if "shuup.simple_supplier" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS") from shuup_tests.simple_supplier.utils import get_simple_supplier activate("en") shop = get_default_shop() tax_class = get_default_tax_class() product_type = get_default_product_type() supplier = get_simple_supplier(stock_managed) sales_unit = get_default_sales_unit() Manufacturer.objects.create(name="manufctr") path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() assert len(importer.unmatched_fields) == 1 assert "gtiin" in importer.unmatched_fields importer.manually_match("gtiin", "shuup.core.models.Product:gtin") importer.do_remap() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 2 for product in products: assert product.gtin == "1280x720" shop_product = product.get_shop_instance(shop) assert shop_product.pk assert shop_product.default_price_value == 150 assert shop_product.default_price == shop.create_price(150) assert product.type == product_type # product type comes from importer defaults assert product.sales_unit == sales_unit if product.pk == 1: assert product.tax_class.pk == 2 # new was created assert product.name == "Product English" assert product.description == "Description English" else: assert product.tax_class.pk == tax_class.pk # old was found as should assert product.name == "Product 2 English" assert product.description == "Description English 2" assert shop_product.primary_category.pk == 1 assert [c.pk for c in shop_product.categories.all()] == [1, 2] # stock was not managed since supplier doesn't like that for msg in importer.other_log_messages: assert "please set Stock Managed on" in msg supplier.stock_managed = True supplier.save() importer.do_import("create,update") assert len(importer.other_log_messages) == 0 for sa in StockAdjustment.objects.all(): assert sa.product.pk assert sa.delta == 20
def test_sample_import_no_match(stock_managed): filename = "sample_import_nomatch.xlsx" if "shuup.simple_supplier" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS") from shuup_tests.simple_supplier.utils import get_simple_supplier activate("en") shop = get_default_shop() tax_class = get_default_tax_class() product_type = get_default_product_type() supplier = get_simple_supplier(stock_managed) sales_unit = get_default_sales_unit() Manufacturer.objects.create(name="manufctr") path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() assert len(importer.unmatched_fields) == 1 assert "gtiin" in importer.unmatched_fields importer.manually_match("gtiin", "shuup.core.models.Product:gtin") importer.do_remap() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 2 for product in products: assert product.gtin == "1280x720" shop_product = product.get_shop_instance(shop) assert shop_product.pk assert shop_product.default_price_value == 150 assert shop_product.default_price == shop.create_price(150) assert product.type == product_type # product type comes from importer defaults assert product.sales_unit == sales_unit if product.pk == 1: assert product.tax_class.pk == 2 # new was created assert product.name == "Product English" assert product.description == "Description English" else: assert product.tax_class.pk == tax_class.pk # old was found as should assert product.name == "Product 2 English" assert product.description == "Description English 2" assert shop_product.primary_category.pk == 1 assert [c.pk for c in shop_product.categories.all()] == [1,2] # stock was not managed since supplier doesn't like that for msg in importer.other_log_messages: assert "please set Stock Managed on" in msg supplier.stock_managed = True supplier.save() importer.do_import("create,update") assert len(importer.other_log_messages) == 0 for sa in StockAdjustment.objects.all(): assert sa.product.pk assert sa.delta == 20
def test_custom_file_transformer_import(admin_user): shop = get_default_shop() shop.staff_members.add(admin_user) get_default_tax_class() get_default_product_type() get_default_sales_unit() client = SmartClient() client.login(username="******", password="******") import_path = reverse("shuup_admin:importer.import.new") process_path = reverse("shuup_admin:importer.import_process") client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name\n123;Teste") data = { "importer": "product_importer", "shop": shop.pk, "language": "en", "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv"), } response = client.post(import_path, data=data) assert response.status_code == 302 with mock.patch.object(ProductImporter, "custom_file_transformer", True): assert ProductImporter.custom_file_transformer is True query_string = urlparse(response["location"]).query process_submit_path = "%s?%s" % (process_path, query_string) query = parse_qs(query_string) data = { "importer": "product_importer", "shop": shop.pk, "language": "en", "n": query.get("n"), } response = client.post(process_submit_path, data=data) assert response.status_code == 302 assert "The import was queued!" in list( response.wsgi_request._messages)[0].message task_execution = BackgroundTaskExecution.objects.last() assert task_execution.status == BackgroundTaskExecutionStatus.ERROR assert "Error! Not implemented: `DataImporter` -> `transform_file()`." in task_execution.error_log
def test_import_error(admin_user): shop = get_default_shop() shop.staff_members.add(admin_user) get_default_tax_class() get_default_product_type() get_default_sales_unit() client = SmartClient() client.login(username="******", password="******") import_path = reverse("shuup_admin:importer.import") process_path = reverse("shuup_admin:importer.import_process") client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name\n123;Teste") data = { "importer": "product_importer", "shop": shop.pk, "language": "en", "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv") } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query query = parse_qs(query_string) data = { "importer": "product_importer", "shop": shop.pk, "language": "en", "n": query.get("n"), } data = {} process_submit_path = "%s?%s" % (process_path, query_string) response = client.post(process_submit_path, data=data) assert response.status_code == 302 assert "Failed to import the file." == list( response.wsgi_request._messages)[0].message
def test_invalid_files(rf, admin_user): lang = "en" import_mode = ImportMode.CREATE_UPDATE sku = "123" name = "test" import_path = reverse("shuup_admin:importer.import") process_path = reverse("shuup_admin:importer.import_process") tax_class = get_default_tax_class() product_type = get_default_product_type() get_default_sales_unit() activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name\n%s;%s" % (sku, name)) # show import view data = { "importer": "product_importer", "shop": shop.pk, "language": lang, "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv") } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query query = parse_qs(query_string) data = { # data with missing `n` "importer": "product_importer", "shop": shop.pk, "language": lang, } response, soup = client.response_and_soup(process_path, data=data) assert response.status_code == 400 assert "File missing." in str(soup)
def test_product_create(browser, admin_user, live_server, settings): activate("en") shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() object_created.connect(_add_custom_product_created_message, sender=Product, dispatch_uid="object_created_signal_test") initialize_admin_browser_test(browser, live_server, settings) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, condition=lambda x: x.is_text_present("New shop product")) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" move_to_element(browser, "#id_base-sku") browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) _add_primary_category(browser, shop) _add_additional_category(browser, shop) move_to_element(browser, "button[form='product_form']") try: click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") except selenium.common.exceptions.WebDriverException as e: # TODO: Revise! # Give a product save second chance it seems that the save can # lag a little and the success message doesn't happen fast # enough every single time. click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") product = Product.objects.filter(sku=sku).first() assert product.log_entries.filter(identifier=OBJECT_CREATED_LOG_IDENTIFIER).count() == 1 object_created.disconnect(sender=Product, dispatch_uid="object_created_signal_test") shop_product = product.get_shop_instance(shop) assert shop_product.categories.count() == 2
def test_admin(rf, admin_user): activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) get_default_tax_class() get_default_product_type() get_default_sales_unit() client = do_importing("123", "test", "en", shop) # change import language and update product client = do_importing("123", "test-fi", "fi", shop, client=client) # update name in english client = do_importing("123", "test-en", "en", shop, client=client) # cannot update client = do_importing("123", "test", "en", shop, import_mode=ImportMode.CREATE, client=client) # can update do_importing("123", "test", "en", shop, import_mode=ImportMode.UPDATE, client=client)
def test_admin_views(rf, admin_user): # list imports activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) get_default_tax_class() get_default_product_type() get_default_sales_unit() # list imports, should be blank list_view_func = ImportListView.as_view() detail_view_func = ImportDetailView.as_view() payload = {"jq": json.dumps({"perPage": 100, "page": 1}), "shop": shop.pk} request = apply_request_middleware(rf.get("/", data=payload), user=admin_user) response = list_view_func(request) assert response.status_code == 200 assert len(json.loads(response.content)["items"]) == 0 # import a product do_importing("123", "test", "en", shop) # should contain 1 successfull import response = list_view_func(request) assert response.status_code == 200 data = json.loads(response.content) assert len(data["items"]) == 1 assert data["items"][0]["importer"] == "Product Importer" assert data["items"][0]["status"] == "Success" # check the details of the import request = apply_request_middleware(rf.get("/"), user=admin_user) response = detail_view_func(request, pk=data["items"][0]["_id"]) assert response.status_code == 200 response.render() template = response.content.decode("utf-8") assert "Import Results" in template assert "The following items were imported as new" in template assert ">test</a>" in template assert "Zero items were updated" in template
def test_sample_import_images_errors(rf): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", "sample_import_images_error.csv") transformed_data = transform_file("csv", path) importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en") ) importer.process_data() importer.do_import(ImportMode.CREATE_UPDATE) assert len(importer.log_messages) == 2 products = importer.new_objects assert len(products) == 2 for product in products: assert not product.media.exists()
def test_sample_import_shop_relation(): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", "complex_import.xlsx") transformed_data = transform_file("xlsx", path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects for product in products: shop_product = product.get_shop_instance(shop) for category in shop_product.categories.all(): assert shop in category.shops.all() if product.manufacturer: assert shop in product.manufacturer.shops.all()
def test_summernote_editor_picture(browser, admin_user, live_server, settings): activate("en") factories.get_default_shop() factories.get_default_product_type() factories.get_default_sales_unit() factories.get_default_tax_class() filer_image = factories.get_random_filer_image() configuration.set(None, "shuup_product_tour_complete", True) initialize_admin_browser_test(browser, live_server, settings) browser.driver.set_window_size(1920, 1080) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) wait_until_appeared( browser, "#id_base-description__en-editor-wrap button[aria-label='Picture']") click_element( browser, "#id_base-description__en-editor-wrap button[aria-label='Picture']") 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] # make sure the image was added to the editor wait_until_appeared( browser, "#id_base-description__en-editor-wrap .note-editable img[src='%s']" % filer_image.url, timeout=20)
def import_categoryfile(filename, expected_category_count, map_from=None, map_to=None): activate("en") shop = get_default_shop() get_default_tax_class() get_default_product_type() get_default_supplier() get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() if map_from: assert len(importer.unmatched_fields) == 1 assert map_from in importer.unmatched_fields importer.manually_match(map_from, map_to) importer.do_remap() else: assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert Category.objects.count() == expected_category_count
def test_invalid_files(rf, admin_user): lang = "en" import_mode = ImportMode.CREATE_UPDATE sku = "123" name = "test" import_path = reverse("shuup_admin:importer.import") process_path = reverse("shuup_admin:importer.import_process") tax_class = get_default_tax_class() product_type = get_default_product_type() get_default_sales_unit() activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name\n%s;%s" % (sku, name)) # show import view data = { "importer": "product_importer", "shop": shop.pk, "language": lang, "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv") } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query query = parse_qs(query_string) data = { # data with missing `n` "importer": "product_importer", "shop": shop.pk, "language": lang, } response, soup = client.response_and_soup(process_path, data=data) assert response.status_code == 400 assert "File missing." in str(soup)
def test_import_error(admin_user): shop = get_default_shop() shop.staff_members.add(admin_user) get_default_tax_class() get_default_product_type() get_default_sales_unit() client = SmartClient() client.login(username="******", password="******") import_path = reverse("shuup_admin:importer.import") process_path = reverse("shuup_admin:importer.import_process") client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name\n123;Teste") data = { "importer": "product_importer", "shop": shop.pk, "language": "en", "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv") } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query query = parse_qs(query_string) data = { "importer": "product_importer", "shop": shop.pk, "language": "en", "n": query.get("n"), } data = {} process_submit_path = "%s?%s" % (process_path, query_string) response = client.post(process_submit_path, data=data) assert response.status_code == 302 assert "Failed to import the file." == list(response.wsgi_request._messages)[0].message
def test_new_shop_product_suppliers_init(rf, admin_user, multiple_suppliers): with override_settings(SHUUP_ENABLE_MULTIPLE_SUPPLIERS=multiple_suppliers): shop = get_default_shop() supplier = get_default_supplier() tax_class = get_default_tax_class() product_type = get_default_product_type() sales_unit = get_default_sales_unit() assert ShopProduct.objects.count() == 0 client = SmartClient() client.login(username="******", password="******") soup = client.soup(reverse("shuup_admin:shop_product.new")) supplier_select = soup.find("select", attrs={"name": "shop%s-suppliers" % shop.id}) assert len(supplier_select.find_all("option")) == (0 if multiple_suppliers else 1)
def test_import(): factories.get_default_product_type() factories.get_default_sales_unit() tax_class = factories.get_default_tax_class() shop = factories.get_default_shop() shop_domain = "test" shop.domain = shop_domain shop.save() supplier = factories.get_default_supplier() supplier.shops = [shop] assert shop.domain == shop_domain args = [ "--shop-domain", shop_domain, "--data-path", os.path.join(os.path.dirname(__file__), "..", "data"), "--language", "en", "--tax-class", tax_class.identifier, "--no-dry-run" ] management.call_command("import_yaml", *args, **{}) assert Category.objects.count() == 18 assert Manufacturer.objects.count() == 71 assert Product.objects.count() == 143 assert Product.objects.filter(shop_products__shop=shop).count() == 143 _test_product(shop, "08712942000P", "Dog Supplies", ["Dog Food"], "Pedigree") _test_product(shop, "029W002479034000", "Dog Supplies", ["Dog Collars, Harnesses and Leashes"], "Champion Breed") _test_product(shop, "SPM9885958922", "Cat Supplies", ["Litter Boxes and Accessories"], "Trixie Pet Products") assert ProductMedia.objects.filter( shops=shop).count() == Product.objects.count()
def test_sample_import_all_match_all_shops(filename, rf): activate("en") shop1 = get_shop(identifier="shop1", domain="shop1", enabled=True) shop2 = get_shop(identifier="shop2", domain="shop2", enabled=True) Product.objects.all().delete() tax_class = get_default_tax_class() product_type = get_default_product_type() sales_unit = get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) for shop in [shop1, shop2]: importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en")) importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects if shop == shop1: # products created assert len(products) == 2 else: # products already exist assert len(products) == 0 assert Product.objects.count() == 2 for product in Product.objects.all(): shop_product = product.get_shop_instance(shop) assert shop_product.pk assert shop_product.default_price_value == 150 assert shop_product.default_price == shop.create_price(150) assert product.type == product_type # product type comes from importer defaults assert product.sales_unit == sales_unit assert shop_product.primary_category.pk == 1 assert [c.pk for c in shop_product.categories.all()] == [1, 2] assert ShopProduct.objects.count() == 4
def test_sample_import_all_match_all_shops(filename): activate("en") shop1 = get_shop(identifier="shop1", domain="shop1", enabled=True) shop2 = get_shop(identifier="shop2", domain="shop2", enabled=True) Product.objects.all().delete() tax_class = get_default_tax_class() product_type = get_default_product_type() sales_unit = get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) for shop in [shop1, shop2]: importer = ProductImporter(transformed_data, shop, "en") importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects if shop == shop1: # products created assert len(products) == 2 else: # products already exist assert len(products) == 0 assert Product.objects.count() == 2 for product in Product.objects.all(): shop_product = product.get_shop_instance(shop) assert shop_product.pk assert shop_product.default_price_value == 150 assert shop_product.default_price == shop.create_price(150) assert product.type == product_type # product type comes from importer defaults assert product.sales_unit == sales_unit assert shop_product.primary_category.pk == 1 assert [c.pk for c in shop_product.categories.all()] == [1, 2] assert ShopProduct.objects.count() == 4
def _get_product_sample_data(): return { # translations "translations": { "en": { "name": "Product Name", "description": "Product Description", "slug": "product_sku", "keywords": "keyword1, k3yw0rd2", "status_text": "available soon", "variation_name": "Product RED" }, "pt-br": { "name": "Nome do Produto", "description": "Descrição do Produto", "slug": "product_sku_em_portugues", "keywords": "chave1, chavez2", "status_text": "disponivel logo", "variation_name": "Produto Vermelho" } }, # others "stock_behavior": StockBehavior.STOCKED.value, "shipping_mode": ShippingMode.SHIPPED.value, "sales_unit": get_default_sales_unit().pk, "tax_class": get_default_tax_class().pk, "type": get_default_product_type().pk, "sku": "sku12345", "gtin": "789456132", "barcode": "7896899123456", "accounting_identifier": "cbe6a7d67a8bdae", "profit_center": "prooofit!", "cost_center": "space ghost", "width": 150.0, "height": 230.0, "depth": 450.4, "net_weight": 13.2, "gross_weight": 20.3 }
def _get_product_sample_data(): return { # translations "translations":{ "en": { "name": "Product Name", "description": "Product Description", "slug": "product_sku", "keywords": "keyword1, k3yw0rd2", "status_text": "available soon", "variation_name": "Product RED" }, "pt-br": { "name": "Nome do Produto", "description": "Descrição do Produto", "slug": "product_sku_em_portugues", "keywords": "chave1, chavez2", "status_text": "disponivel logo", "variation_name": "Produto Vermelho" } }, # others "stock_behavior": StockBehavior.STOCKED.value, "shipping_mode": ShippingMode.SHIPPED.value, "sales_unit": get_default_sales_unit().pk, "tax_class": get_default_tax_class().pk, "type": get_default_product_type().pk, "sku": "sku12345", "gtin": "789456132", "barcode": "7896899123456", "accounting_identifier": "cbe6a7d67a8bdae", "profit_center": "prooofit!", "cost_center": "space ghost", "width": 150.0, "height": 230.0, "depth": 450.4, "net_weight": 13.2, "gross_weight": 20.3 }
def test_invalid_file_type(rf, admin_user): lang = "en" import_mode = ImportMode.CREATE_UPDATE sku = "123" name = "test" import_path = reverse("shuup_admin:importer.import.new") process_path = reverse("shuup_admin:importer.import_process") get_default_tax_class() get_default_product_type() get_default_sales_unit() activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name\n%s;%s" % (sku, name)) # show import view data = { "importer": "product_importer", "shop": shop.pk, "language": lang, "file": SimpleUploadedFile("file.derp", csv_content, content_type="text/csv"), } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query data = { # data with missing `n` "importer": "product_importer", "shop": shop.pk, "language": lang, } response, soup = client.response_and_soup(process_path, data=data) assert response.status_code == 400 for row in soup.findAll("tr"): first_td = row.find("td") if not first_td: continue tds = row.findAll("td") if len(tds) < 2: continue second_td = tds[1] if first_td.text.startswith("Connection"): # check that sku was connected badges = second_td.findAll("span", {"class": "badge"}) assert len(badges) == 1 assert badges[0].text == "sku" elif first_td.text.startswith("The following fields"): badges = second_td.findAll("span", {"class": "badge"}) assert len(badges) == 2 badge_texts = [] for b in badges: badge_texts.append(b.text) badge_texts.sort() assert badge_texts[0] == "name" assert badge_texts[1] == "sku" data = {} data["import_mode"] = import_mode.value process_submit_path = "%s?%s" % (process_path, query_string) response = client.post(process_submit_path, data=data) assert response.status_code == 302
def test_remap(rf, admin_user): lang = "en" import_mode = ImportMode.CREATE_UPDATE sku = "123" name = "test" import_path = reverse("shuup_admin:importer.import") process_path = reverse("shuup_admin:importer.import_process") tax_class = get_default_tax_class() product_type = get_default_product_type() get_default_sales_unit() activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name;gtiin\n%s;%s;111" % (sku, name)) # show import view data = { "importer": "product_importer", "shop": shop.pk, "language": lang, "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv") } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query query = parse_qs(query_string) data = { # data with missing `n` "importer": "product_importer", "shop": shop.pk, "language": lang, "n": query.get("n") } soup = client.soup(process_path, data=data) assert "The following fields must be manually tied" in str(soup) for row in soup.findAll("tr"): first_td = row.find("td") if not first_td: continue tds = row.findAll("td") if len(tds) < 2: continue second_td = tds[1] if first_td.text.startswith("Connection"): # check that sku was connected badges = second_td.findAll("span", {"class": "badge"}) assert len(badges) == 1 assert badges[0].text == "sku" elif first_td.text.startswith("The following fields"): badges = second_td.findAll("span", {"class": "badge"}) assert len(badges) == 2 badge_texts = [] for b in badges: badge_texts.append(b.text) badge_texts.sort() assert badge_texts[0] == "name" assert badge_texts[1] == "sku" data = {} data["import_mode"] = import_mode.value data["remap[gtiin]"] = "Product:gtin" # map gtin process_submit_path = "%s?%s" % (process_path, query_string) client.soup(process_submit_path, data=data, method="post") assert Product.objects.count() == 1 product = Product.objects.first() assert product.gtin == "111"
def test_remap(rf, admin_user): lang = "en" import_mode = ImportMode.CREATE_UPDATE sku = "123" name = "test" import_path = reverse("shuup_admin:importer.import") process_path = reverse("shuup_admin:importer.import_process") tax_class = get_default_tax_class() product_type = get_default_product_type() get_default_sales_unit() activate("en") shop = get_default_shop() shop.staff_members.add(admin_user) client = SmartClient() client.login(username="******", password="******") csv_content = str.encode("sku;name;gtiin\n%s;%s;111" % (sku, name)) # show import view data = { "importer": "product_importer", "shop": shop.pk, "language": lang, "file": SimpleUploadedFile("file.csv", csv_content, content_type="text/csv") } response = client.post(import_path, data=data) assert response.status_code == 302 query_string = urlparse(response["location"]).query query = parse_qs(query_string) data = { # data with missing `n` "importer": "product_importer", "shop": shop.pk, "language": lang, "n": query.get("n") } soup = client.soup(process_path, data=data) assert "The following fields must be manually tied" in str(soup) for row in soup.findAll("tr"): first_td = row.find("td") if not first_td: continue tds = row.findAll("td") if len(tds) < 2: continue second_td = tds[1] if first_td.text.startswith("Connection"): # check that sku was connected badges = second_td.findAll("span", {"class": "badge"}) assert len(badges) == 1 assert badges[0].text == "sku" elif first_td.text.startswith("The following fields"): badges = second_td.findAll("span", {"class": "badge"}) assert len(badges) == 2 badge_texts = [] for b in badges: badge_texts.append(b.text) badge_texts.sort() assert badge_texts[0] == "name" assert badge_texts[1] == "sku" data = {} data["import_mode"] = import_mode.value data["remap[gtiin]"] = "Product:gtin" # map gtin process_submit_path = "%s?%s" % (process_path, query_string) client.soup(process_submit_path, data=data, method="post") assert Product.objects.count() == 1 product = Product.objects.first() assert product.gtin == "111"
def test_sample_import_all_match(filename): activate("en") shop = get_default_shop() tax_class = get_default_tax_class() product_type = get_default_product_type() sales_unit = get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) if filename == bom_file: import codecs bytes = min(32, os.path.getsize(path)) raw = open(path, 'rb').read(bytes) assert raw.startswith(codecs.BOM_UTF8) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() if filename == images_file: assert len(importer.unmatched_fields) == 2 _create_random_media_file(shop, "image1.jpeg") _create_random_media_file(shop, "products/images/image2.jpeg") _create_random_media_file(shop, "products/images/image3.jpeg") _create_random_media_file(shop, "image4.jpeg") _create_random_media_file(shop, "products2/images/image5.jpeg") _create_random_media_file(shop, "product1.jpeg") _create_random_media_file(shop, "products/images/product2.jpeg") _create_random_media_file(shop, "products/images2/product2.jpeg") else: assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects if filename == images_file: assert len(products) == 3 else: assert len(products) == 2 for product in products: shop_product = product.get_shop_instance(shop) assert shop_product.pk assert shop_product.default_price_value == 150 assert shop_product.default_price == shop.create_price(150) assert product.type == product_type # product type comes from importer defaults assert product.sales_unit == sales_unit if product.pk == 1: assert product.tax_class.pk == 2 # new was created assert product.name == "Product English" assert product.description == "Description English" if filename == images_file: assert product.media.count() == 3 elif product.pk == 2: assert product.tax_class.pk == tax_class.pk # old was found as should assert product.name == "Product 2 English" assert product.description == "Description English 2" if filename == images_file: assert product.media.count() == 2 elif product.pk == 3 and filename == images_file: assert product.media.count() == 3 assert shop_product.primary_category.pk == 1 assert [c.pk for c in shop_product.categories.all()] == [1,2]
def test_edit_button_no_permission(browser, admin_user, live_server, settings): shop = get_default_shop() manager_group = Group.objects.create(name="Managers") manager = create_random_user("en", is_staff=True) manager.username = "******" manager.set_password("password") manager.save() manager.groups.add(manager_group) shop.staff_members.add(manager) # add permissions for Product admin module manager_permissions = set(["dashboard", "Products", "shop_product.new"]) set_permissions_for_group(manager_group, manager_permissions) get_default_product_type() get_default_sales_unit() get_default_tax_class() initialize_admin_browser_test(browser, live_server, settings, username=manager.username) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) wait_until_appeared( browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) click_element( browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") # no permission to add category with browser.get_iframe("create-object-iframe") as iframe: error = "Can't view this page. You do not have the required permissions: category.new" wait_until_condition(iframe, condition=lambda x: x.is_text_present(error)) # close iframe click_element(browser, "#create-object-overlay a.close-btn") # add permission to add category manager_permissions.add("category.new") manager_permissions.add("category.edit") set_permissions_for_group(manager_group, manager_permissions) # click to add category again click_element( browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") # add the category with browser.get_iframe("create-object-iframe") as iframe: assert Category.objects.count() == 0 wait_until_appeared(iframe, "input[name='base-name__en']") iframe.fill("base-name__en", "Test Category") time.sleep( 3 ) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(browser, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.count() == 1, timeout=20) assert Category.objects.first().name == "Test Category" # remove the edit category permissions # add permission to add category manager_permissions.remove("category.edit") set_permissions_for_group(manager_group, manager_permissions) # click to edit the button click_element( browser, "#id_shop%d-primary_category ~ .edit-object-btn a.btn" % shop.id) # no permission to edit category with browser.get_iframe("create-object-iframe") as iframe: error = "Can't view this page. You do not have the required permission(s): `category.edit`." wait_until_condition(iframe, condition=lambda x: x.is_text_present(error)) # close iframe click_element(browser, "#create-object-overlay a.close-btn") manager_permissions.add("category.edit") set_permissions_for_group(manager_group, manager_permissions) click_element( browser, "#id_shop%d-primary_category ~ .edit-object-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") new_cat_name = "Changed Name" with browser.get_iframe("create-object-iframe") as iframe: wait_until_appeared(iframe, "input[name='base-name__en']") iframe.fill("base-name__en", new_cat_name) time.sleep( 3 ) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(browser, "button[form='category_form']") wait_until_condition( browser, condition=lambda x: Category.objects.first().name == new_cat_name, timeout=20)
def test_sample_import_all_match(filename): activate("en") shop = get_default_shop() tax_class = get_default_tax_class() product_type = get_default_product_type() sales_unit = get_default_sales_unit() path = os.path.join(os.path.dirname(__file__), "data", "product", filename) if filename == bom_file: import codecs bytes = min(32, os.path.getsize(path)) raw = open(path, 'rb').read(bytes) assert raw.startswith(codecs.BOM_UTF8) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter(transformed_data, shop, "en") importer.process_data() if filename == images_file: assert len(importer.unmatched_fields) == 2 _create_random_media_file(shop, "image1.jpeg") _create_random_media_file(shop, "products/images/image2.jpeg") _create_random_media_file(shop, "products/images/image3.jpeg") _create_random_media_file(shop, "image4.jpeg") _create_random_media_file(shop, "products2/images/image5.jpeg") _create_random_media_file(shop, "product1.jpeg") _create_random_media_file(shop, "products/images/product2.jpeg") _create_random_media_file(shop, "products/images2/product2.jpeg") else: assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects if filename == images_file: assert len(products) == 3 else: assert len(products) == 2 for product in products: shop_product = product.get_shop_instance(shop) assert shop_product.pk assert shop_product.default_price_value == 150 assert shop_product.default_price == shop.create_price(150) assert product.type == product_type # product type comes from importer defaults assert product.sales_unit == sales_unit if product.pk == 1: assert product.tax_class.pk == 2 # new was created assert product.name == "Product English" assert product.description == "Description English" if filename == images_file: assert product.media.count() == 3 elif product.pk == 2: assert product.tax_class.pk == tax_class.pk # old was found as should assert product.name == "Product 2 English" assert product.description == "Description English 2" if filename == images_file: assert product.media.count() == 2 elif product.pk == 3 and filename == images_file: assert product.media.count() == 3 assert shop_product.primary_category.pk == 1 assert [c.pk for c in shop_product.categories.all()] == [1, 2]
def test_edit_button_no_permission(browser, admin_user, live_server, settings): shop = get_default_shop() manager_group = Group.objects.create(name="Managers") manager = create_random_user("en", is_staff=True) manager.username = "******" manager.set_password("password") manager.save() manager.groups.add(manager_group) shop.staff_members.add(manager) # add permissions for Product admin module manager_permissions = set(["dashboard", "Products", "shop_product.new"]) set_permissions_for_group(manager_group, manager_permissions) get_default_product_type() get_default_sales_unit() get_default_tax_class() initialize_admin_browser_test(browser, live_server, settings, username=manager.username) url = reverse("shuup_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) wait_until_appeared(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) click_element(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") # no permission to add category with browser.get_iframe('create-object-iframe') as iframe: error = "Can't view this page. You do not have the required permissions: category.new" wait_until_condition(iframe, condition=lambda x: x.is_text_present(error)) # close iframe click_element(browser, "#create-object-overlay a.close-btn") # add permission to add category manager_permissions.add("category.new") manager_permissions.add("category.edit") set_permissions_for_group(manager_group, manager_permissions) # click to add category again click_element(browser, "#id_shop%d-primary_category ~ .quick-add-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") # add the category with browser.get_iframe('create-object-iframe') as iframe: assert Category.objects.count() == 0 wait_until_appeared(iframe, "input[name='base-name__en']") iframe.fill("base-name__en", "Test Category") time.sleep(3) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(browser, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.count() == 1, timeout=20) assert Category.objects.first().name == "Test Category" # remove the edit category permissions # add permission to add category manager_permissions.remove("category.edit") set_permissions_for_group(manager_group, manager_permissions) # click to edit the button click_element(browser, "#id_shop%d-primary_category ~ .edit-object-btn a.btn" % shop.id) # no permission to edit category with browser.get_iframe('create-object-iframe') as iframe: error = "Can't view this page. You do not have the required permission(s): category.edit" wait_until_condition(iframe, condition=lambda x: x.is_text_present(error)) # close iframe click_element(browser, "#create-object-overlay a.close-btn") manager_permissions.add("category.edit") set_permissions_for_group(manager_group, manager_permissions) click_element(browser, "#id_shop%d-primary_category ~ .edit-object-btn a.btn" % shop.id) wait_until_appeared(browser, "#create-object-iframe") new_cat_name = "Changed Name" with browser.get_iframe('create-object-iframe') as iframe: wait_until_appeared(iframe, "input[name='base-name__en']") iframe.fill("base-name__en", new_cat_name) time.sleep(3) # Let's just wait here to the iFrame to open fully (for Chrome and headless) wait_until_appeared(iframe, "button[form='category_form']") click_element(browser, "button[form='category_form']") wait_until_condition(browser, condition=lambda x: Category.objects.first().name == new_cat_name, timeout=20)
def test_variatins_import(rf): filename = "product_sample_import_with_variations.xlsx" if "shuup.simple_supplier" not in settings.INSTALLED_APPS: pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS") from shuup_tests.simple_supplier.utils import get_simple_supplier activate("en") shop = get_default_shop() product_type = get_default_product_type() sales_unit = get_default_sales_unit() tax_class = get_default_tax_class() # Create media _create_random_media_file(shop, "shirt1.jpeg") _create_random_media_file(shop, "shirt2.jpeg") _create_random_media_file(shop, "shirt3.jpeg") path = os.path.join(os.path.dirname(__file__), "data", "product", filename) transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en")) importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 42 # 2 parents 20 variations each supplier = Supplier.objects.first() assert supplier and supplier.stock_managed and supplier.module_identifier == "simple_supplier" assert ShopProduct.objects.filter(suppliers=supplier).count() == 42 parent1 = Product.objects.filter(sku=1).first() assert parent1.mode == ProductMode.VARIABLE_VARIATION_PARENT assert parent1.variation_children.all().count() == 20 # Check product names child1 = Product.objects.filter(sku=10).first() assert child1.name == "T-Shirt - Pink - S" child2 = Product.objects.filter(sku=11).first() assert child2.name == "T-Shirt - Pink - XS" # Check stock counts assert supplier.get_stock_status(child1.pk).logical_count == Decimal(5) assert supplier.get_stock_status(child2.pk).logical_count == Decimal(10) parent2 = Product.objects.filter(sku=22).first() assert parent1.mode == ProductMode.VARIABLE_VARIATION_PARENT assert parent1.variation_children.all().count() == 20 # Check product names child1 = Product.objects.filter(sku=38).first() assert child1.name == "Custom T-Shirt - Black - XL" child2 = Product.objects.filter(sku=39).first() assert child2.name == "Custom T-Shirt - Black - L" # Check stock counts assert supplier.get_stock_status(child1.pk).logical_count == Decimal(5) assert supplier.get_stock_status(child2.pk).logical_count == Decimal(10) path = os.path.join(os.path.dirname(__file__), "data", "product", "product_sample_import_with_variations_update.xlsx") transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en")) importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 0 updated_products = importer.updated_objects assert len(updated_products) == 4 # Check product names child1 = Product.objects.filter(sku=10).first() assert child1.name == "T-Shirt - Pink - S" child2 = Product.objects.filter(sku=11).first() assert child2.name == "Test" # Check stock counts assert supplier.get_stock_status(child1.pk).logical_count == Decimal(5) assert supplier.get_stock_status(child2.pk).logical_count == Decimal( 20) # Did not add 20 but made the logical to 20 parent2 = Product.objects.filter(sku=22).first() assert parent1.mode == ProductMode.VARIABLE_VARIATION_PARENT assert parent1.variation_children.all().count() == 20 # Check product names child1 = Product.objects.filter(sku=38).first() assert child1.name == "Custom T-Shirt - Black - XL" child2 = Product.objects.filter(sku=39).first() assert child2.name == "Custom T-Shirt - Black - L" # Check stock counts assert supplier.get_stock_status(child1.pk).logical_count == Decimal(15) assert supplier.get_stock_status(child2.pk).logical_count == Decimal(10) # Test file with missing variations path = os.path.join( os.path.dirname(__file__), "data", "product", "product_sample_import_with_variations_missing_variables.xlsx") transformed_data = transform_file(filename.split(".")[1], path) importer = ProductImporter( transformed_data, ProductImporter.get_importer_context(rf.get("/"), shop=shop, language="en")) importer.process_data() assert len(importer.unmatched_fields) == 0 importer.do_import(ImportMode.CREATE_UPDATE) products = importer.new_objects assert len(products) == 0 updated_products = importer.updated_objects assert len(updated_products) == 4 for log_message in importer.log_messages: assert "Parent SKU set for the row, but no variation" in log_message[ "messages"][0] # check that both variation products still looks correct parent1 = Product.objects.filter(sku=1).first() assert parent1.mode == ProductMode.VARIABLE_VARIATION_PARENT assert parent1.variation_children.all().count() == 20 parent2 = Product.objects.filter(sku=22).first() assert parent1.mode == ProductMode.VARIABLE_VARIATION_PARENT assert parent1.variation_children.all().count() == 20
def test_admin_custom_customer_price_updates(rf, admin_user): shop = factories.get_default_shop() supplier = factories.get_default_supplier() contact = factories.create_random_person() group = PersonContact.get_default_group() contact.groups.add(group) product_type = factories.get_default_product_type() tax_class = factories.get_default_tax_class() sales_unit = factories.get_default_sales_unit() view = ProductEditView.as_view() group_price = "10.0" default_price = "15.0" payload = { "base-name__en": "My Product", "base-type": product_type.pk, "base-sku": "p1", "base-shipping_mode": ShippingMode.NOT_SHIPPED.value, "base-tax_class": tax_class.pk, "base-sales_unit": sales_unit.pk, "base-width": "0", "base-height": "0", "base-depth": "0", "base-net_weight": "0", "base-gross_weight": "0", f"shop{shop.pk}-default_price_value": default_price, f"shop{shop.pk}-visibility": ShopProductVisibility.ALWAYS_VISIBLE.value, f"shop{shop.pk}-visibility_limit": ProductVisibility.VISIBLE_TO_ALL.value, f"shop{shop.pk}-minimum_purchase_quantity": "1", f"shop{shop.pk}-purchase_multiple": "1", f"shop{shop.pk}-suppliers": [supplier.pk], f"customer_group_pricing-s_{shop.pk}_g_{group.pk}": group_price, # set price for the group } # create a new product request = apply_request_middleware(rf.post("/", data=payload), shop=shop, user=admin_user) with patch("django.db.transaction.on_commit", new=atomic_commit_mock): response = view(request, pk=None) assert response.status_code == 302 anon_catalog = ProductCatalog(context=ProductCatalogContext( purchasable_only=False)) customer_catalog = ProductCatalog( context=ProductCatalogContext(purchasable_only=False, contact=contact)) product = Product.objects.first() _assert_products_queryset(anon_catalog, [(product.pk, Decimal(default_price), None)]) _assert_products_queryset(customer_catalog, [(product.pk, Decimal(group_price), None)]) payload.update({ # remove the customer group price f"customer_group_pricing-s_{shop.pk}_g_{group.pk}": "", "media-TOTAL_FORMS": 0, "media-INITIAL_FORMS": 0, "media-MIN_NUM_FORMS": 0, "media-MAX_NUM_FORMS": 1000, "images-TOTAL_FORMS": 0, "images-INITIAL_FORMS": 0, "images-MIN_NUM_FORMS": 0, "images-MAX_NUM_FORMS": 1000, }) request = apply_request_middleware(rf.post("/", data=payload), shop=shop, user=admin_user) with patch("django.db.transaction.on_commit", new=atomic_commit_mock): response = view(request, pk=product.get_shop_instance(shop).pk) assert response.status_code == 302 # default price for both _assert_products_queryset(anon_catalog, [(product.pk, Decimal(default_price), None)]) _assert_products_queryset(customer_catalog, [(product.pk, Decimal(default_price), None)])