예제 #1
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
예제 #2
0
def test_product_add_attribute(admin_user):
    shop = get_default_shop()
    client = _get_client(admin_user)
    product = create_product("product1")

    attribute1 = Attribute.objects.create(identifier="attr1",
                                          type=AttributeType.BOOLEAN,
                                          visibility_mode=AttributeVisibility.SHOW_ON_PRODUCT_PAGE,
                                          name="Attribute 1")
    attribute2 = Attribute.objects.create(identifier="attr2",
                                          type=AttributeType.TRANSLATED_STRING,
                                          visibility_mode=AttributeVisibility.SHOW_ON_PRODUCT_PAGE,
                                          name="Attribute 2")
    attribute3 = Attribute.objects.create(identifier="attr3",
                                          type=AttributeType.UNTRANSLATED_STRING,
                                          visibility_mode=AttributeVisibility.SHOW_ON_PRODUCT_PAGE,
                                          name="Attribute 3")

    get_default_product_type().attributes.add(attribute1)
    get_default_product_type().attributes.add(attribute2)

    product_attr1_data = {
        "attribute": attribute1.pk,
        "numeric_value": 0,
    }
    response = client.post("/api/shuup/product/%d/add_attribute/" % product.pk,
                           content_type="application/json",
                           data=json.dumps(product_attr1_data))
    assert response.status_code == status.HTTP_201_CREATED
    assert ProductAttribute.objects.filter(product=product).count() == 1
    pa = ProductAttribute.objects.first()
    assert pa.attribute.pk == attribute1.pk
    assert pa.numeric_value == product_attr1_data["numeric_value"]

    product_attr2_data = {
        "attribute": attribute2.pk,
        "translations": {
            "en": {"translated_string_value": "come on"},
            "pt-br": {"translated_string_value": "vamos lá"}
        }
    }
    response = client.post("/api/shuup/product/%d/add_attribute/" % product.pk,
                           content_type="application/json",
                           data=json.dumps(product_attr2_data))
    assert response.status_code == status.HTTP_201_CREATED
    assert ProductAttribute.objects.filter(product=product).count() == 2
    pa = ProductAttribute.objects.last()
    assert pa.attribute.pk == attribute2.pk
    assert pa.translated_string_value == product_attr2_data["translations"]["en"]["translated_string_value"]

    # try to add an attribute which does not belong to the product type
    product_attr3_data = {
        "attribute": attribute3.pk,
        "untraslated_string": "lalala"
    }
    response = client.post("/api/shuup/product/%d/add_attribute/" % product.pk,
                           content_type="application/json",
                           data=json.dumps(product_attr3_data))
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert ProductAttribute.objects.filter(product=product).count() == 2
예제 #3
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']")
예제 #4
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"]
예제 #5
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()

    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) == 2
    for product in products:
        shop_product = product.get_shop_instance(shop)
        assert shop_product.pk
        assert shop_product.pk == 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
        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]
