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)
def test_basket_total_undiscounted_value_conditions(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() product = create_product("Just-A-Product", shop, default_price="150", supplier=supplier) discounted_product = create_product("Just-A-Second-Product", shop, default_price="200", supplier=supplier) # 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) basket.add_product(supplier=supplier, shop=shop, product=discounted_product, quantity=1) condition = BasketTotalUndiscountedProductAmountCondition.objects.create() condition.value = 1 condition.save() assert not condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert condition.matches(basket, []) # Too high amount for undiscounted value condition.value = 151 condition.save() assert not condition.matches(basket, [])
def test_product_in_basket_condition_with_variation_parent(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() product = create_product( "test-product", shop, default_price="200", supplier=supplier, mode=ProductMode.SIMPLE_VARIATION_PARENT) child_products = [] for x in range(0, 3): child_product = create_product("test-product-%s" % x, shop, default_price="10", supplier=supplier) child_product.link_to_parent(product) child_products.append(child_product) condition = ProductsInBasketCondition.objects.create() condition.values = [product] condition.operator = ComparisonOperator.EQUALS condition.quantity = 3 condition.save() assert not condition.matches(basket, []) for child_product in child_products: basket.add_product(supplier=supplier, shop=shop, product=child_product, quantity=1) assert condition.matches(basket, [])
def test_price_cannot_be_under_zero(rf): activate("en") discount_amount = "200" original_price = "199.20" request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") rule1, rule2 = create_condition_and_filter(cat, request) campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=True) campaign.conditions.add(rule1) campaign.filters.add(rule2) campaign.save() ProductDiscountAmount.objects.create(campaign=campaign, discount_amount=discount_amount) price = shop.create_price product = create_product("Just-A-Product-Too", shop, default_price=original_price) shop_product = product.get_shop_instance(shop) shop_product.categories.add(cat) shop_product.save() assert product.get_price_info(request, quantity=1).price == price("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() 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()
def test_basket_total_undiscounted_value_conditions(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier(shop) product = create_product("Just-A-Product", shop, default_price="150", supplier=supplier) discounted_product = create_product("Just-A-Second-Product", shop, default_price="200", supplier=supplier) # 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) basket.add_product(supplier=supplier, shop=shop, product=discounted_product, quantity=1) condition = BasketTotalUndiscountedProductAmountCondition.objects.create() condition.value = 1 condition.save() assert not condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert condition.matches(basket, []) # Too high amount for undiscounted value condition.value = 151 condition.save() assert not condition.matches(basket, [])
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
def test_category_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() category = get_default_category() product = create_product("The Product", shop=shop, default_price="200", supplier=supplier) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) basket.shipping_method = get_shipping_method(shop=shop) shop_product = product.get_shop_instance(shop) assert category not in shop_product.categories.all() condition = CategoryProductsBasketCondition.objects.create(operator=ComparisonOperator.EQUALS, quantity=1) condition.categories.add(category) # No match the product does not have the category assert not condition.matches(basket, []) shop_product.categories.add(category) assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, []) condition.operator = ComparisonOperator.GTE condition.save() assert condition.matches(basket, []) condition.excluded_categories.add(category) assert not condition.matches(basket, [])
def test_campaign_with_non_active_coupon(rf): initial_status = get_initial_order_status() request, shop, group = initialize_test(rf, include_tax=False) order = _get_order_with_coupon(request, initial_status) coupon = order.coupon_usages.first().coupon coupon.active = False coupon.save() modifier = UserFactory() contact = create_random_person(locale="en_US", minimum_name_comp_len=5) assert order.customer != contact state = _get_frontend_order_state(shop, contact) assert order.shop.id == state["shop"]["selected"]["id"] request = get_frontend_request_for_command(state, "finalize", modifier) response = OrderEditView.as_view()(request, pk=order.pk) assert_contains(response, "orderIdentifier") data = json.loads(response.content.decode("utf8")) edited_order = Order.objects.get(pk=order.pk) assert edited_order.identifier == data["orderIdentifier"] == order.identifier assert edited_order.pk == order.pk assert edited_order.lines.count() == 3 assert OrderLineType.DISCOUNT not in [l.type for l in edited_order.lines.all()] assert edited_order.coupon_usages.count() == 0
def test_percentage_campaigns(rf): activate("en") discount_percentage = "0.14" original_price = "123.47" request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") rule1 = ContactGroupCondition.objects.create() rule1.contact_groups = request.customer.groups.all() rule1.save() rule2 = CategoryFilter.objects.create() rule2.categories.add(cat) rule2.save() campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=True) campaign.conditions.add(rule1) campaign.filters.add(rule2) campaign.save() cdp = ProductDiscountPercentage.objects.create(campaign=campaign, discount_percentage=discount_percentage) product = create_product("Just-A-Product-Too", shop, default_price=original_price) price = shop.create_price # price should not be discounted because the request.category is faulty assert product.get_price_info(request, quantity=1).price == price(original_price) shop_product = product.get_shop_instance(shop) shop_product.categories.add(cat) shop_product.save() # now the category is set, so both rules match, discount should be given discounted_price = price(original_price) - (price(original_price) * Decimal(cdp.value)) assert product.get_price_info(request, quantity=1).price == discounted_price
def test_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() product = create_product("Just-A-Product-Too", shop, default_price="200") basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) condition = ProductsInBasketCondition.objects.create() condition.values = [product] condition.save() assert condition.values.first() == product assert condition.matches(basket, []) condition.quantity = 2 condition.save() assert not condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert condition.matches(basket, []) condition.operator = ComparisonOperator.EQUALS condition.save() assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, [])
def test_minimum_price_is_forced(rf): activate("en") discount_amount = "20.53" original_price = "199.20" allowed_minimum_price = "190.20" request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") rule1, rule2 = create_condition_and_filter(cat, request) campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=True) campaign.conditions.add(rule1) campaign.filters.add(rule2) campaign.save() ProductDiscountAmount.objects.create(campaign=campaign, discount_amount=discount_amount) price = shop.create_price product = create_product("Just-A-Product-Too", shop, default_price=original_price) shop_product = product.get_shop_instance(shop) shop_product.minimum_price = price(allowed_minimum_price) shop_product.save() # price should not be discounted because the request.category is faulty assert product.get_price_info(request, quantity=1).price == price(original_price) shop_product.categories.add(cat) shop_product.save() # now the category is set, so both rules match, discount should be given assert product.get_price_info(request, quantity=1).price == shop_product.minimum_price
def test_category_filter(rf): request, shop, group = initialize_test(rf, False) cat = get_default_category() cat_filter = CategoryFilter.objects.create() cat_filter.categories.add(cat) cat_filter.save() assert cat_filter.values.first() == cat category = Category.objects.create( parent=None, identifier="testcat", name="catcat", ) cat_filter.values = [cat, category] cat_filter.save() assert cat_filter.values.count() == 2 product = create_product("Just-A-Product-Too", shop, default_price="200") shop_product = product.get_shop_instance(shop) shop_product.categories.add(cat) shop_product.save() assert cat_filter.filter_queryset(ShopProduct.objects.all()).exists() # filter matches
def test_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) 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()) == 2 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)
def test_category_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() category = get_default_category() product = create_product("The Product", shop=shop, default_price="200", supplier=supplier) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) shop_product = product.get_shop_instance(shop) assert category not in shop_product.categories.all() condition = CategoryProductsBasketCondition.objects.create( category=category, operator=ComparisonOperator.EQUALS, quantity=1) # No match the product does not have the category assert not condition.matches(basket, []) shop_product.categories.add(category) assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, []) condition.operator = ComparisonOperator.GTE condition.save() assert condition.matches(basket, [])
def test_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
def test_order_creation_adds_usage(rf, admin_user): request, shop, group = initialize_test(rf, False) source = seed_source(admin_user) source.add_line( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=get_default_supplier(), quantity=1, base_unit_price=source.create_price(10), ) source.add_line( type=OrderLineType.OTHER, quantity=1, base_unit_price=source.create_price(10), require_verification=True, ) # add coupon coupon = Coupon.objects.create(active=True, code="asdf") campaign = BasketCampaign.objects.create( active=True, shop=shop, name="test", public_name="test", coupon=coupon) BasketDiscountPercentage.objects.create(campaign=campaign, discount_percentage="0.1") source.add_code(coupon.code) creator = OrderCreator() creator.create_order(source) assert CouponUsage.objects.count() == 1
def test_coupon_uniqueness(rf): request, shop, group = initialize_test(rf, False) first_campaign = BasketCampaign.objects.create( active=True, shop=shop, name="test", public_name="test", coupon=None) second_campaign = BasketCampaign.objects.create( active=True, shop=shop, name="test1", public_name="test1", coupon=None) BasketDiscountPercentage.objects.create(campaign=first_campaign, discount_percentage="0.1") BasketDiscountPercentage.objects.create(campaign=second_campaign, discount_percentage="0.1") coupon = Coupon.objects.create(active=True, code="test_code") first_campaign.coupon = coupon first_campaign.save() first_form = BasketCampaignForm(instance=first_campaign, request=request) assert len(first_form.fields["coupon"].choices) == 2 # coupon + empty second_form = BasketCampaignForm(instance=second_campaign, request=request) assert len(second_form.fields["coupon"].choices) == 1 # only empty # Can't set coupon for second campaign since coupon is unique with pytest.raises(IntegrityError): second_campaign.coupon = coupon second_campaign.save()
def test_basket_total_amount_conditions(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() product = create_product("Just-A-Product-Too", shop, default_price="200") basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) condition = BasketTotalAmountCondition.objects.create() condition.value = 1 condition.save() assert condition.value == 1 assert condition.matches(basket, []) condition2 = BasketMaxTotalAmountCondition.objects.create() condition2.value = 200 condition2.save() assert condition2.matches(basket, []) condition2.value = 199 condition2.save() assert not condition2.matches(basket, [])
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) 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()) == 2 assert basket.product_count == 1 assert basket.total_price == expected_discounted_price
def test_category_product_in_basket_condition(rf): request, shop, group = initialize_test(rf, False) basket = get_basket(request) supplier = get_default_supplier() category = get_default_category() product = create_product("The Product", shop=shop, default_price="200", supplier=supplier) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) basket.shipping_method = get_shipping_method(shop=shop) shop_product = product.get_shop_instance(shop) assert category not in shop_product.categories.all() condition = CategoryProductsBasketCondition.objects.create(operator=ComparisonOperator.EQUALS, quantity=1) condition.categories.add(category) # No match the product does not have the category assert not condition.matches(basket, []) category.shop_products.add(shop_product) assert condition.matches(basket, []) basket.add_product(supplier=supplier, shop=shop, product=product, quantity=1) assert not condition.matches(basket, []) condition.operator = ComparisonOperator.GTE condition.save() assert condition.matches(basket, []) condition.excluded_categories.add(category) assert not condition.matches(basket, []) with pytest.raises(CampaignsInvalidInstanceForCacheUpdate): update_filter_cache("test", shop)
def test_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 test_campaign_all_rules_must_match1(rf): activate("en") discount_amount = "20.53" original_price = "199.20" request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") rule1 = ContactGroupCondition.objects.create() rule1.contact_groups = request.customer.groups.all() rule1.save() rule2 = CategoryFilter.objects.create() rule2.categories.add(cat) rule2.save() campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=True) campaign.conditions.add(rule1) campaign.filters.add(rule2) campaign.save() ProductDiscountAmount.objects.create(campaign=campaign, discount_amount=discount_amount) product = create_product("Just-A-Product-Too", shop, default_price=original_price) price = shop.create_price # price should not be discounted because the request.category is faulty assert product.get_price_info(request, quantity=1).price == price(original_price) shop_product = product.get_shop_instance(shop) shop_product.categories.add(cat) shop_product.save() # now the category is set, so both rules match, disconut should be given assert product.get_price_info(request, quantity=1).price == (price(original_price) - price(discount_amount))
def test_campaign_creation(rf): activate("en") request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") condition = ContactGroupCondition.objects.create() condition.contact_groups = request.customer.groups.all() condition.save() assert condition.values.first() == request.customer.groups.first() condition.values = request.customer.groups.all() condition.save() assert condition.values.first() == request.customer.groups.first() category_filter = CategoryFilter.objects.create() category_filter.categories.add(cat) category_filter.save() campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=True) campaign.conditions.add(condition) campaign.filters.add(category_filter) campaign.save() ProductDiscountAmount.objects.create(campaign=campaign, discount_amount=20) # Make sure disabling campaign disables it filters and conditions assert campaign.filters.filter(active=True).exists() assert campaign.conditions.filter(active=True).exists() campaign.active = False campaign.save() assert not campaign.filters.filter(active=True).exists() assert not campaign.conditions.filter(active=True).exists()
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
def test_condition_doesnt_match(rf): activate("en") request, shop, group = initialize_test(rf, False) condition = ContactGroupCondition.objects.create() condition.contact_groups = [get_default_customer_group()] condition.save() request.customer = None assert not condition.matches(request)
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
def test_start_end_dates(rf): activate("en") original_price = "180" discounted_price = "160" request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") rule1, rule2 = create_condition_and_filter(cat, request) discount_amount = 20 campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=True) campaign.conditions.add(rule1) campaign.save() ProductDiscountAmount.objects.create(discount_amount=discount_amount, campaign=campaign) price = shop.create_price product = create_product("Just-A-Product-Too", shop, default_price=original_price) today = now() # starts in future campaign.start_datetime = (today + datetime.timedelta(days=2)) campaign.save() assert not campaign.is_available() assert product.get_price_info(request, quantity=1).price == price(original_price) # has already started campaign.start_datetime = (today - datetime.timedelta(days=2)) campaign.save() assert product.get_price_info(request, quantity=1).price == price(discounted_price) # already ended campaign.end_datetime = (today - datetime.timedelta(days=1)) campaign.save() assert not campaign.is_available() assert product.get_price_info(request, quantity=1).price == price(original_price) # not ended yet campaign.end_datetime = (today + datetime.timedelta(days=1)) campaign.save() assert product.get_price_info(request, quantity=1).price == price(discounted_price) # no start datetime campaign.start_datetime = None campaign.save() assert product.get_price_info(request, quantity=1).price == price(discounted_price) # no start datetime but ended campaign.end_datetime = (today - datetime.timedelta(days=1)) campaign.save() assert not campaign.is_available() assert product.get_price_info(request, quantity=1).price == price(original_price)
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()
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_availability(rf): activate("en") request, shop, group = initialize_test(rf, False) cat = Category.objects.create(name="test") rule1, rule2 = create_condition_and_filter(cat, request) discount_amount = "20" campaign = CatalogCampaign.objects.create(shop=shop, name="test", active=False) campaign.conditions.add(rule1) campaign.save() ProductDiscountAmount.objects.create(discount_amount=discount_amount, campaign=campaign) assert not campaign.is_available()
def test_filter_caching(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) product2 = create_product(printable_gibberish(), shop=shop, supplier=supplier, default_price=product_price) assert product.pk != product2.pk # ensure they're different # create catalog campaign catalog_filter = ProductFilter.objects.create() catalog_filter.products.add(product) catalog_campaign = CatalogCampaign.objects.create(shop=shop, active=True, name="test") catalog_campaign.filters.add(catalog_filter) assert CatalogFilterCachedShopProduct.objects.count() == 1 catalog_campaign.save() assert CatalogFilterCachedShopProduct.objects.count() == 1 entry = CatalogFilterCachedShopProduct.objects.first() assert entry.pk == get_matching_catalog_filters(product.get_shop_instance(shop))[0] # create another campaign catalog_filter2 = ProductFilter.objects.create() catalog_filter2.products.add(product2) catalog_campaign2 = CatalogCampaign.objects.create(shop=shop, active=True, name="test") catalog_campaign2.filters.add(catalog_filter2) assert CatalogFilterCachedShopProduct.objects.count() == 2 catalog_campaign2.save() assert CatalogFilterCachedShopProduct.objects.count() == 2 # new cache for this product was created entry = CatalogFilterCachedShopProduct.objects.last() assert entry.pk == get_matching_catalog_filters(product2.get_shop_instance(shop))[0] # third campaign catalog_filter3 = ProductFilter.objects.create() catalog_filter3.products.add(product2) catalog_campaign3 = CatalogCampaign.objects.create(shop=shop, active=True, name="test") catalog_campaign3.filters.add(catalog_filter3) assert CatalogFilterCachedShopProduct.objects.count() == 3 catalog_campaign3.save() assert CatalogFilterCachedShopProduct.objects.count() == 3 # new one for this filter again expected = get_matching_catalog_filters(product2.get_shop_instance(shop)) for id in expected: assert id in [catalog_filter2.pk, catalog_filter3.pk]
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)
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
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()]