예제 #1
0
def seed_source(user, shop=None):
    source_shop = shop or get_default_shop()
    source = BasketishOrderSource(source_shop)
    billing_address = get_address()
    shipping_address = get_address(name="Shippy Doge")
    source.status = get_initial_order_status()
    source.billing_address = billing_address
    source.shipping_address = shipping_address
    source.customer = get_person_contact(user)
    source.payment_method = get_payment_method(shop)
    source.shipping_method = get_shipping_method(shop)
    assert source.payment_method_id == get_payment_method(shop).id
    assert source.shipping_method_id == get_shipping_method(shop).id
    return source
예제 #2
0
def _get_frontend_order_state(shop, contact):
    tax = Tax.objects.create(code="test_code", rate=decimal.Decimal("0.20"), name="Default")
    tax_class = TaxClass.objects.create(identifier="test_tax_class", name="Default")
    rule = TaxRule.objects.create(tax=tax)
    rule.tax_classes.add(tax_class)
    rule.save()
    product = create_product(sku=printable_gibberish(), supplier=get_default_supplier(), shop=shop)
    product.tax_class = tax_class
    product.save()
    lines = [{"id": "x", "type": "product", "product": {"id": product.id}, "quantity": "32", "baseUnitPrice": 50}]

    state = {
        "customer": {
            "id": contact.id if contact else None,
            "billingAddress": _encode_address(contact.default_billing_address) if contact else {},
            "shippingAddress": _encode_address(contact.default_shipping_address) if contact else {},
        },
        "lines": lines,
        "methods": {
            "shippingMethod": {"id": get_shipping_method(shop=shop).id},
            "paymentMethod": {"id": get_payment_method(shop=shop).id},
        },
        "shop": {
            "selected": {
                "id": shop.id,
                "name": shop.safe_translation_getter("name"),
                "currency": shop.currency,
                "priceIncludeTaxes": shop.prices_include_tax,
            }
        },
    }
    return state
예제 #3
0
def test_translations_of_method_and_component():
    sm = get_shipping_method(name="Unique shipping")
    sm.set_current_language('en')
    sm.name = "Shipping"
    sm.set_current_language('fi')
    sm.name = "Toimitus"
    sm.save()

    cost = FixedCostBehaviorComponent.objects.language('fi').create(
        price_value=10, description="kymppi")
    cost.set_current_language('en')
    cost.description = "ten bucks"
    cost.save()
    sm.behavior_components.add(cost)

    source = BasketishOrderSource(get_default_shop())
    source.shipping_method = sm

    translation.activate('fi')
    shipping_lines = [
        line for line in source.get_final_lines()
        if line.type == OrderLineType.SHIPPING]
    assert len(shipping_lines) == 1
    assert shipping_lines[0].text == 'Toimitus: kymppi'

    translation.activate('en')
    source.uncache()
    shipping_lines = [
        line for line in source.get_final_lines()
        if line.type == OrderLineType.SHIPPING]
    assert len(shipping_lines) == 1
    assert shipping_lines[0].text == 'Shipping: ten bucks'
def _get_order_with_coupon(request, initial_status, condition_product_count=1):
    shop = request.shop
    basket = get_basket(request)
    supplier = get_default_supplier()
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price="50")
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)  # For shippable products

    dc = Coupon.objects.create(code="TEST", active=True)
    campaign = BasketCampaign.objects.create(
        shop=shop,
        name="test",
        public_name="test",
        coupon=dc,
        active=True
    )

    BasketDiscountAmount.objects.create(discount_amount=shop.create_price("20"), campaign=campaign)

    rule = BasketTotalProductAmountCondition.objects.create(value=1)
    campaign.conditions.add(rule)
    campaign.save()
    basket.add_code(dc.code)
    basket.save()

    basket.status = initial_status
    creator = OrderCreator(request)
    order = creator.create_order(basket)
    assert order.lines.count() == 3
    assert OrderLineType.DISCOUNT in [l.type for l in order.lines.all()]
    return order
예제 #5
0
def test_limited_methods():
    """
    Test that products can declare that they limit available shipping methods.
    """
    unique_shipping_method = get_shipping_method(name="unique", price=0)
    shop = get_default_shop()
    common_product = create_product(sku="SH_COMMON", shop=shop)  # A product that does not limit shipping methods
    unique_product = create_product(sku="SH_UNIQUE", shop=shop)  # A product that only supports unique_shipping_method
    unique_shop_product = unique_product.get_shop_instance(shop)
    unique_shop_product.limit_shipping_methods = True
    unique_shop_product.shipping_methods.add(unique_shipping_method)
    unique_shop_product.save()
    impossible_product = create_product(sku="SH_IMP", shop=shop)  # A product that can't be shipped at all
    imp_shop_product = impossible_product.get_shop_instance(shop)
    imp_shop_product.limit_shipping_methods = True
    imp_shop_product.save()
    for product_ids, method_ids in [
        ((common_product.pk, unique_product.pk), (unique_shipping_method.pk,)),
        ((common_product.pk,), ShippingMethod.objects.values_list("pk", flat=True)),
        ((unique_product.pk,), (unique_shipping_method.pk,)),
        ((unique_product.pk, impossible_product.pk,), ()),
        ((common_product.pk, impossible_product.pk,), ()),
    ]:
        product_ids = set(product_ids)
        assert ShippingMethod.objects.available_ids(shop=shop, products=product_ids) == set(method_ids)
def test_category_product_in_basket_condition(rf):
    request, shop, group = initialize_test(rf, False)
    basket = get_basket(request)
    supplier = get_default_supplier()
    category = get_default_category()
    product = create_product("The Product", shop=shop, default_price="200", supplier=supplier)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    shop_product = product.get_shop_instance(shop)
    assert category not in shop_product.categories.all()

    condition = CategoryProductsBasketCondition.objects.create(operator=ComparisonOperator.EQUALS, quantity=1)
    condition.categories.add(category)

    # No match the product does not have the category
    assert not condition.matches(basket, [])

    shop_product.categories.add(category)
    assert condition.matches(basket, [])

    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    assert not condition.matches(basket, [])

    condition.operator = ComparisonOperator.GTE
    condition.save()

    assert condition.matches(basket, [])

    condition.excluded_categories.add(category)
    assert not condition.matches(basket, [])
예제 #7
0
def test_only_cheapest_price_is_selected(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()
     # create a basket rule that requires atleast value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    product_price = "200"

    discount1 = "10"
    discount2 = "20"  # should be selected
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    campaign1 = BasketCampaign.objects.create(shop=shop, public_name="test", name="test", active=True)
    campaign1.conditions.add(rule)
    campaign1.save()
    BasketDiscountAmount.objects.create(discount_amount=discount1, campaign=campaign1)

    campaign2 = BasketCampaign.objects.create(shop=shop, public_name="test", name="test", active=True)
    campaign2.conditions.add(rule)
    campaign2.save()
    BasketDiscountAmount.objects.create(discount_amount=discount2, campaign=campaign2)

    assert len(basket.get_final_lines()) == 3

    line_types = [l.type for l in basket.get_final_lines()]
    assert OrderLineType.DISCOUNT in line_types

    for line in basket.get_final_lines():
        if line.type == OrderLineType.DISCOUNT:
            assert line.discount_amount == price(discount2)
예제 #8
0
def test_percentage_campaign(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()
    # create a basket rule that requires at least value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    product_price = "200"

    discount_percentage = "0.1"

    expected_discounted_price = price(product_price) - (price(product_price) * Decimal(discount_percentage))

    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True)
    campaign.conditions.add(rule)
    campaign.save()

    BasketDiscountPercentage.objects.create(campaign=campaign, discount_percentage=discount_percentage)

    assert len(basket.get_final_lines()) == 3
    assert basket.product_count == 1
    assert basket.total_price == expected_discounted_price
예제 #9
0
def test_source_lines_with_multiple_fixed_costs():
    """
    Costs with description creates new line always and costs without
    description is combined into one line.
    """
    translation.activate("en")
    starting_price_value = 5
    sm = get_shipping_method(name="Multiple costs", price=starting_price_value)
    sm.behavior_components.clear()

    source = BasketishOrderSource(get_default_shop())
    source.shipping_method = sm

    lines = list(sm.get_lines(source))
    assert len(lines) == 1
    assert get_total_price_value(lines) == Decimal("0")

    sm.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=10))
    lines = list(sm.get_lines(source))
    assert len(lines) == 1
    assert get_total_price_value(lines) == Decimal("10")

    sm.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=15, description="extra"))
    lines = list(sm.get_lines(source))
    assert len(lines) == 2
    assert get_total_price_value(lines) == Decimal("25")

    sm.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=1))
    lines = list(sm.get_lines(source))
    assert len(lines) == 2
    assert get_total_price_value(lines) == Decimal("26")