예제 #6
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
예제 #7
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
예제 #8
0
def test_product_attribute(admin_user):
    shop = get_default_shop()
    client = _get_client(admin_user)
    product1 = create_product("product1")

    attrib1 = create_random_product_attribute()
    attrib2 = create_random_product_attribute()
    product_type = get_default_product_type()
    product_type.attributes.add(attrib1)
    product_type.attributes.add(attrib2)

    product_attr1_data = {"attribute": attrib1.pk, "numeric_value": 0}
    product_attr2_data = {"attribute": attrib2.pk, "numeric_value": 1}
    response = client.post("/api/shuup/product/%d/add_attribute/" % product1.pk,
                           content_type="application/json",
                           data=json.dumps(product_attr1_data))
    assert response.status_code == status.HTTP_201_CREATED
    response = client.post("/api/shuup/product/%d/add_attribute/" % product1.pk,
                           content_type="application/json",
                           data=json.dumps(product_attr2_data))
    assert response.status_code == status.HTTP_201_CREATED

    attrs = ProductAttribute.objects.filter(product=product1)

    # get the first attr
    response = client.get("/api/shuup/product_attribute/%d/" % attrs[0].id)
    assert response.status_code == status.HTTP_200_OK
    data = json.loads(response.content.decode("utf-8"))
    assert data["product"] == product1.id
    assert data["attribute"] == attrib1.id
    assert Decimal(data["numeric_value"]) == Decimal(0)

    # get the 2nd attr
    response = client.get("/api/shuup/product_attribute/%d/" % attrs[1].id)
    assert response.status_code == status.HTTP_200_OK
    data = json.loads(response.content.decode("utf-8"))
    assert data["product"] == product1.id
    assert data["attribute"] == attrib2.id
    assert Decimal(data["numeric_value"]) == Decimal(1)

    # update the first attr - numeric_value=1, attr=2
    attr_data = {"numeric_value": 1, "attribute": attrib2.pk}
    response = client.put("/api/shuup/product_attribute/%d/" % attrs[0].id,
                          content_type="application/json",
                          data=json.dumps(attr_data))
    assert response.status_code == status.HTTP_200_OK
    response = client.get("/api/shuup/product_attribute/%d/" % attrs[0].id)
    assert response.status_code == status.HTTP_200_OK
    data = json.loads(response.content.decode("utf-8"))
    assert data["product"] == product1.id
    assert data["attribute"] == attrib2.id
    assert Decimal(data["numeric_value"]) == Decimal(1)

    # deletes the last attr
    response = client.delete("/api/shuup/product_attribute/%d/" % attrs[1].id)
    assert response.status_code == status.HTTP_204_NO_CONTENT
    assert ProductAttribute.objects.count() == 1
예제 #9
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
예제 #10
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)
예제 #11
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()

    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
예제 #12
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()
예제 #13
0
파일: factories.py 프로젝트: ruqaiya/shuup
def create_sample_product(name, description, business_segment, image_file, shop):
    product = Product.objects.create(
        name=name,
        description=description,
        type=get_default_product_type(),
        tax_class=get_default_tax_class(),
        sales_unit=SalesUnit.objects.first(),
        sku=fuzzy.FuzzyText(length=10).fuzz()
    )

    image_file_path = os.path.join(SAMPLE_IMAGES_BASE_DIR, image_file)
    path = "ProductImages/Samples/%s" % business_segment.capitalize()
    filer_image = _filer_image_from_file_path(image_file_path, path)

    media_file = MediaFile.objects.create(file=filer_image)
    media_file.shops.add(shop)

    media = ProductMedia.objects.create(
        product=product,
        kind=ProductMediaKind.IMAGE,
        file=filer_image
    )
    media.save()
    media.shops.add(shop)
    product.primary_image = media
    product.save()

    # create the price and round it to the number of decimals of the currency
    price = shop.create_price(decimal.Decimal(random.random() * random.randrange(0, 500))).as_rounded()

    sp = ShopProduct.objects.create(
        product=product,
        purchasable=True,
        visibility=ShopProductVisibility.ALWAYS_VISIBLE,
        default_price_value=price,
        shop=shop,
        shop_primary_image=media
    )
    sp.categories = shop.categories.all()
    sp.suppliers.add(get_default_supplier())

    # configure prices
    if "shuup.customer_group_pricing" in settings.INSTALLED_APPS:
        from shuup.customer_group_pricing.models import CgpPrice
        CgpPrice.objects.create(
            product=product,
            price_value=random.randint(15, 340),
            shop=shop,
            group=PersonContact.get_default_group()
        )

    return product
예제 #14
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
예제 #15
0
파일: test_admin.py 프로젝트: suutari/shoop
def test_admin(rf, admin_user):
    view = ImportView.as_view()
    activate("en")
    shop = get_default_shop()
    tax_class = get_default_tax_class()
    product_type = get_default_product_type()

    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)
예제 #16
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
예제 #17
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
    }
예제 #18
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)
예제 #19
0
파일: test_admin.py 프로젝트: suutari/shoop
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()

    activate("en")
    shop = get_default_shop()
    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"
