예제 #1
0
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
    )
예제 #2
0
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")
예제 #3
0
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
예제 #4
0
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()
예제 #5
0
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
예제 #6
0
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)
예제 #7
0
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
예제 #8
0
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"]
예제 #9
0
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']")
예제 #10
0
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"])
예제 #11
0
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']")
예제 #12
0
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"]
예제 #13
0
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
예제 #14
0
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
예제 #15
0
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
예제 #16
0
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
예제 #17
0
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
예제 #18
0
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
예제 #19
0
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)
예제 #20
0
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
예제 #21
0
파일: test_admin.py 프로젝트: ruqaiya/shuup
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)
예제 #22
0
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
예제 #23
0
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()
예제 #24
0
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()
예제 #25
0
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)
예제 #26
0
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
예제 #27
0
파일: test_admin.py 프로젝트: ruqaiya/shuup
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)
예제 #28
0
파일: test_admin.py 프로젝트: ruqaiya/shuup
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)
예제 #30
0
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()
예제 #31
0
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
예제 #32
0
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
예제 #33
0
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
    }
예제 #34
0
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
    }
예제 #35
0
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
예제 #36
0
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"
예제 #37
0
파일: test_admin.py 프로젝트: ruqaiya/shuup
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"
예제 #38
0
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]
예제 #39
0
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)
예제 #40
0
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]
예제 #41
0
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)
예제 #42
0
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
예제 #43
0
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)])