예제 #10
0
def test_productfilter_works(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price
    product_price = "100"
    discount_percentage = "0.30"

    supplier = get_default_supplier()
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=product_price)
    shop_product = product.get_shop_instance(shop)

    # create catalog campaign
    catalog_filter = ProductFilter.objects.create()
    catalog_filter.products.add(product)

    assert catalog_filter.matches(shop_product)

    catalog_campaign = CatalogCampaign.objects.create(shop=shop, active=True, name="test")
    catalog_campaign.filters.add(catalog_filter)
    cdp = ProductDiscountPercentage.objects.create(campaign=catalog_campaign, discount_percentage=discount_percentage)

    # add product to basket
    basket = get_basket(request)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    expected_total = price(product_price) - (Decimal(discount_percentage) * price(product_price))
    assert basket.total_price == expected_total
def _get_source(user, shipping_country, billing_country):
    prices_include_taxes = True
    shop = get_shop(prices_include_taxes)
    payment_method = get_payment_method(shop)
    shipping_method = get_shipping_method(shop)
    source = _seed_source(shop, user, shipping_country, billing_country)
    source.payment_method = payment_method
    source.shipping_method = shipping_method
    assert source.payment_method_id == payment_method.id
    assert source.shipping_method_id == shipping_method.id

    supplier = get_default_supplier()
    product = create_product(
        sku="test-%s--%s" % (prices_include_taxes, 10),
        shop=source.shop,
        supplier=supplier,
        default_price=10
    )
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    assert payment_method == source.payment_method
    assert shipping_method == source.shipping_method
    return source
def _get_source(user, prices_include_taxes, total_price_value):
    shop = get_shop(prices_include_taxes)
    payment_method = get_payment_method(shop)
    shipping_method = get_shipping_method(shop)
    source = _seed_source(shop, user)
    source.payment_method = payment_method
    source.shipping_method = shipping_method
    assert source.payment_method_id == payment_method.id
    assert source.shipping_method_id == shipping_method.id

    supplier = get_default_supplier()
    product = create_product(
        sku="test-%s--%s" % (prices_include_taxes, total_price_value),
        shop=source.shop,
        supplier=supplier,
        default_price=total_price_value
    )
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(total_price_value),
    )
    if prices_include_taxes:
        assert source.taxful_total_price.value == total_price_value
    else:
        assert source.taxless_total_price.value == total_price_value
    assert payment_method == source.payment_method
    assert shipping_method == source.shipping_method
    return source, shipping_method
예제 #13
0
def test_basket(rf, storage):
    StoredBasket.objects.all().delete()
    quantities = [3, 12, 44, 23, 65]
    shop = get_default_shop()
    get_default_payment_method(
    )  # Can't create baskets without payment methods
    supplier = get_default_supplier()
    products_and_quantities = []
    for quantity in quantities:
        product = create_product(printable_gibberish(),
                                 shop=shop,
                                 supplier=supplier,
                                 default_price=50)
        products_and_quantities.append((product, quantity))

    is_database = (
        storage == "shuup.front.basket.storage:DatabaseBasketStorage")
    with override_settings(SHUUP_BASKET_STORAGE_CLASS_SPEC=storage):
        for product, q in products_and_quantities:
            request = rf.get("/")
            request.session = {}
            request.shop = shop
            apply_request_middleware(request)
            basket = get_basket(request)
            assert basket == request.basket
            assert basket.product_count == 0
            line = basket.add_product(supplier=supplier,
                                      shop=shop,
                                      product=product,
                                      quantity=q)
            basket.shipping_method = get_shipping_method(
                shop=shop)  # For shippable product
            assert line.quantity == q
            assert basket.get_lines()
            assert basket.get_product_ids_and_quantities().get(product.pk) == q
            assert basket.product_count == q
            basket.save()
            delattr(request, "basket")
            basket = get_basket(request)
            assert basket.get_product_ids_and_quantities().get(product.pk) == q
            if is_database:
                product_ids = set(
                    StoredBasket.objects.last().products.values_list(
                        "id", flat=True))
                assert product_ids == set([product.pk])

        if is_database:
            stats = StoredBasket.objects.all().aggregate(
                n=Sum("product_count"),
                tfs=Sum("taxful_total_price_value"),
                tls=Sum("taxless_total_price_value"),
            )
            assert stats["n"] == sum(quantities)
            if shop.prices_include_tax:
                assert stats["tfs"] == sum(quantities) * 50
            else:
                assert stats["tls"] == sum(quantities) * 50

        basket.finalize()
예제 #14
0
def test_basket_free_product_coupon(rf):
    request, shop, _ = initialize_test(rf, False)

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = "50"

    # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=single_product_price)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    second_product = create_product(printable_gibberish(),
                                    shop=shop,
                                    supplier=supplier,
                                    default_price=single_product_price)

    rule = BasketTotalProductAmountCondition.objects.create(value="2")
    coupon = Coupon.objects.create(code="TEST", active=True)

    campaign = BasketCampaign.objects.create(active=True,
                                             shop=shop,
                                             name="test",
                                             public_name="test",
                                             coupon=coupon)
    campaign.conditions.add(rule)

    effect = FreeProductLine.objects.create(campaign=campaign)
    effect.products.add(second_product)

    basket.add_code(coupon.code)

    basket.uncache()
    final_lines = basket.get_final_lines()

    assert len(final_lines) == 3

    line_types = [l.type for l in final_lines]
    assert OrderLineType.DISCOUNT not in line_types

    for line in basket.get_final_lines():
        assert line.type in [OrderLineType.PRODUCT, OrderLineType.SHIPPING]
        if line.type == OrderLineType.SHIPPING:
            continue

        if line.product != product:
            assert line.product == second_product
예제 #15
0
def test_basket_campaign_with_multiple_supppliers(rf):
    request, shop, group = initialize_test(rf, False)
    supplier1 = Supplier.objects.create(identifier="1")
    supplier2 = Supplier.objects.create(identifier="2")

    price = shop.create_price
    basket = get_basket(request)
    
    single_product_price = "50"
    discount_amount_supplier1 = "10"
    discount_amount_supplier2 = "40"

    product1 = create_product("product1", shop=shop, supplier=supplier1, default_price=single_product_price)
    product2 = create_product("product2", shop=shop, supplier=supplier2, default_price=single_product_price)

    basket.add_product(supplier=supplier1, shop=shop, product=product1, quantity=1)
    basket.add_product(supplier=supplier2, shop=shop, product=product2, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    assert basket.product_count == 2
    assert basket.total_price.value == 100

    # Create campaign for supplier one
    basket_rule1 = ProductsInBasketCondition.objects.create(quantity=1)
    basket_rule1.products.add(product1)

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True, supplier=supplier1)
    campaign.conditions.add(basket_rule1)
    campaign.save()
    BasketDiscountAmount.objects.create(
        campaign=campaign, discount_amount=discount_amount_supplier1)

    basket.uncache()
    lines = basket.get_final_lines()
    assert len(lines) == 4
    assert basket.total_price.value == 90  # 10d discount from the supplier1 product
    line = _get_discount_line(lines, 10)
    assert line.supplier == supplier1


    # Create campaign for supplier two
    basket_rule2 = ProductsInBasketCondition.objects.create(quantity=1)
    basket_rule2.products.add(product2)

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True, supplier=supplier2)
    campaign.conditions.add(basket_rule2)
    campaign.save()
    BasketDiscountAmount.objects.create(
        campaign=campaign, discount_amount=discount_amount_supplier2)

    basket.uncache()
    lines = basket.get_final_lines()
    assert len(lines) == 5
    assert basket.total_price.value == 50  # -10d - 40d from 100d
    line = _get_discount_line(lines, 40)
    assert line.supplier == supplier2
예제 #16
0
def test_basket_campaign_with_multiple_supppliers(rf):
    request, shop, group = initialize_test(rf, False)
    supplier1 = Supplier.objects.create(identifier="1")
    supplier2 = Supplier.objects.create(identifier="2")

    price = shop.create_price
    basket = get_basket(request)
    
    single_product_price = "50"
    discount_amount_supplier1 = "10"
    discount_amount_supplier2 = "40"

    product1 = create_product("product1", shop=shop, supplier=supplier1, default_price=single_product_price)
    product2 = create_product("product2", shop=shop, supplier=supplier2, default_price=single_product_price)

    basket.add_product(supplier=supplier1, shop=shop, product=product1, quantity=1)
    basket.add_product(supplier=supplier2, shop=shop, product=product2, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    assert basket.product_count == 2
    assert basket.total_price.value == 100

    # Create campaign for supplier one
    basket_rule1 = ProductsInBasketCondition.objects.create(quantity=1)
    basket_rule1.products.add(product1)

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True, supplier=supplier1)
    campaign.conditions.add(basket_rule1)
    campaign.save()
    BasketDiscountAmount.objects.create(
        campaign=campaign, discount_amount=discount_amount_supplier1)

    basket.uncache()
    lines = basket.get_final_lines()
    assert len(lines) == 4
    assert basket.total_price.value == 90  # 10d discount from the supplier1 product
    line = _get_discount_line(lines, 10)
    assert line.supplier == supplier1


    # Create campaign for supplier two
    basket_rule2 = ProductsInBasketCondition.objects.create(quantity=1)
    basket_rule2.products.add(product2)

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True, supplier=supplier2)
    campaign.conditions.add(basket_rule2)
    campaign.save()
    BasketDiscountAmount.objects.create(
        campaign=campaign, discount_amount=discount_amount_supplier2)

    basket.uncache()
    lines = basket.get_final_lines()
    assert len(lines) == 5
    assert basket.total_price.value == 50  # -10d - 40d from 100d
    line = _get_discount_line(lines, 40)
    assert line.supplier == supplier2