예제 #20
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]
예제 #21
0
def test_sample_import_no_match(rf, 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,
        ProductImporter.get_importer_context(rf.get("/"),
                                             shop=shop,
                                             language="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
예제 #22
0
def test_product_type_selector(admin_user):
    shop = get_default_shop()
    get_default_product_type()
    assert get_object_selector_results(ProductType, shop, admin_user,
                                       "default")
예제 #23
0
파일: test_admin.py 프로젝트: zaster/shuup
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")
    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
    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

    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
예제 #24
0
파일: test_admin.py 프로젝트: ruqaiya/shuup
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")
    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
    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

    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
예제 #25
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]
예제 #26
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)
예제 #27
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
예제 #28
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']")
예제 #29
0
def test_create_product_with_shop_product_and_attributes(admin_user):
    shop = get_default_shop()
    client = _get_client(admin_user)
    supplier = get_default_supplier()

    cat = Category.objects.create(
        status=CategoryStatus.VISIBLE,
        visibility=CategoryVisibility.VISIBLE_TO_ALL,
        identifier="test_category",
        name="Test"
    )
    product_type = get_default_product_type()

    assert Attribute.objects.count() > 0

    assert Product.objects.count() == 0

    attributes_data = []

    expected_values = {
        "untranslated_string_value": "test value",
        "numeric_value": 12,
        "boolean_value": True,
        "timedelta_value": "200",  # seconds
        "datetime_value": "2017-01-01 01:00:00",
        "translated_string_value": "translated string value"
    }

    for spec in ATTR_SPECS:
        attr = Attribute.objects.get(identifier=spec["identifier"])
        attr_data = {
            "numeric_value": None,
            "datetime_value": None,
            "untranslated_string_value": "",
            "attribute": attr.pk,
            # "product": product.pk
        }

        if attr.is_stringy:
            if attr.is_translated:
                attr_data["translations"] = {
                    "en": {
                        "translated_string_value": expected_values["translated_string_value"]
                    }
                }
            else:
                attr_data["untranslated_string_value"] = expected_values["untranslated_string_value"]
        elif attr.is_numeric:
            if attr.type == AttributeType.BOOLEAN:
                attr_data["numeric_value"] = int(expected_values["boolean_value"])
            elif attr.type == AttributeType.TIMEDELTA:
                attr_data["numeric_value"] = int(expected_values["timedelta_value"])
            else:
                attr_data["numeric_value"] = expected_values["numeric_value"]
        elif attr.is_temporal:
            attr_data["datetime_value"] = expected_values["datetime_value"]

        attributes_data.append(attr_data)

    data = _get_product_sample_data()
    data["shop_products"] = _get_sample_shop_product_data(shop, cat, supplier)
    data["attributes"] = attributes_data
    response = client.post("/api/shuup/product/", content_type="application/json", data=json.dumps(data))
    assert response.status_code == status.HTTP_201_CREATED

    # check all
    for lang in ("en", "pt-br"):
        activate(lang)
        product = Product.objects.first()
        _check_product_basic_data(product, data, lang)

    assert Product.objects.count() == 1
    assert ShopProduct.objects.count() == 1

    product = Product.objects.first()
    shop_product = ShopProduct.objects.first()

    assert product.get_shop_instance(shop) == shop_product
    assert supplier in shop_product.suppliers.all()
    assert cat in shop_product.categories.all()
    assert shop_product.primary_category == cat

    # validate attribute values
    for spec in ATTR_SPECS:
        attribute = Attribute.objects.get(identifier=spec["identifier"])
        attr = ProductAttribute.objects.get(product=product, attribute=attribute)
        if attribute.is_stringy:
            if attribute.is_translated:
                attr.set_current_language("en")
                assert attr.value == expected_values["translated_string_value"]
            else:
                assert attr.value == expected_values["untranslated_string_value"]
        elif attribute.is_numeric:
            if attribute.type == AttributeType.BOOLEAN:
                assert attr.value == expected_values["boolean_value"]
            elif attribute.type == AttributeType.TIMEDELTA:
                assert attr.value == datetime.timedelta(seconds=int(expected_values["timedelta_value"]))
            else:
                assert attr.value == expected_values["numeric_value"]
        elif attribute.is_temporal:
            dt_value = expected_values["datetime_value"]
            parsed_dt = dt.strptime(dt_value, "%Y-%m-%d %H:%M:%S")
            assert attr.value.year == parsed_dt.year
            assert attr.value.month == parsed_dt.month
            assert attr.value.day == parsed_dt.day
