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") BasketCampaign.objects.create(active=True, shop=shop, name="test", public_name="test", discount_percentage="0.1", coupon=coupon) source.add_code(coupon.code) creator = OrderCreator() creator.create_order(source) assert CouponUsage.objects.count() == 1
def create_random_order(customer=None, products=(), completion_probability=0, shop=None): if not customer: customer = Contact.objects.all().order_by("?").first() if not customer: raise ValueError("No valid contacts") if shop is None: shop = get_default_shop() pricing_context = _get_pricing_context(shop, customer) source = OrderSource(shop) source.customer = customer source.customer_comment = "Mock Order" if customer.default_billing_address and customer.default_shipping_address: source.billing_address = customer.default_billing_address source.shipping_address = customer.default_shipping_address else: source.billing_address = create_random_address() source.shipping_address = create_random_address() source.order_date = now() - datetime.timedelta(days=random.uniform(0, 400)) source.language = customer.language source.status = get_initial_order_status() if not products: products = list( Product.objects.list_visible(source.shop, customer).order_by("?")[:40]) for i in range(random.randint(3, 10)): product = random.choice(products) quantity = random.randint(1, 5) price_info = product.get_price_info(pricing_context, quantity=quantity) shop_product = product.get_shop_instance(source.shop) supplier = shop_product.suppliers.first() line = source.add_line(type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, base_unit_price=price_info.base_unit_price, discount_amount=price_info.discount_amount, sku=product.sku, text=product.safe_translation_getter( "name", any_language=True)) assert line.price == price_info.price with atomic(): oc = OrderCreator() order = oc.create_order(source) if random.random() < completion_probability: order.create_shipment_of_all_products() # also set complete order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status", )) return order
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", discount_percentage="0.1", coupon=coupon ) source.add_code(coupon.code) request = apply_request_middleware(rf.get("/")) creator = OrderCreator(request) order = creator.create_order(source) assert CouponUsage.objects.count() == 1
def test_order_source_parentage(rf, admin_user): source = seed_source(admin_user) product = get_default_product() source.add_line( type=OrderLineType.PRODUCT, product=product, supplier=get_default_supplier(), quantity=1, base_unit_price=source.create_price(10), line_id="parent" ) source.add_line( type=OrderLineType.OTHER, text="Child Line", sku="KIDKIDKID", quantity=1, base_unit_price=source.create_price(5), parent_line_id="parent" ) request = apply_request_middleware(rf.get("/")) creator = OrderCreator(request) order = Order.objects.get(pk=creator.create_order(source).pk) kid_line = order.lines.filter(sku="KIDKIDKID").first() assert kid_line assert kid_line.parent_line.product_id == product.pk
def create_random_order(customer=None, products=(), completion_probability=0): if not customer: customer = Contact.objects.all().order_by("?").first() if not customer: raise ValueError("No valid contacts") shop = get_default_shop() request = apply_request_middleware(RequestFactory().get("/"), customer=customer) context = PriceTaxContext.from_request(request) source = OrderSource() source.customer = customer source.customer_comment = "Mock Order" if customer.default_billing_address and customer.default_shipping_address: source.billing_address = customer.default_billing_address source.shipping_address = customer.default_shipping_address else: source.billing_address = create_random_address() source.shipping_address = create_random_address() source.order_date = now() - datetime.timedelta(days=random.uniform(0, 400)) source.shop = shop source.language = customer.language source.status = get_initial_order_status() if not products: products = list(Product.objects.list_visible(source.shop, customer).order_by("?")[:40]) source.lines = [] for i in range(random.randint(3, 10)): product = random.choice(products) quantity = random.randint(1, 5) price_info = product.get_price_info(context, quantity=quantity) shop_product = product.get_shop_instance(source.shop) supplier = shop_product.suppliers.first() line = SourceLine( type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, unit_price=price_info.unit_base_price, total_discount=price_info.discount_amount, sku=product.sku, text=product.safe_translation_getter("name", any_language=True) ) assert line.total_price == price_info.price source.lines.append(line) with atomic(): oc = OrderCreator(request) order = oc.create_order(source) if random.random() < completion_probability: order.create_shipment_of_all_products() # also set complete order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status",)) return order
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) 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() == 2 assert OrderLineType.DISCOUNT in [l.type for l in order.lines.all()] return order
def test_order_creator(rf, admin_user): 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, ) request = apply_request_middleware(rf.get("/")) creator = OrderCreator(request) order = creator.create_order(source) assert get_data_dict(source.billing_address) == get_data_dict(order.billing_address) assert get_data_dict(source.shipping_address) == get_data_dict(order.shipping_address) assert source.customer == order.customer assert source.payment_method == order.payment_method assert source.shipping_method == order.shipping_method assert order.pk
def test_package(): shop = get_default_shop() supplier = get_default_supplier() package_product = create_product("PackageParent", shop=shop, supplier=supplier) assert not package_product.get_package_child_to_quantity_map() children = [create_product("PackageChild-%d" % x, shop=shop, supplier=supplier) for x in range(4)] package_def = {child: 1 + i for (i, child) in enumerate(children)} package_product.make_package(package_def) assert package_product.mode == ProductMode.PACKAGE_PARENT package_product.save() sp = package_product.get_shop_instance(shop) assert not list(sp.get_orderability_errors(supplier=supplier, quantity=1, customer=AnonymousContact())) with pytest.raises(ValueError): # Test re-packaging fails package_product.make_package(package_def) # Check that OrderCreator can deal with packages source = BasketishOrderSource() source.lines.append(SourceLine( type=OrderLineType.PRODUCT, product=package_product, supplier=get_default_supplier(), quantity=10, unit_price=TaxlessPrice(10), )) source.shop = get_default_shop() source.status = get_initial_order_status() creator = OrderCreator(request=None) order = creator.create_order(source) pids_to_quantities = order.get_product_ids_and_quantities() for child, quantity in six.iteritems(package_def): assert pids_to_quantities[child.pk] == 10 * quantity
def test_order_creator(admin_user): source = seed_source(admin_user) source.lines.append( SourceLine( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=get_default_supplier(), quantity=1, unit_price=TaxlessPrice(10), )) source.lines.append( SourceLine( type=OrderLineType.OTHER, quantity=1, unit_price=TaxlessPrice(10), require_verification=True, )) creator = OrderCreator(request=None) order = creator.create_order(source) assert get_data_dict(source.billing_address) == get_data_dict( order.billing_address) assert get_data_dict(source.shipping_address) == get_data_dict( order.shipping_address) assert source.customer == order.customer assert source.payment_method == order.payment_method assert source.shipping_method == order.shipping_method assert order.pk
def get_order_and_source(admin_user): # create original source to tamper with source = BasketishOrderSource(get_default_shop()) source.status = get_initial_order_status() source.billing_address = MutableAddress.objects.create(name="Original Billing") source.shipping_address = MutableAddress.objects.create(name="Original Shipping") source.customer = get_person_contact(admin_user) source.payment_method = get_default_payment_method() source.shipping_method = get_default_shipping_method() 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, ) assert len(source.get_lines()) == 2 source.creator = admin_user creator = OrderCreator() order = creator.create_order(source) return order, source
def get_order_and_source(admin_user): # create original source to tamper with source = BasketishOrderSource(get_default_shop()) source.status = get_initial_order_status() source.billing_address = MutableAddress.objects.create( name="Original Billing") source.shipping_address = MutableAddress.objects.create( name="Original Shipping") source.customer = get_person_contact(admin_user) source.payment_method = get_default_payment_method() source.shipping_method = get_default_shipping_method() 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, ) assert len(source.get_lines()) == 2 source.creator = admin_user creator = OrderCreator() order = creator.create_order(source) return order, source
def create_order_from_state(self, state, creator=None, ip_address=None): """ Create an order from a state dict unserialized from JSON. :param state: State dictionary :type state: dict :param creator: Creator user :type creator: django.contrib.auth.models.User|None :param ip_address: Remote IP address (IPv4 or IPv6) :type ip_address: str :return: The created order, or None if something failed along the way :rtype: Order|None """ source = self.create_source_from_state(state, creator=creator, ip_address=ip_address, save=True) # Then create an OrderCreator and try to get things done! creator = OrderCreator() try: order = creator.create_order(order_source=source) self._postprocess_order(order, state) return order except Exception as exc: # pragma: no cover self.add_error(exc) return
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) dc = Coupon.objects.create(code="TEST", active=True) campaign = BasketCampaign.objects.create( shop=shop, name="test", public_name="test", coupon=dc, discount_amount_value=shop.create_price("20"), active=True ) 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() == 2 assert OrderLineType.DISCOUNT in [l.type for l in order.lines.all()] return order
def create_order_from_state(self, state, creator=None, ip_address=None): """ Create an order from a state dict unserialized from JSON. :param state: State dictionary :type state: dict :param creator: Creator user :type creator: django.contrib.auth.models.User|None :param ip_address: Remote IP address (IPv4 or IPv6) :type ip_address: str :return: The created order, or None if something failed along the way :rtype: Order|None """ source = self.create_source_from_state( state, creator=creator, ip_address=ip_address, save=True) # Then create an OrderCreator and try to get things done! creator = OrderCreator() try: order = creator.create_order(order_source=source) self._postprocess_order(order, state) return order except Exception as exc: # pragma: no cover self.add_error(exc) return
def create_random_order(customer=None, products=(), completion_probability=0): if not customer: customer = Contact.objects.all().order_by("?").first() if not customer: raise ValueError("No valid contacts") shop = get_default_shop() request = apply_request_middleware(RequestFactory().get("/"), customer=customer) context = PriceTaxContext.from_request(request) source = OrderSource() source.customer = customer source.customer_comment = "Mock Order" if customer.default_billing_address and customer.default_shipping_address: source.billing_address = customer.default_billing_address source.shipping_address = customer.default_shipping_address else: source.billing_address = create_random_address() source.shipping_address = create_random_address() source.order_date = now() - datetime.timedelta(days=random.uniform(0, 400)) source.shop = shop source.language = customer.language source.status = get_initial_order_status() if not products: products = list( Product.objects.list_visible(source.shop, customer).order_by("?")[:40]) source.lines = [] for i in range(random.randint(3, 10)): product = random.choice(products) quantity = random.randint(1, 5) price = product.get_price(context, quantity=quantity) shop_product = product.get_shop_instance(source.shop) supplier = shop_product.suppliers.first() line = SourceLine(type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, unit_price=price, sku=product.sku, text=product.safe_translation_getter( "name", any_language=True)) source.lines.append(line) with atomic(): oc = OrderCreator(request) order = oc.create_order(source) if random.random() < completion_probability: order.create_shipment_of_all_products() # also set complete order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status", )) return order
def test_order_creator_can_deal_with_packages(): source = get_order_source_with_a_package() package_product = source.get_lines()[0].product package_def = package_product.get_package_child_to_quantity_map() creator = OrderCreator() order = creator.create_order(source) pids_to_quantities = order.get_product_ids_and_quantities() for child, quantity in six.iteritems(package_def): assert pids_to_quantities[child.pk] == 10 * quantity
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) 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() ) == 2 # no discount was applied because coupon is required basket.add_code(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()] # 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
def test_order_creator_supplierless_product_line_conversion_should_fail(admin_user): source = seed_source(admin_user) source.lines.append(SourceLine( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=None, quantity=1, unit_price=TaxlessPrice(10), )) creator = OrderCreator(request=None) with pytest.raises(ValueError): order = creator.create_order(source)
def test_order_creator_supplierless_product_line_conversion_should_fail(rf, admin_user): source = seed_source(admin_user) source.add_line( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=None, quantity=1, base_unit_price=source.create_price(10), ) creator = OrderCreator() with pytest.raises(ValueError): order = creator.create_order(source)
def test_order_creator_supplierless_product_line_conversion_should_fail( rf, admin_user): source = seed_source(admin_user) source.add_line( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=None, quantity=1, base_unit_price=source.create_price(10), ) creator = OrderCreator() with pytest.raises(ValueError): order = creator.create_order(source)
def test_order_creator_supplierless_product_line_conversion_should_fail( admin_user): source = seed_source(admin_user) source.lines.append( SourceLine( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=None, quantity=1, unit_price=TaxlessPrice(10), )) creator = OrderCreator(request=None) with pytest.raises(ValueError): order = creator.create_order(source)
def test_order_package_children_taxes(): """ Test OrderCreator creates package parent links for child lines. """ tax_class = get_default_tax_class() tax = Tax.objects.create(rate='0.25', name="Da Tax") TaxRule.objects.create(tax=tax).tax_classes.add(tax_class) source = get_order_source_with_a_package() assert source.get_lines()[0].tax_class == tax_class order = OrderCreator().create_order(source) lines_and_taxes = [] for line in order.lines.all(): lines_and_taxes.append(prettify_order_line(line)) for line_tax in line.taxes.all(): lines_and_taxes.append(' %s' % (line_tax, )) assert lines_and_taxes == [ '#0 10 x PackageParent', ' Da Tax: 20.000000000 EUR on 80.000000000 EUR', '#1 10 x PackageChild-0, child of #0', '#2 20 x PackageChild-1, child of #0', '#3 30 x PackageChild-2, child of #0', '#4 40 x PackageChild-3, child of #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) dc = Coupon.objects.create(code="TEST", active=True) campaign = BasketCampaign.objects.create( shop=shop, name="test", public_name="test", coupon=dc, discount_amount_value=shop.create_price("20"), active=True ) rule = BasketTotalProductAmountCondition.objects.create(value=2) campaign.conditions.add(rule) campaign.save() assert len(basket.get_final_lines()) == 2 # no discount was applied because coupon is required basket.add_code(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()] # 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
def test_order_creator_parent_linkage(): """ Test OrderCreator creates parent links from OrderSource. """ source = BasketishOrderSource(get_default_shop()) source.status = get_initial_order_status() source.add_line( line_id='LINE1', type=OrderLineType.OTHER, quantity=1, sku='parent', text='Parent line', ) source.add_line( line_id='LINE1.1', parent_line_id='LINE1', type=OrderLineType.OTHER, quantity=1, sku='child1.1', text='Child line 1.1', ) source.add_line( line_id='LINE1.2', parent_line_id='LINE1', type=OrderLineType.OTHER, quantity=1, sku='child1.2', text='Child line 1.2', ) source.add_line( line_id='LINE1.2.1', parent_line_id='LINE1.2', type=OrderLineType.OTHER, quantity=1, sku='child1.2.1', text='Child line 1.2.1', ) source.add_line( line_id='LINE1.3', parent_line_id='LINE1', type=OrderLineType.OTHER, quantity=1, sku='child1.3', text='Child line 1.3', ) order = OrderCreator().create_order(source) lines = [prettify_order_line(line) for line in order.lines.all()] assert lines == [ '#0 1 x parent', '#1 1 x child1.1, child of #0', '#2 1 x child1.2, child of #0', '#3 1 x child1.2.1, child of #2', '#4 1 x child1.3, child of #0', ]
def test_order_source_parentage(admin_user): source = seed_source(admin_user) product = get_default_product() source.lines.append( SourceLine(type=OrderLineType.PRODUCT, product=product, supplier=get_default_supplier(), quantity=1, unit_price=TaxlessPrice(10), line_id="parent")) source.lines.append( SourceLine(type=OrderLineType.OTHER, text="Child Line", sku="KIDKIDKID", quantity=1, unit_price=TaxlessPrice(5), parent_line_id="parent")) creator = OrderCreator(request=None) order = Order.objects.get(pk=creator.create_order(source).pk) kid_line = order.lines.filter(sku="KIDKIDKID").first() assert kid_line assert kid_line.parent_line.product_id == product.pk
def create_order_from_state(self, state, creator=None): """ Create an order from a state dict unserialized from JSON. :param state: State dictionary :type state: dict :param creator: Creator user :type creator: django.contrib.auth.models.User|None :return: The created order, or None if something failed along the way :rtype: Order|None """ if not self.is_valid: # pragma: no cover raise ValueError("Create a new JsonOrderCreator for each order.") # We'll be mutating the state to make it easier to track we've done everything, # so it's nice to deepcopy things first. state = deepcopy(state) # First, initialize an OrderSource. source = self._initialize_source_from_state(state, creator) if not source: return None # Then, copy some lines into it. self._process_lines(source, state) if not self.is_valid: # If we encountered any errors thus far, don't bother going forward return None # Then create an OrderCreator and try to get things done! creator = OrderCreator(request=None) try: order = creator.create_order(order_source=source) self._postprocess_order(order, state) return order except Exception as exc: # pragma: no cover self.add_error(exc) return
def test_order_creator(admin_user): source = seed_source(admin_user) source.lines.append(SourceLine( type=OrderLineType.PRODUCT, product=get_default_product(), supplier=get_default_supplier(), quantity=1, unit_price=TaxlessPrice(10), )) source.lines.append(SourceLine( type=OrderLineType.OTHER, quantity=1, unit_price=TaxlessPrice(10), require_verification=True, )) creator = OrderCreator(request=None) order = creator.create_order(source) assert get_data_dict(source.billing_address) == get_data_dict(order.billing_address) assert get_data_dict(source.shipping_address) == get_data_dict(order.shipping_address) assert source.customer == order.customer assert source.payment_method == order.payment_method assert source.shipping_method == order.shipping_method assert order.pk
def test_order_source_parentage(admin_user): source = seed_source(admin_user) product = get_default_product() source.lines.append(SourceLine( type=OrderLineType.PRODUCT, product=product, supplier=get_default_supplier(), quantity=1, unit_price=TaxlessPrice(10), line_id="parent" )) source.lines.append(SourceLine( type=OrderLineType.OTHER, text="Child Line", sku="KIDKIDKID", quantity=1, unit_price=TaxlessPrice(5), parent_line_id="parent" )) creator = OrderCreator(request=None) order = Order.objects.get(pk=creator.create_order(source).pk) kid_line = order.lines.filter(sku="KIDKIDKID").first() assert kid_line assert kid_line.parent_line.product_id == product.pk
def test_order_package_parent_links(): """ Test OrderCreator creates package parent links for child lines. """ source = get_order_source_with_a_package() order = OrderCreator().create_order(source) lines = [prettify_order_line(line) for line in order.lines.all()] assert lines == [ '#0 10 x PackageParent', '#1 10 x PackageChild-0, child of #0', '#2 20 x PackageChild-1, child of #0', '#3 30 x PackageChild-2, child of #0', '#4 40 x PackageChild-3, child of #0', ]