예제 #17
0
def test_multiple_campaigns_match_with_coupon(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()
    # create a basket rule that requires atleast value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    product_price = "200"

    discount1 = "10"
    discount2 = "20"
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=product_price)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    campaign = BasketCampaign.objects.create(shop=shop,
                                             public_name="test",
                                             name="test",
                                             active=True)
    campaign.conditions.add(rule)
    campaign.save()

    BasketDiscountAmount.objects.create(discount_amount=discount1,
                                        campaign=campaign)

    dc = Coupon.objects.create(code="TEST", active=True)
    campaign2 = BasketCampaign.objects.create(shop=shop,
                                              public_name="test",
                                              name="test",
                                              coupon=dc,
                                              active=True)

    BasketDiscountAmount.objects.create(discount_amount=discount2,
                                        campaign=campaign2)

    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)

    resp = handle_add_campaign_code(request, basket, dc.code)
    assert resp.get("ok")

    discount_lines_values = [
        line.discount_amount for line in basket.get_final_lines()
    ]
    assert price(discount1) in discount_lines_values
    assert price(discount2) in discount_lines_values
    assert basket.total_price == (price(product_price) * basket.product_count -
                                  price(discount1) - price(discount2))
예제 #18
0
def test_basket_category_discount(rf):
    """
    Test that discounting based on product category works.
    """

    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    category = CategoryFactory()

    discount_amount_value = 6
    single_product_price = 10

    def create_category_product(category):
        product = create_product(printable_gibberish(), shop, supplier,
                                 single_product_price)
        product.primary_category = category

        sp = ShopProduct.objects.get(product=product, shop=shop)
        sp.primary_category = category
        sp.categories.add(category)

        return product

    basket_condition = CategoryProductsBasketCondition.objects.create(
        quantity=2)
    basket_condition.categories.add(category)

    campaign = BasketCampaign.objects.create(shop=shop,
                                             public_name="test",
                                             name="test",
                                             active=True)
    campaign.conditions.add(basket_condition)
    campaign.save()

    DiscountFromCategoryProducts.objects.create(
        campaign=campaign,
        discount_amount=discount_amount_value,
        category=category)
    basket.save()

    products = [create_category_product(category) for i in range(2)]
    for product in products:
        basket.add_product(supplier=supplier,
                           shop=shop,
                           product=product,
                           quantity=1)
        basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    assert basket.product_count == 2
    assert basket_condition.matches(basket=basket, lines=basket.get_lines())
    assert campaign.rules_match(basket, basket.get_lines())
    assert basket.total_price == price(single_product_price * 2) - price(
        discount_amount_value * 2)
예제 #19
0
def test_product_category_discount_percentage_greater_then_products(
        rf, include_tax):
    # Buy X amount of Y get Z discount from Y
    request, shop, _ = initialize_test(rf, include_tax)

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    single_product_price = "50"
    discount_percentage = Decimal(1.9)  # 190%
    quantity = 2

    # the expected discount amount should not be greater than the products
    expected_discount_amount = basket.create_price(
        single_product_price) * quantity

    category = CategoryFactory()

    # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=single_product_price)
    ShopProduct.objects.get(shop=shop,
                            product=product).categories.add(category)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    rule = ProductsInBasketCondition.objects.create(quantity=2)
    rule.products.add(product)
    rule.save()

    campaign = BasketCampaign.objects.create(active=True,
                                             shop=shop,
                                             name="test",
                                             public_name="test")
    campaign.conditions.add(rule)

    DiscountFromCategoryProducts.objects.create(
        campaign=campaign,
        discount_percentage=discount_percentage,
        category=category)
    assert rule.matches(basket, [])
    basket.uncache()

    final_lines = basket.get_final_lines()

    assert len(final_lines
               ) == 2  # no new lines since the effect touches original lines

    original_price = basket.create_price(single_product_price) * quantity
    line = final_lines[0]
    assert line.discount_amount == expected_discount_amount
    assert basket.total_price == original_price - expected_discount_amount
예제 #20
0
def create_service(shop, line, tax_classes):
    assert line.quantity == 1 and line.discount == 0
    if line.is_payment:
        meth = get_payment_method(shop=shop, price=line.price, name=line.payment_name)
    elif line.is_shipping:
        meth = get_shipping_method(shop=shop, price=line.price, name=line.shipping_name)
    meth.tax_class = tax_classes[line.tax_name]
    meth.save()
    return meth
예제 #21
0
def test_basket_campaign_module_case1(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    single_product_price = "50"
    discount_amount_value = "10"

    # create basket rule that requires 2 products in basket
    basket_rule1 = BasketTotalProductAmountCondition.objects.create(value="2")

    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=single_product_price)

    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    assert basket.product_count == 1

    campaign = BasketCampaign.objects.create(shop=shop,
                                             public_name="test",
                                             name="test",
                                             active=True)
    campaign.conditions.add(basket_rule1)
    campaign.save()
    BasketDiscountAmount.objects.create(campaign=campaign,
                                        discount_amount=discount_amount_value)

    assert len(basket.get_final_lines()) == 2  # case 1
    assert basket.total_price == price(single_product_price)  # case 1

    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.save()

    assert len(basket.get_final_lines()) == 3  # case 1
    assert basket.product_count == 2
    assert basket.total_price == (
        price(single_product_price) * basket.product_count -
        price(discount_amount_value))
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]

    # Make sure disabling campaign disables it conditions
    assert campaign.conditions.filter(active=True).exists()
    campaign.active = False
    campaign.save()
    assert not campaign.conditions.filter(active=True).exists()
예제 #22
0
def test_waiver():
    sm = get_shipping_method(name="Waivey", price=100, waive_at=370)
    source = BasketishOrderSource(get_default_shop())
    assert sm.get_effective_name(source) == u"Waivey"
    assert sm.get_total_cost(source).price == source.create_price(100)
    source.add_line(
        type=OrderLineType.PRODUCT, product=get_default_product(), base_unit_price=source.create_price(400), quantity=1
    )
    assert sm.get_total_cost(source).price == source.create_price(0)
예제 #23
0
def test_campaign_with_coupons(rf):
    status = get_initial_order_status()
    request, shop, group = initialize_test(rf, False)
    basket = get_basket(request)
    supplier = get_default_supplier()

    for x in range(2):
        product = create_product(printable_gibberish(),
                                 shop,
                                 supplier=supplier,
                                 default_price="50")
        basket.add_product(supplier=supplier,
                           shop=shop,
                           product=product,
                           quantity=1)

    basket.shipping_method = get_shipping_method(
        shop=shop)  # For shippable products
    dc = Coupon.objects.create(code="TEST", active=True)
    campaign = BasketCampaign.objects.create(shop=shop,
                                             name="test",
                                             public_name="test",
                                             coupon=dc,
                                             active=True)
    BasketDiscountAmount.objects.create(
        discount_amount=shop.create_price("20"), campaign=campaign)
    rule = BasketTotalProductAmountCondition.objects.create(value=2)
    campaign.conditions.add(rule)
    campaign.save()

    assert len(basket.get_final_lines()
               ) == 3  # no discount was applied because coupon is required

    basket.add_code(dc.code)

    assert len(basket.get_final_lines()
               ) == 4  # now basket has codes so they will be applied too
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]

    # Ensure codes persist between requests, so do what the middleware would, i.e.
    basket.save()
    # and then reload the basket:
    del request.basket
    basket = get_basket(request)

    assert basket.codes == [dc.code]
    assert len(basket.get_final_lines()
               ) == 3  # now basket has codes so they will be applied too
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]

    basket.status = status
    creator = OrderCreator(request)
    order = creator.create_order(basket)
    assert CouponUsage.objects.filter(order=order).count() == 1
    assert CouponUsage.objects.filter(order=order,
                                      coupon__code=dc.code).count() == 1