예제 #30
0
def test_create_product_with_shop_product_and_attributes(admin_user):
    shop = get_default_shop()
    client = _get_client(admin_user)
    supplier = get_default_supplier()

    cat = Category.objects.create(status=CategoryStatus.VISIBLE,
                                  visibility=CategoryVisibility.VISIBLE_TO_ALL,
                                  identifier="test_category",
                                  name="Test")
    product_type = get_default_product_type()

    assert Attribute.objects.count() > 0

    assert Product.objects.count() == 0

    attributes_data = []

    expected_values = {
        "untranslated_string_value": "test value",
        "numeric_value": 12,
        "boolean_value": True,
        "timedelta_value": "200",  # seconds
        "datetime_value": "2017-01-01 01:00:00",
        "translated_string_value": "translated string value"
    }

    for spec in ATTR_SPECS:
        attr = Attribute.objects.get(identifier=spec["identifier"])
        attr_data = {
            "numeric_value": None,
            "datetime_value": None,
            "untranslated_string_value": "",
            "attribute": attr.pk,
            # "product": product.pk
        }

        if attr.is_stringy:
            if attr.is_translated:
                attr_data["translations"] = {
                    "en": {
                        "translated_string_value":
                        expected_values["translated_string_value"]
                    }
                }
            else:
                attr_data["untranslated_string_value"] = expected_values[
                    "untranslated_string_value"]
        elif attr.is_numeric:
            if attr.type == AttributeType.BOOLEAN:
                attr_data["numeric_value"] = int(
                    expected_values["boolean_value"])
            elif attr.type == AttributeType.TIMEDELTA:
                attr_data["numeric_value"] = int(
                    expected_values["timedelta_value"])
            else:
                attr_data["numeric_value"] = expected_values["numeric_value"]
        elif attr.is_temporal:
            attr_data["datetime_value"] = expected_values["datetime_value"]

        attributes_data.append(attr_data)

    data = _get_product_sample_data()
    data["shop_products"] = _get_sample_shop_product_data(shop, cat, supplier)
    data["attributes"] = attributes_data
    response = client.post("/api/shuup/product/",
                           content_type="application/json",
                           data=json.dumps(data))
    assert response.status_code == status.HTTP_201_CREATED

    # check all
    for lang in ("en", "pt-br"):
        activate(lang)
        product = Product.objects.first()
        _check_product_basic_data(product, data, lang)

    assert Product.objects.count() == 1
    assert ShopProduct.objects.count() == 1

    product = Product.objects.first()
    shop_product = ShopProduct.objects.first()

    assert product.get_shop_instance(shop) == shop_product
    assert supplier in shop_product.suppliers.all()
    assert cat in shop_product.categories.all()
    assert shop_product.primary_category == cat

    # validate attribute values
    for spec in ATTR_SPECS:
        attribute = Attribute.objects.get(identifier=spec["identifier"])
        attr = ProductAttribute.objects.get(product=product,
                                            attribute=attribute)
        if attribute.is_stringy:
            if attribute.is_translated:
                attr.set_current_language("en")
                assert attr.value == expected_values["translated_string_value"]
            else:
                assert attr.value == expected_values[
                    "untranslated_string_value"]
        elif attribute.is_numeric:
            if attribute.type == AttributeType.BOOLEAN:
                assert attr.value == expected_values["boolean_value"]
            elif attribute.type == AttributeType.TIMEDELTA:
                assert attr.value == datetime.timedelta(
                    seconds=int(expected_values["timedelta_value"]))
            else:
                assert attr.value == expected_values["numeric_value"]
        elif attribute.is_temporal:
            dt_value = expected_values["datetime_value"]
            parsed_dt = dt.strptime(dt_value, "%Y-%m-%d %H:%M:%S")
            assert attr.value.year == parsed_dt.year
            assert attr.value.month == parsed_dt.month
            assert attr.value.day == parsed_dt.day
예제 #31
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()

    activate("en")
    shop = get_default_shop()
    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_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)