예제 #24
0
def _get_frontend_order_state(shop, contact):
    tax = Tax.objects.create(code="test_code",
                             rate=decimal.Decimal("0.20"),
                             name="Default")
    tax_class = TaxClass.objects.create(identifier="test_tax_class",
                                        name="Default")
    rule = TaxRule.objects.create(tax=tax)
    rule.tax_classes.add(tax_class)
    rule.save()
    supplier = get_default_supplier(shop)
    product = create_product(sku=printable_gibberish(),
                             supplier=supplier,
                             shop=shop)
    product.tax_class = tax_class
    product.save()
    lines = [{
        "id": "x",
        "type": "product",
        "product": {
            "id": product.id
        },
        "quantity": "32",
        "baseUnitPrice": 50,
        "supplier": {
            "name": supplier.name,
            "id": supplier.id
        },
    }]

    state = {
        "customer": {
            "id": contact.id if contact else None,
            "billingAddress": _encode_address(contact.default_billing_address)
            if contact else {},
            "shippingAddress": _encode_address(
                contact.default_shipping_address) if contact else {},
        },
        "lines": lines,
        "methods": {
            "shippingMethod": {
                "id": get_shipping_method(shop=shop).id
            },
            "paymentMethod": {
                "id": get_payment_method(shop=shop).id
            },
        },
        "shop": {
            "selected": {
                "id": shop.id,
                "name": shop.safe_translation_getter("name"),
                "currency": shop.currency,
                "priceIncludeTaxes": shop.prices_include_tax,
            }
        },
    }
    return state
예제 #25
0
def test_productdiscountamount_with_minimum_price(rf, per_line_discount):
    # Buy X amount of Y get Z discount from Y
    request, shop, _ = initialize_test(rf, False)

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    single_product_price = Decimal("50")
    single_product_min_price = Decimal("40")
    discount_amount_value = Decimal("200")  # will exceed the minimum price
    quantity = 2

    # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=single_product_price)
    shop_product = ShopProduct.objects.get(product=product, shop=shop)
    shop_product.minimum_price_value = single_product_min_price
    shop_product.save()

    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    rule = ProductsInBasketCondition.objects.create(quantity=2)
    rule.products.add(product)
    rule.save()

    campaign = BasketCampaign.objects.create(active=True,
                                             shop=shop,
                                             name="test",
                                             public_name="test")
    campaign.conditions.add(rule)

    effect = DiscountFromProduct.objects.create(
        campaign=campaign,
        discount_amount=discount_amount_value,
        per_line_discount=per_line_discount)
    effect.products.add(product)

    assert rule.matches(basket, [])
    basket.uncache()

    # the discount amount should not exceed the minimum price. as the configued discount
    # will exceed, it should limit the discount amount
    final_lines = basket.get_final_lines()
    expected_discount_amount = basket.create_price(
        (single_product_price - single_product_min_price) * quantity)
    original_price = basket.create_price(single_product_price) * quantity
    line = final_lines[0]
    assert line.discount_amount == expected_discount_amount
    assert basket.total_price == original_price - expected_discount_amount
예제 #26
0
def test_basket_free_product(rf):
    request, shop, _ = initialize_test(rf, False)

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = "50"
    original_quantity = 2
    # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=2)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    second_product = create_product(printable_gibberish(),
                                    shop=shop,
                                    supplier=supplier,
                                    default_price=single_product_price)

    # no shop
    third_product = create_product(printable_gibberish(), supplier=supplier)

    rule = BasketTotalProductAmountCondition.objects.create(value="2")

    campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test")
    campaign.conditions.add(rule)

    effect = FreeProductLine.objects.create(campaign=campaign, quantity=2)
    effect.products.add(second_product)
    discount_lines_count = len(effect.get_discount_lines(basket, [], supplier))
    assert discount_lines_count == 1

    # do not affect as there is no shop product for the product
    effect.products.add(third_product)
    assert len(effect.get_discount_lines(basket, [], supplier)) == discount_lines_count

    basket.uncache()
    final_lines = basket.get_final_lines()

    assert len(final_lines) == 3

    line_types = [l.type for l in final_lines]
    assert OrderLineType.DISCOUNT not in line_types

    for line in basket.get_final_lines():
        assert line.type in [OrderLineType.PRODUCT, OrderLineType.SHIPPING]
        if line.type == OrderLineType.SHIPPING:
            continue
        if line.product != product:
            assert line.product == second_product
            assert line.line_source == LineSource.DISCOUNT_MODULE
            assert line.quantity == original_quantity
        else:
            assert line.line_source == LineSource.CUSTOMER
예제 #27
0
def test_basket_free_product(rf):
    request, shop, _ = initialize_test(rf, False)

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    single_product_price = "50"
    original_quantity = 2
    # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=2)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    second_product = create_product(printable_gibberish(),
                                    shop=shop,
                                    supplier=supplier,
                                    default_price=single_product_price)

    # no shop
    third_product = create_product(printable_gibberish(), supplier=supplier)

    rule = BasketTotalProductAmountCondition.objects.create(value="2")

    campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test")
    campaign.conditions.add(rule)

    effect = FreeProductLine.objects.create(campaign=campaign, quantity=2)
    effect.products.add(second_product)
    discount_lines_count = len(effect.get_discount_lines(basket, [], supplier))
    assert discount_lines_count == 1

    # do not affect as there is no shop product for the product
    effect.products.add(third_product)
    assert len(effect.get_discount_lines(basket, [], supplier)) == discount_lines_count

    basket.uncache()
    final_lines = basket.get_final_lines()

    assert len(final_lines) == 3

    line_types = [l.type for l in final_lines]
    assert OrderLineType.DISCOUNT not in line_types

    for line in basket.get_final_lines():
        assert line.type in [OrderLineType.PRODUCT, OrderLineType.SHIPPING]
        if line.type == OrderLineType.SHIPPING:
            continue
        if line.product != product:
            assert line.product == second_product
            assert line.line_source == LineSource.DISCOUNT_MODULE
            assert line.quantity == original_quantity
        else:
            assert line.line_source == LineSource.CUSTOMER
예제 #28
0
def create_service(shop, line, tax_classes):
    assert line.quantity == 1 and line.discount == 0
    if line.is_payment:
        meth = get_payment_method(
            shop=shop, price=line.price, name=line.payment_name)
    elif line.is_shipping:
        meth = get_shipping_method(
            shop=shop, price=line.price, name=line.shipping_name)
    meth.tax_class = tax_classes[line.tax_name]
    meth.save()
    return meth
예제 #29
0
def _init_test_for_product_with_basket(rf, default_price):
    request, product = _init_test_for_product_without_basket(rf, default_price)
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    basket = get_basket(request)
    basket.status = factories.get_initial_order_status()
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = factories.get_shipping_method(shop=shop)
    basket.payment_method = factories.get_payment_method(shop=shop)
    assert basket.shop == request.shop
    assert basket.customer == request.customer
    return request, product, basket
예제 #30
0
def test_undiscounted_effects(rf, include_tax):
    request, shop, _ = initialize_test(rf, include_tax)

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    single_product_price = Decimal(50)
    discounted_product_quantity = 4
    normal_priced_product_quantity = 2
    discount_percentage = Decimal(0.2)  # 20%
    discount_amount = basket.create_price(single_product_price * normal_priced_product_quantity * discount_percentage)

    category = CategoryFactory()

    discounted_product = create_product(
        printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price
    )
    second_product = create_product(
        printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price
    )

    ShopProduct.objects.get(shop=shop, product=discounted_product).categories.add(category)
    ShopProduct.objects.get(shop=shop, product=second_product).categories.add(category)
    basket.add_product(supplier=supplier, shop=shop, product=discounted_product, quantity=discounted_product_quantity)
    basket.add_product(supplier=supplier, shop=shop, product=second_product, quantity=normal_priced_product_quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    # Store basket price before any campaigns exists
    original_price = basket.total_price

    # CatalogCampaign
    catalog_campaign = CatalogCampaign.objects.create(active=True, shop=shop, name="test", public_name="test")
    # Limit catalog campaign to "discounted_product"
    product_filter = ProductFilter.objects.create()
    product_filter.products.add(discounted_product)
    catalog_campaign.filters.add(product_filter)

    # BasketCampaign
    campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test2", public_name="test2")

    final_lines = basket.get_final_lines()
    assert len(final_lines) == 3

    # Discount based on undiscounted product values
    DiscountPercentageFromUndiscounted.objects.create(campaign=campaign, discount_percentage=discount_percentage)

    basket.uncache()
    final_lines = basket.get_final_lines()
    assert len(final_lines) == 4

    discounted_basket_price = original_price - discount_amount
    assert basket.total_price.as_rounded() == discounted_basket_price.as_rounded()
예제 #31
0
def test_fixed_cost_with_waiving_costs():
    sm = get_shipping_method(name="Fixed and waiving", price=5)

    sm.behavior_components.add(*[
        WaivingCostBehaviorComponent.objects.create(price_value=p,
                                                    waive_limit_value=w)
        for (p, w) in [(3, 5), (7, 10), (10, 30)]
    ])

    source = BasketishOrderSource(get_default_shop())
    source.shipping_method = sm

    def pricestr(pi):
        assert pi.price.unit_matches_with(source.create_price(0))
        return "%.0f EUR (%.0f EUR)" % (pi.price.value, pi.base_price.value)

    assert pricestr(sm.get_total_cost(source)) == "25 EUR (25 EUR)"
    assert source.total_price.value == 25

    source.add_line(type=OrderLineType.PRODUCT,
                    product=get_default_product(),
                    base_unit_price=source.create_price(2),
                    quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "25 EUR (25 EUR)"
    assert source.total_price.value == 27

    source.add_line(type=OrderLineType.PRODUCT,
                    product=get_default_product(),
                    base_unit_price=source.create_price(3),
                    quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "22 EUR (25 EUR)"
    assert source.total_price.value == 27

    source.add_line(type=OrderLineType.PRODUCT,
                    product=get_default_product(),
                    base_unit_price=source.create_price(10),
                    quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "15 EUR (25 EUR)"
    assert source.total_price.value == 30

    source.add_line(type=OrderLineType.PRODUCT,
                    product=get_default_product(),
                    base_unit_price=source.create_price(10),
                    quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "15 EUR (25 EUR)"
    assert source.total_price.value == 40

    source.add_line(type=OrderLineType.PRODUCT,
                    product=get_default_product(),
                    base_unit_price=source.create_price(10),
                    quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "5 EUR (25 EUR)"
    assert source.total_price.value == 40
예제 #32
0
def test_waiver():
    sm = get_shipping_method(name="Waivey", price=100, waive_at=370)
    source = BasketishOrderSource(get_default_shop())
    assert sm.get_effective_name(source) == u"Waivey"
    assert sm.get_total_cost(source).price == source.create_price(100)
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=get_default_product(),
        base_unit_price=source.create_price(400),
        quantity=1
    )
    assert sm.get_total_cost(source).price == source.create_price(0)
예제 #33
0
def _init_test_for_product_with_basket(rf, default_price):
    request, product = _init_test_for_product_without_basket(rf, default_price)
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    basket = get_basket(request)
    basket.status = factories.get_initial_order_status()
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = factories.get_shipping_method(shop=shop)
    basket.payment_method = factories.get_payment_method(shop=shop)
    assert basket.shop == request.shop
    assert basket.customer == request.customer
    return request, product, basket
예제 #34
0
def test_percentage_campaign_different_coupon_supplier(rf):
    request, shop, group = initialize_test(rf, True)
    create_default_order_statuses()

    basket = get_basket(request)
    supplier = get_default_supplier(shop)
    supplier_2 = Supplier.objects.create(name="Supplier 2")

    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=200)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.status = get_initial_order_status()

    # Create coupon that is attached to Supplier 2
    coupon = Coupon.objects.create(code="QWERTY",
                                   shop=shop,
                                   active=True,
                                   supplier=supplier_2)
    # create basket with coupon code
    campaign = BasketCampaign.objects.create(shop=shop,
                                             public_name="test",
                                             name="test",
                                             active=True,
                                             coupon=coupon,
                                             supplier=supplier_2)
    BasketDiscountPercentage.objects.create(campaign=campaign,
                                            discount_percentage=Decimal(1))
    basket.add_code(coupon.code)

    # discount is never applied as there is no line
    # in the basket that matches the coupon's supplier
    lines_types = [line.type for line in basket.get_final_lines()]
    assert OrderLineType.DISCOUNT not in lines_types
    assert basket.product_count == 1
    assert basket.total_price.value == Decimal(200)

    # make supplier be the default supplier
    coupon.supplier = supplier
    coupon.save()
    campaign.supplier = supplier
    campaign.save()
    basket.uncache()

    lines_types = [line.type for line in basket.get_final_lines()]
    assert OrderLineType.DISCOUNT in lines_types
    assert basket.product_count == 1
    assert basket.total_price.value == Decimal()
예제 #35
0
def test_undiscounted_effects(rf, include_tax):
    request, shop, _ = initialize_test(rf, include_tax)

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = Decimal(50)
    discounted_product_quantity = 4
    normal_priced_product_quantity = 2
    discount_percentage = Decimal(0.2)  # 20%
    discount_amount = basket.create_price(single_product_price * normal_priced_product_quantity * discount_percentage)

    category = CategoryFactory()

    discounted_product = create_product(
        printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    second_product = create_product(
        printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)

    ShopProduct.objects.get(shop=shop, product=discounted_product).categories.add(category)
    ShopProduct.objects.get(shop=shop, product=second_product).categories.add(category)
    basket.add_product(supplier=supplier, shop=shop, product=discounted_product, quantity=discounted_product_quantity)
    basket.add_product(supplier=supplier, shop=shop, product=second_product, quantity=normal_priced_product_quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    # Store basket price before any campaigns exists
    original_price = basket.total_price

    # CatalogCampaign
    catalog_campaign = CatalogCampaign.objects.create(active=True, shop=shop, name="test", public_name="test")
    # Limit catalog campaign to "discounted_product"
    product_filter = ProductFilter.objects.create()
    product_filter.products.add(discounted_product)
    catalog_campaign.filters.add(product_filter)

    # BasketCampaign
    campaign = BasketCampaign.objects.create(
        active=True, shop=shop, name="test2", public_name="test2")

    final_lines = basket.get_final_lines()
    assert len(final_lines) == 3

    # Discount based on undiscounted product values
    DiscountPercentageFromUndiscounted.objects.create(campaign=campaign, discount_percentage=discount_percentage)

    basket.uncache()
    final_lines = basket.get_final_lines()
    assert len(final_lines) == 4

    discounted_basket_price = original_price - discount_amount
    assert basket.total_price.as_rounded() == discounted_basket_price.as_rounded()
예제 #36
0
def test_multiple_campaigns_match_with_coupon(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()
    # create a basket rule that requires atleast value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    product_price = "200"

    discount1 = "10"
    discount2 = "20"
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    campaign = BasketCampaign.objects.create(shop=shop, public_name="test", name="test", active=True)
    campaign.conditions.add(rule)
    campaign.save()

    BasketDiscountAmount.objects.create(discount_amount=discount1, campaign=campaign)

    dc = Coupon.objects.create(code="TEST", active=True)
    campaign2 = BasketCampaign.objects.create(
        shop=shop, public_name="test",
        name="test",
        coupon=dc,
        active=True
    )

    BasketDiscountAmount.objects.create(discount_amount=discount2, campaign=campaign2)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)

    resp = handle_add_campaign_code(request, basket, dc.code)
    assert resp.get("ok")

    discount_lines_values = [line.discount_amount for line in basket.get_final_lines() if line.type == OrderLineType.DISCOUNT]
    assert price(discount1) in discount_lines_values
    assert price(discount2) in discount_lines_values
    assert basket.total_price == (price(product_price) * basket.product_count - price(discount1) - price(discount2))

    assert basket.codes == [dc.code]

    # test code removal
    resp = handle_remove_campaign_code(request, basket, dc.code)
    assert resp.get("ok")

    assert basket.codes == []
    discount_lines_values = [line.discount_amount for line in basket.get_final_lines() if line.type == OrderLineType.DISCOUNT]
    assert price(discount1) in discount_lines_values
    assert not price(discount2) in discount_lines_values
def test_category_products_effect_with_amount(rf):
    request, shop, group = initialize_test(rf, False)

    basket = get_basket(request)
    category = get_default_category()
    supplier = get_default_supplier()

    single_product_price = "50"
    discount_amount_value = "10"
    quantity = 5

    product = create_product("The product",
                             shop=shop,
                             supplier=supplier,
                             default_price=single_product_price)
    shop_product = product.get_shop_instance(shop)
    shop_product.categories.add(category)

    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    rule = CategoryProductsBasketCondition.objects.create(
        operator=ComparisonOperator.EQUALS, quantity=quantity)
    rule.categories.add(category)

    campaign = BasketCampaign.objects.create(active=True,
                                             shop=shop,
                                             name="test",
                                             public_name="test")
    campaign.conditions.add(rule)

    DiscountFromCategoryProducts.objects.create(
        campaign=campaign,
        category=category,
        discount_amount=discount_amount_value)

    assert rule.matches(basket, [])
    basket.uncache()
    final_lines = basket.get_final_lines()

    assert len(final_lines
               ) == 2  # no new lines since the effect touches original lines
    expected_discount_amount = quantity * basket.create_price(
        discount_amount_value)
    original_price = basket.create_price(single_product_price) * quantity
    line = final_lines[0]
    assert line.discount_amount == expected_discount_amount
    assert basket.total_price == original_price - expected_discount_amount
예제 #38
0
def test_productdiscountamount(rf):
    # Buy X amount of Y get Z discount from Y
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = "50"
    discount_amount_value = "10"
    quantity = 2

    # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=single_product_price)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    rule = ProductsInBasketCondition.objects.create(quantity=2)
    rule.products.add(product)
    rule.save()

    campaign = BasketCampaign.objects.create(active=True,
                                             shop=shop,
                                             name="test",
                                             public_name="test")
    campaign.conditions.add(rule)

    effect = DiscountFromProduct.objects.create(
        campaign=campaign, discount_amount=discount_amount_value)
    effect.products.add(product)

    assert rule.matches(basket, [])
    basket.uncache()

    final_lines = basket.get_final_lines()

    assert len(final_lines
               ) == 2  # no new lines since the effect touches original lines
    expected_discount_amount = basket.create_price(discount_amount_value)
    original_price = basket.create_price(single_product_price) * quantity
    line = final_lines[0]
    assert line.discount_amount == expected_discount_amount
    assert basket.total_price == original_price - expected_discount_amount
예제 #39
0
def test_basket_category_discount(rf):
    """
    Test that discounting based on product category works.
    """

    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()

    category = CategoryFactory()

    discount_amount_value = 6
    single_product_price = 10

    def create_category_product(category):
        product = create_product(printable_gibberish(), shop, supplier, single_product_price)
        product.primary_category = category

        sp = ShopProduct.objects.get(product=product, shop=shop)
        sp.primary_category = category
        sp.categories.add(category)

        return product

    basket_condition = CategoryProductsBasketCondition.objects.create(quantity=2)
    basket_condition.categories.add(category)

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True
    )
    campaign.conditions.add(basket_condition)
    campaign.save()

    DiscountFromCategoryProducts.objects.create(
        campaign=campaign, discount_amount=discount_amount_value, category=category
    )
    basket.save()

    products = [create_category_product(category) for i in range(2)]
    for product in products:
        basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
        basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    assert basket.product_count == 2
    assert basket_condition.matches(basket=basket, lines=basket.get_lines())
    assert campaign.rules_match(basket, basket.get_lines())
    assert basket.total_price == price(single_product_price * 2) - price(discount_amount_value * 2)
예제 #40
0
def test_only_cheapest_price_is_selected(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier(shop)
    # create a basket rule that requires atleast value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    product_price = "200"

    discount1 = "10"
    discount2 = "20"  # should be selected
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=product_price)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    campaign1 = BasketCampaign.objects.create(shop=shop,
                                              public_name="test",
                                              name="test",
                                              active=True)
    campaign1.conditions.add(rule)
    campaign1.save()
    BasketDiscountAmount.objects.create(discount_amount=discount1,
                                        campaign=campaign1)

    campaign2 = BasketCampaign.objects.create(shop=shop,
                                              public_name="test",
                                              name="test",
                                              active=True)
    campaign2.conditions.add(rule)
    campaign2.save()
    BasketDiscountAmount.objects.create(discount_amount=discount2,
                                        campaign=campaign2)

    assert len(basket.get_final_lines()) == 3

    line_types = [l.type for l in basket.get_final_lines()]
    assert OrderLineType.DISCOUNT in line_types

    for line in basket.get_final_lines():
        if line.type == OrderLineType.DISCOUNT:
            assert line.discount_amount == price(discount2)
예제 #41
0
def test_product_category_discount_amount_with_minimum_price(rf):
    # Buy X amount of Y get Z discount from Y
    request, shop, _ = initialize_test(rf, False)

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = Decimal("50")
    single_product_min_price = Decimal("40")
    discount_amount_value = Decimal("200") # will exceed the minimum price
    quantity = 2

    # the expected discount amount should not be greater than the products
    expected_discount_amount = basket.create_price(single_product_price) * quantity

    category = CategoryFactory()

     # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    shop_product = ShopProduct.objects.get(shop=shop, product=product)
    shop_product.minimum_price_value = single_product_min_price
    shop_product.save()
    shop_product.categories.add(category)

    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    rule = ProductsInBasketCondition.objects.create(quantity=2)
    rule.products.add(product)
    rule.save()

    campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test")
    campaign.conditions.add(rule)

    DiscountFromCategoryProducts.objects.create(campaign=campaign,
                                                discount_amount=discount_amount_value,
                                                category=category)
    assert rule.matches(basket, [])
    basket.uncache()

    # the discount amount should not exceed the minimum price. as the configued discount
    # will exceed, it should limit the discount amount
    final_lines = basket.get_final_lines()
    expected_discount_amount = basket.create_price((single_product_price - single_product_min_price) * quantity)
    original_price = basket.create_price(single_product_price) * quantity
    line = final_lines[0]
    assert line.discount_amount == expected_discount_amount
    assert basket.total_price == original_price - expected_discount_amount
예제 #42
0
def _create_order(request, customer, coupon, product, expected_product_price):
    creator = OrderCreator(request)
    shop = request.shop
    request.basket = None
    request.customer = customer
    basket = get_basket(request)
    basket.status = factories.get_initial_order_status()
    basket.add_product(supplier=factories.get_default_supplier(), shop=shop, product=product, quantity=1)
    basket.shipping_method = factories.get_shipping_method(shop=shop)
    basket.payment_method = factories.get_payment_method(shop=shop)
    basket.add_code(coupon)
    assert basket.shop == request.shop
    assert basket.customer == request.customer
    assert product.get_price_info(request).price == expected_product_price
    creator.create_order(basket)
예제 #43
0
def _create_order(request, customer, coupon, product, expected_product_price):
    creator = OrderCreator(request)
    shop = request.shop
    request.basket = None
    request.customer = customer
    basket = get_basket(request)
    basket.status = factories.get_initial_order_status()
    basket.add_product(supplier=factories.get_default_supplier(), shop=shop, product=product, quantity=1)
    basket.shipping_method = factories.get_shipping_method(shop=shop)
    basket.payment_method = factories.get_payment_method(shop=shop)
    basket.add_code(coupon)
    assert basket.shop == request.shop
    assert basket.customer == request.customer
    assert product.get_price_info(request).price == expected_product_price
    creator.create_order(basket)
예제 #44
0
def test_basket(rf, storage):
    StoredBasket.objects.all().delete()
    quantities = [3, 12, 44, 23, 65]
    shop = get_default_shop()
    get_default_payment_method()  # Can't create baskets without payment methods
    supplier = get_default_supplier()
    products_and_quantities = []
    for quantity in quantities:
        product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=50)
        products_and_quantities.append((product, quantity))

    is_database = (storage == "shuup.front.basket.storage:DatabaseBasketStorage")
    with override_settings(SHUUP_BASKET_STORAGE_CLASS_SPEC=storage):
        for product, q in products_and_quantities:
            request = rf.get("/")
            request.session = {}
            request.shop = shop
            apply_request_middleware(request)
            basket = get_basket(request)
            assert basket == request.basket
            assert basket.product_count == 0
            line = basket.add_product(supplier=supplier, shop=shop, product=product, quantity=q)
            basket.shipping_method = get_shipping_method(shop=shop)  # For shippable product
            assert line.quantity == q
            assert basket.get_lines()
            assert basket.get_product_ids_and_quantities().get(product.pk) == q
            assert basket.product_count == q
            basket.save()
            delattr(request, "basket")
            basket = get_basket(request)
            assert basket.get_product_ids_and_quantities().get(product.pk) == q
            if is_database:
                product_ids = set(StoredBasket.objects.last().products.values_list("id", flat=True))
                assert product_ids == set([product.pk])

        if is_database:
            stats = StoredBasket.objects.all().aggregate(
                n=Sum("product_count"),
                tfs=Sum("taxful_total_price_value"),
                tls=Sum("taxless_total_price_value"),
            )
            assert stats["n"] == sum(quantities)
            if shop.prices_include_tax:
                assert stats["tfs"] == sum(quantities) * 50
            else:
                assert stats["tls"] == sum(quantities) * 50

        basket.finalize()
예제 #45
0
def test_basket_free_product_coupon(rf):
    request, shop, _ = initialize_test(rf, False)

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = "50"
    discount_amount_value = "10"

     # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    second_product = create_product(printable_gibberish(),
                                    shop=shop,
                                    supplier=supplier,
                                    default_price=single_product_price)

    rule = BasketTotalProductAmountCondition.objects.create(value="2")
    coupon = Coupon.objects.create(code="TEST", active=True)

    campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test", coupon=coupon)
    campaign.conditions.add(rule)

    effect = FreeProductLine.objects.create(campaign=campaign)
    effect.products.add(second_product)

    basket.add_code(coupon.code)

    basket.uncache()
    final_lines = basket.get_final_lines()

    assert len(final_lines) == 3

    line_types = [l.type for l in final_lines]
    assert OrderLineType.DISCOUNT not in line_types

    for line in basket.get_final_lines():
        assert line.type in [OrderLineType.PRODUCT, OrderLineType.SHIPPING]
        if line.type == OrderLineType.SHIPPING:
            continue

        if line.product != product:
            assert line.product == second_product
예제 #46
0
def test_fixed_cost_with_waiving_costs():
    sm = get_shipping_method(name="Fixed and waiving", price=5)

    sm.behavior_components.add(
        *[WaivingCostBehaviorComponent.objects.create(
            price_value=p, waive_limit_value=w)
          for (p, w) in [(3, 5), (7, 10), (10, 30)]])

    source = BasketishOrderSource(get_default_shop())
    source.shipping_method = sm

    def pricestr(pi):
        assert pi.price.unit_matches_with(source.create_price(0))
        return "%.0f EUR (%.0f EUR)" % (pi.price.value, pi.base_price.value)

    assert pricestr(sm.get_total_cost(source)) == "25 EUR (25 EUR)"
    assert source.total_price.value == 25

    source.add_line(
        type=OrderLineType.PRODUCT, product=get_default_product(),
        base_unit_price=source.create_price(2), quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "25 EUR (25 EUR)"
    assert source.total_price.value == 27

    source.add_line(
        type=OrderLineType.PRODUCT, product=get_default_product(),
        base_unit_price=source.create_price(3), quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "22 EUR (25 EUR)"
    assert source.total_price.value == 27

    source.add_line(
        type=OrderLineType.PRODUCT, product=get_default_product(),
        base_unit_price=source.create_price(10), quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "15 EUR (25 EUR)"
    assert source.total_price.value == 30

    source.add_line(
        type=OrderLineType.PRODUCT, product=get_default_product(),
        base_unit_price=source.create_price(10), quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "15 EUR (25 EUR)"
    assert source.total_price.value == 40

    source.add_line(
        type=OrderLineType.PRODUCT, product=get_default_product(),
        base_unit_price=source.create_price(10), quantity=1)
    assert pricestr(sm.get_total_cost(source)) == "5 EUR (25 EUR)"
    assert source.total_price.value == 40
예제 #47
0
def test_basket_campaign_case2(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()
     # create a basket rule that requires at least value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    single_product_price = "50"
    discount_amount_value = "10"

    unique_shipping_method = get_shipping_method(shop, price=50)

    for x in range(3):
        product = create_product(
            printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
        basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)

    assert basket.product_count == 3

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True)
    campaign.conditions.add(rule)
    campaign.save()

    BasketDiscountAmount.objects.create(discount_amount=discount_amount_value, campaign=campaign)

    assert len(basket.get_final_lines()) == 3
    assert basket.total_price == price(single_product_price) * basket.product_count

    # check that shipping method affects campaign
    basket.shipping_method = unique_shipping_method
    basket.save()
    basket.uncache()
    assert len(basket.get_final_lines()) == 4  # Shipping should not affect the rule being triggered

    line_types = [l.type for l in basket.get_final_lines()]
    assert OrderLineType.DISCOUNT not in line_types

    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)

    assert len(basket.get_final_lines()) == 6  # Discount included
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]
예제 #48
0
def test_basket_campaign_case2(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()
     # create a basket rule that requires at least value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    single_product_price = "50"
    discount_amount_value = "10"

    unique_shipping_method = get_shipping_method(shop, price=50)

    for x in range(3):
        product = create_product(
            printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
        basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)

    assert basket.product_count == 3

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True)
    campaign.conditions.add(rule)
    campaign.save()

    BasketDiscountAmount.objects.create(discount_amount=discount_amount_value, campaign=campaign)

    assert len(basket.get_final_lines()) == 3
    assert basket.total_price == price(single_product_price) * basket.product_count

    # check that shipping method affects campaign
    basket.shipping_method = unique_shipping_method
    basket.save()
    basket.uncache()
    assert len(basket.get_final_lines()) == 4  # Shipping should not affect the rule being triggered

    line_types = [l.type for l in basket.get_final_lines()]
    assert OrderLineType.DISCOUNT not in line_types

    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)

    assert len(basket.get_final_lines()) == 6  # Discount included
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]
예제 #49
0
def test_campaign_with_coupons(rf):
    status = get_initial_order_status()
    request, shop, group = initialize_test(rf, False)
    basket = get_basket(request)
    supplier = get_default_supplier()

    for x in range(2):
        product = create_product(printable_gibberish(), shop, supplier=supplier, default_price="50")
        basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)

    basket.shipping_method = get_shipping_method(shop=shop)  # For shippable products
    dc = Coupon.objects.create(code="TEST", active=True)
    campaign = BasketCampaign.objects.create(
            shop=shop,
            name="test", public_name="test",
            coupon=dc,
            active=True
    )
    BasketDiscountAmount.objects.create(discount_amount=shop.create_price("20"), campaign=campaign)
    rule = BasketTotalProductAmountCondition.objects.create(value=2)
    campaign.conditions.add(rule)
    campaign.save()

    assert len(basket.get_final_lines()) == 3  # no discount was applied because coupon is required

    basket.add_code(dc.code)

    assert len(basket.get_final_lines()) == 4  # now basket has codes so they will be applied too
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]

    # Ensure codes persist between requests, so do what the middleware would, i.e.
    basket.save()
    # and then reload the basket:
    del request.basket
    basket = get_basket(request)

    assert basket.codes == [dc.code]
    assert len(basket.get_final_lines()) == 3  # now basket has codes so they will be applied too
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]

    basket.status = status
    creator = OrderCreator(request)
    order = creator.create_order(basket)
    assert CouponUsage.objects.filter(order=order).count() == 1
    assert CouponUsage.objects.filter(order=order, coupon__code=dc.code).count() == 1
예제 #50
0
def _init_basket_coupon_test(rf, code="TEST"):
    status = get_initial_order_status()
    request, shop, group = initialize_test(rf, False)
    basket = get_basket(request)
    supplier = get_default_supplier()
    for x in range(2):
        product = create_product(printable_gibberish(), shop, supplier=supplier, default_price="50")
        basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)  # For shippable products
    dc = Coupon.objects.create(code=code, active=True)
    campaign = BasketCampaign.objects.create(
        shop=shop, name="test", public_name="test", coupon=dc, active=True
    )
    BasketDiscountAmount.objects.create(discount_amount=shop.create_price("20"), campaign=campaign)
    rule = BasketTotalProductAmountCondition.objects.create(value=2)
    campaign.conditions.add(rule)
    campaign.save()
    return basket, dc, request, status
예제 #51
0
def _init_basket_coupon_test(rf, code="TEST"):
    status = get_initial_order_status()
    request, shop, group = initialize_test(rf, False)
    basket = get_basket(request)
    supplier = get_default_supplier(shop)
    for x in range(2):
        product = create_product(printable_gibberish(), shop, supplier=supplier, default_price="50")
        basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)  # For shippable products
    dc = Coupon.objects.create(code=code, active=True)
    campaign = BasketCampaign.objects.create(
        shop=shop, name="test", public_name="test", coupon=dc, active=True
    )
    BasketDiscountAmount.objects.create(discount_amount=shop.create_price("20"), campaign=campaign)
    rule = BasketTotalProductAmountCondition.objects.create(value=2)
    campaign.conditions.add(rule)
    campaign.save()
    return basket, dc, request, status
def test_category_product_in_basket_condition(rf):
    request, shop, group = initialize_test(rf, False)
    basket = get_basket(request)
    supplier = get_default_supplier()
    category = get_default_category()
    product = create_product("The Product",
                             shop=shop,
                             default_price="200",
                             supplier=supplier)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    shop_product = product.get_shop_instance(shop)
    assert category not in shop_product.categories.all()

    condition = CategoryProductsBasketCondition.objects.create(
        operator=ComparisonOperator.EQUALS, quantity=1)
    condition.categories.add(category)

    # No match the product does not have the category
    assert not condition.matches(basket, [])

    category.shop_products.add(shop_product)
    assert condition.matches(basket, [])

    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    assert not condition.matches(basket, [])

    condition.operator = ComparisonOperator.GTE
    condition.save()

    assert condition.matches(basket, [])

    condition.excluded_categories.add(category)
    assert not condition.matches(basket, [])

    with pytest.raises(CampaignsInvalidInstanceForCacheUpdate):
        update_filter_cache("test", shop)
예제 #53
0
def test_product_category_discount_percentage_greater_then_products(rf, include_tax):
    # Buy X amount of Y get Z discount from Y
    request, shop, _ = initialize_test(rf, include_tax)

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = "50"
    discount_percentage = Decimal(1.9) # 190%
    quantity = 2

    # the expected discount amount should not be greater than the products
    expected_discount_amount = basket.create_price(single_product_price) * quantity

    category = CategoryFactory()

     # create basket rule that requires 2 products in basket
    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)
    ShopProduct.objects.get(shop=shop, product=product).categories.add(category)
    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=quantity)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    rule = ProductsInBasketCondition.objects.create(quantity=2)
    rule.products.add(product)
    rule.save()

    campaign = BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test")
    campaign.conditions.add(rule)

    DiscountFromCategoryProducts.objects.create(campaign=campaign,
                                                discount_percentage=discount_percentage,
                                                category=category)
    assert rule.matches(basket, [])
    basket.uncache()

    final_lines = basket.get_final_lines()

    assert len(final_lines) == 2  # no new lines since the effect touches original lines

    original_price = basket.create_price(single_product_price) * quantity
    line = final_lines[0]
    assert line.discount_amount == expected_discount_amount
    assert basket.total_price == original_price - expected_discount_amount
예제 #54
0
def test_basket_campaign_module_case1(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier()

    single_product_price = "50"
    discount_amount_value = "10"

     # create basket rule that requires 2 products in basket
    basket_rule1 = BasketTotalProductAmountCondition.objects.create(value="2")

    product = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=single_product_price)

    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    assert basket.product_count == 1

    campaign = BasketCampaign.objects.create(
        shop=shop, public_name="test", name="test", active=True)
    campaign.conditions.add(basket_rule1)
    campaign.save()
    BasketDiscountAmount.objects.create(campaign=campaign, discount_amount=discount_amount_value)

    assert len(basket.get_final_lines()) == 2  # case 1
    assert basket.total_price == price(single_product_price) # case 1

    basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1)
    basket.save()

    assert len(basket.get_final_lines()) == 3  # case 1
    assert basket.product_count == 2
    assert basket.total_price == (price(single_product_price) * basket.product_count - price(discount_amount_value))
    assert OrderLineType.DISCOUNT in [l.type for l in basket.get_final_lines()]

    # Make sure disabling campaign disables it conditions
    assert campaign.conditions.filter(active=True).exists()
    campaign.active = False
    campaign.save()
    assert not campaign.conditions.filter(active=True).exists()
예제 #55
0
def test_productfilter_works():
    rf = RequestFactory()
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price
    product_price = "100"
    discount_percentage = "0.30"

    supplier = get_default_supplier()
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=product_price)
    shop_product = product.get_shop_instance(shop)

    # create catalog campaign
    catalog_filter = ProductFilter.objects.create()
    catalog_filter.products.add(product)

    assert catalog_filter.matches(shop_product)

    catalog_campaign = CatalogCampaign.objects.create(shop=shop,
                                                      active=True,
                                                      name="test")
    catalog_campaign.filters.add(catalog_filter)
    cdp = ProductDiscountPercentage.objects.create(
        campaign=catalog_campaign, discount_percentage=discount_percentage)

    # add product to basket
    basket = get_basket(request)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.save()

    expected_total = price(product_price) - (Decimal(discount_percentage) *
                                             price(product_price))
    assert basket.total_price == expected_total
예제 #56
0
def test_limited_methods():
    """
    Test that products can declare that they limit available shipping methods.
    """
    unique_shipping_method = get_shipping_method(name="unique", price=0)
    shop = get_default_shop()
    common_product = create_product(
        sku="SH_COMMON",
        shop=shop)  # A product that does not limit shipping methods
    unique_product = create_product(
        sku="SH_UNIQUE",
        shop=shop)  # A product that only supports unique_shipping_method
    unique_shop_product = unique_product.get_shop_instance(shop)
    unique_shop_product.limit_shipping_methods = True
    unique_shop_product.shipping_methods.add(unique_shipping_method)
    unique_shop_product.save()
    impossible_product = create_product(
        sku="SH_IMP", shop=shop)  # A product that can't be shipped at all
    imp_shop_product = impossible_product.get_shop_instance(shop)
    imp_shop_product.limit_shipping_methods = True
    imp_shop_product.save()
    for product_ids, method_ids in [
        ((common_product.pk, unique_product.pk),
         (unique_shipping_method.pk, )),
        ((common_product.pk, ),
         ShippingMethod.objects.values_list("pk", flat=True)),
        ((unique_product.pk, ), (unique_shipping_method.pk, )),
        ((
            unique_product.pk,
            impossible_product.pk,
        ), ()),
        ((
            common_product.pk,
            impossible_product.pk,
        ), ()),
    ]:
        product_ids = set(product_ids)
        assert ShippingMethod.objects.available_ids(
            shop=shop, products=product_ids) == set(method_ids)
예제 #57
0
def test_percentage_campaign(rf):
    request, shop, group = initialize_test(rf, False)
    price = shop.create_price

    basket = get_basket(request)
    supplier = get_default_supplier(shop)
    # create a basket rule that requires at least value of 200
    rule = BasketTotalAmountCondition.objects.create(value="200")

    product_price = "200"

    discount_percentage = "0.1"

    expected_discounted_price = price(product_price) - (
        price(product_price) * Decimal(discount_percentage))

    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=product_price)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)

    campaign = BasketCampaign.objects.create(shop=shop,
                                             public_name="test",
                                             name="test",
                                             active=True)
    campaign.conditions.add(rule)
    campaign.save()

    BasketDiscountPercentage.objects.create(
        campaign=campaign, discount_percentage=discount_percentage)

    assert len(basket.get_final_lines()) == 3
    assert basket.product_count == 1
    assert basket.total_price == expected_discounted_price
def create_basket_and_campaign(request, conditions, product_price_value, campaign_discount_value):
    product = create_product(
        "Some crazy product", request.shop, get_default_supplier(), default_price=product_price_value)
    basket = get_basket(request)
    basket.customer = request.customer
    supplier = get_default_supplier()
    basket.add_product(supplier=supplier, shop=request.shop, product=product, quantity=1)
    basket.shipping_method = get_shipping_method(shop=request.shop)

    original_line_count = len(basket.get_final_lines())
    assert original_line_count == 2
    assert basket.product_count == 1
    original_price = basket.total_price

    campaign = BasketCampaign.objects.create(
        shop=request.shop, name="test", public_name="test", active=True)
    BasketDiscountAmount.objects.create(campaign=campaign, discount_amount=campaign_discount_value)

    for condition in conditions:
        campaign.conditions.add(condition)
    assert campaign.is_available()

    return basket, original_line_count, original_price
예제 #59
0
def _get_order_with_coupon(request, initial_status, condition_product_count=1):
    shop = request.shop
    basket = get_basket(request)
    supplier = get_default_supplier()
    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price="50")
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(
        shop=shop)  # For shippable products

    dc = Coupon.objects.create(code="TEST", active=True)
    campaign = BasketCampaign.objects.create(shop=shop,
                                             name="test",
                                             public_name="test",
                                             coupon=dc,
                                             active=True)

    BasketDiscountAmount.objects.create(
        discount_amount=shop.create_price("20"), campaign=campaign)

    rule = BasketTotalProductAmountCondition.objects.create(value=1)
    campaign.conditions.add(rule)
    campaign.save()
    basket.add_code(dc.code)
    basket.save()

    basket.status = initial_status
    creator = OrderCreator(request)
    order = creator.create_order(basket)
    assert order.lines.count() == 3
    assert OrderLineType.DISCOUNT in [l.type for l in order.lines.all()]
    return order
예제 #60
0
def test_percentage_campaign_full_discount(rf, include_tax):
    request, shop, group = initialize_test(rf, include_tax)
    create_default_order_statuses()
    tax = get_tax("sales-tax", "Sales Tax", Decimal(0.2))  # 20%
    create_default_tax_rule(tax)

    basket = get_basket(request)
    supplier = get_default_supplier(shop)

    product = create_product(printable_gibberish(),
                             shop=shop,
                             supplier=supplier,
                             default_price=200)
    basket.add_product(supplier=supplier,
                       shop=shop,
                       product=product,
                       quantity=1)
    basket.shipping_method = get_shipping_method(shop=shop)
    basket.status = get_initial_order_status()

    campaign = BasketCampaign.objects.create(shop=shop,
                                             public_name="test",
                                             name="test",
                                             active=True)
    # 100% of discount
    BasketDiscountPercentage.objects.create(campaign=campaign,
                                            discount_percentage=Decimal(1))

    assert len(basket.get_final_lines()) == 3
    assert basket.product_count == 1
    assert basket.total_price.value == Decimal()

    order_creator = OrderCreator()
    order = order_creator.create_order(basket)
    order.create_payment(order.taxful_total_price)
    assert order.taxful_total_price.value == Decimal()