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()
Exemple #2
0
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
Exemple #3
0
def test_order_creation_adds_usage(rf, admin_user):
    request, shop, group = initialize_test(rf, False)

    source = seed_source(admin_user, shop)
    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_campaign_with_coupons1(rf):
    basket, dc, request, status = _init_basket_coupon_test(rf)

    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
Exemple #5
0
def test_order_creator_taxes(admin_user, include_tax):
    shop = get_shop(include_tax)
    source = OrderSource(shop)
    source.status = get_initial_order_status()
    create_default_order_statuses()
    tax = get_tax("sales-tax", "Sales Tax", Decimal(0.2))  # 20%
    create_default_tax_rule(tax)
    product = get_default_product()

    line = source.add_line(
        line_id="product-line",
        type=OrderLineType.PRODUCT,
        product=product,
        supplier=get_default_supplier(shop),
        quantity=1,
        shop=shop,
        base_unit_price=source.create_price(100),
    )
    discount_line = source.add_line(
        line_id="discount-line",
        type=OrderLineType.DISCOUNT,
        supplier=get_default_supplier(shop),
        quantity=1,
        base_unit_price=source.create_price(0),
        discount_amount=source.create_price(100),
        parent_line_id=line.line_id,
    )
    assert source.taxful_total_price.value == Decimal()
    creator = OrderCreator()
    order = creator.create_order(source)
    assert order.taxful_total_price.value == Decimal()
Exemple #6
0
def get_order_and_source(admin_user, product):
    # 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=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
Exemple #7
0
def test_order_source_extra_data(rf, admin_user):
    source = seed_source(admin_user)
    product = get_default_product()
    line1 = source.add_line(
        type=OrderLineType.PRODUCT,
        product=product,
        supplier=get_default_supplier(source.shop),
        quantity=1,
        base_unit_price=source.create_price(10),
        line_id="parent",
    )
    line2 = source.add_line(
        type=OrderLineType.OTHER,
        text="Child Line",
        sku="KIDKIDKID",
        quantity=1,
        base_unit_price=source.create_price(5),
        parent_line_id="parent",
    )

    creator = OrderCreator()
    order = Order.objects.get(pk=creator.create_order(source).pk)
    line_ids = [
        line.extra_data["source_line_id"] for line in order.lines.all()
    ]
    assert line1.line_id in line_ids
    assert line2.line_id in line_ids
Exemple #8
0
def test_order_copy_by_updating_order_source_from_order(admin_user):
    shop = get_default_shop()

    line_data = {
        "type": OrderLineType.PRODUCT,
        "product": get_default_product(),
        "supplier": get_default_supplier(shop),
        "quantity": 1,
        "base_unit_price": shop.create_price(10),
    }
    source = seed_source(admin_user)
    source.add_line(**line_data)
    source.payment_data = None

    creator = OrderCreator()
    order = creator.create_order(source)

    new_source = OrderSource(shop)
    new_source.update_from_order(order)
    new_source.add_line(**line_data)

    new_order = creator.create_order(new_source)
    assert new_order
    assert order.billing_address == new_order.billing_address
    assert order.taxful_total_price == new_order.taxful_total_price
Exemple #9
0
def test_order_statuses(admin_user):
    create_default_order_statuses()

    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,
    )

    creator = OrderCreator()
    order = creator.create_order(source)
    # new order, status/role is new/initial
    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL

    # FUTURE: order gets payment the status changes to processing/processing
    total = order.taxful_total_price.amount
    order.create_payment(total)

    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL

    # FUTURE: order is fully shipped the status changes to complete/complete
    order.create_shipment_of_all_products()
    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL
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
    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_and_source(admin_user, product):
    # 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=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
Exemple #13
0
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"
    )

    creator = OrderCreator()
    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
Exemple #14
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)

    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
Exemple #15
0
def test_order_statuses(admin_user):
    create_default_order_statuses()

    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,
    )

    creator = OrderCreator()
    order = creator.create_order(source)
    # new order, status/role is new/initial
    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL

    # FUTURE: order gets payment the status changes to processing/processing
    total = order.taxful_total_price.amount
    order.create_payment(total)

    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL

    # FUTURE: order is fully shipped the status changes to complete/complete
    order.create_shipment_of_all_products()
    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL
Exemple #16
0
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,
    )

    creator = OrderCreator()
    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
Exemple #17
0
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"
    )

    creator = OrderCreator()
    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, 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
Exemple #19
0
def test_order_creator_account_manager():
    company = create_random_company()
    shop = get_shop(identifier="random-shop", enabled=True)
    source = seed_source(create_random_user(), shop)
    source.customer = company
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=get_default_product(),
        supplier=get_default_supplier(),
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    creator = OrderCreator()
    order = creator.create_order(source)
    assert order.account_manager is None  # Company contact doesn't have account manager field

    person = create_random_person()
    person.account_manager = create_random_person()
    person.save()

    source = seed_source(create_random_user(), shop)
    source.customer = person
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=get_default_product(),
        supplier=get_default_supplier(),
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    creator = OrderCreator()
    order = creator.create_order(source)
    assert order.account_manager is not None
    assert order.account_manager == person.account_manager
    with pytest.raises(ProtectedError):
        person.account_manager.delete()
Exemple #20
0
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,
    )

    creator = OrderCreator()
    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)
    customer = source.customer
    assert customer == order.customer
    assert customer.groups.count() == 1
    assert customer.groups.first() == order.customer_groups.first()
    assert customer.tax_group is not None
    assert customer.tax_group == order.tax_group

    assert source.payment_method == order.payment_method
    assert source.shipping_method == order.shipping_method
    assert order.pk
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
Exemple #22
0
def test_order_source_extra_data(rf, admin_user):
    source = seed_source(admin_user)
    product = get_default_product()
    line1 = source.add_line(
        type=OrderLineType.PRODUCT,
        product=product,
        supplier=get_default_supplier(),
        quantity=1,
        base_unit_price=source.create_price(10),
        line_id="parent"
    )
    line2 = source.add_line(
        type=OrderLineType.OTHER,
        text="Child Line",
        sku="KIDKIDKID",
        quantity=1,
        base_unit_price=source.create_price(5),
        parent_line_id="parent"
    )

    creator = OrderCreator()
    order = Order.objects.get(pk=creator.create_order(source).pk)
    line_ids = [line.extra_data["source_line_id"] for line in order.lines.all()]
    assert line1.line_id in line_ids
    assert line2.line_id in line_ids
def test_campaign_with_coupons1(rf):
    basket, dc, request, status = _init_basket_coupon_test(rf)

    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()
               ) == 4  # 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
Exemple #24
0
def test_refunds_report(rf):
    shop = get_default_shop()
    get_default_tax_class()
    creator = OrderCreator()

    source1 = seed_source()
    source2 = seed_source()
    source3 = seed_source()
    source4 = seed_source()

    order1 = creator.create_order(source1)
    order2 = creator.create_order(source2)
    order3 = creator.create_order(source3)
    order4 = creator.create_order(source4)

    # pay orders
    [o.create_payment(o.taxful_total_price) for o in Order.objects.all()]

    order1.create_full_refund()
    order2.create_refund(
        [{"line": order2.lines.first(), "amount": order2.taxful_total_price.amount * Decimal(0.5), "quantity": 1}]
    )
    order3.create_refund(
        [{"line": order3.lines.first(), "amount": order3.taxful_total_price.amount * Decimal(0.3), "quantity": 1}]
    )
    order4.create_refund(
        [{"line": order4.lines.first(), "amount": order4.taxful_total_price.amount * Decimal(0.1), "quantity": 1}]
    )

    total_refunded = (order1.get_total_refunded_amount() +
                      order2.get_total_refunded_amount() +
                      order3.get_total_refunded_amount() +
                      order4.get_total_refunded_amount())

    data = {
        "report": RefundedSalesReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.ALL_TIME,
        "writer": "json",
        "force_download": 1,
    }
    report = RefundedSalesReport(**data)
    writer = get_writer_instance(data["writer"])
    response = writer.get_response(report=report)
    if hasattr(response, "render"):
        response.render()
    json_data = json.loads(response.content.decode("utf-8"))
    assert force_text(RefundedSalesReport.title) in json_data.get("heading")
    data = json_data.get("tables")[0].get("data")
    assert len(data) == 1
    data = data[0]

    expected_data = {
        "refunded_orders": "4",
        "total_refunded": str(total_refunded.value)
    }

    for k, v in expected_data.items():
        assert data[k] == v
Exemple #25
0
def test_matching_coupon_code(rf):
    default_price = 10
    request, product = _init_test_for_product_without_basket(rf, default_price)

    discount_amount = 4
    coupon_code = CouponCode.objects.create(code="HORSESHOW2018", active=True)
    coupon_code.shops = [request.shop]
    discount = Discount.objects.create(active=True,
                                       product=product,
                                       coupon_code=coupon_code,
                                       discount_amount_value=discount_amount)
    discount.shops.add(request.shop)

    # No basket means no coupon code in basket which means no discount
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price)

    request, product, basket = _init_test_for_product_with_basket(
        rf, default_price)
    assert request.basket == basket

    # Ok now we have basket, but the coupon is not yet applied
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price)

    # Make sure disabling discount makes coupon un-usable
    coupon_code_modifier = CouponCodeModule()
    assert coupon_code_modifier.can_use_code(request.basket, coupon_code.code)

    discount.active = False
    discount.save()
    assert not coupon_code_modifier.can_use_code(request.basket,
                                                 coupon_code.code)

    discount.active = True
    discount.save()
    assert coupon_code_modifier.can_use_code(request.basket, coupon_code.code)

    basket.add_code(coupon_code)
    assert coupon_code.code in basket.codes
    assert coupon_code.code in request.basket.codes
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price - discount_amount)

    # Apply coupon code after order is created
    basket.clear_codes()
    creator = OrderCreator()
    order = creator.create_order(basket)
    assert order.taxful_total_price == request.shop.create_price(default_price)

    # Make sure non active discount can't be used
    discount.active = False
    discount.save()
    order_modifier = CouponCodeModule()
    assert not order_modifier.use_code(order, coupon_code.code)
    discount.active = True
    discount.save()
    assert isinstance(order_modifier.use_code(order, coupon_code.code),
                      CouponUsage)
Exemple #26
0
def test_order_creator_with_package_product(rf, admin_user):
    if "shuup.simple_supplier" not in settings.INSTALLED_APPS:
        pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS")
    from shuup_tests.simple_supplier.utils import get_simple_supplier

    shop = get_default_shop()
    supplier = get_simple_supplier()
    package_product = create_package_product("Package-Product-Test", shop=shop, supplier=supplier,
                                             children=2)
    shop_product =  package_product.get_shop_instance(shop)
    quantity_map = package_product.get_package_child_to_quantity_map()
    product_1, product_2 = quantity_map.keys()
    product_1.stock_behavior = StockBehavior.STOCKED
    product_1.save()
    product_2.stock_behavior = StockBehavior.STOCKED
    product_2.save()

    assert quantity_map[product_1] == 1
    assert quantity_map[product_2] == 2

    supplier.adjust_stock(product_1.pk, 1)
    supplier.adjust_stock(product_2.pk, 2)

    assert supplier.get_stock_status(product_1.pk).logical_count == 1
    assert supplier.get_stock_status(product_2.pk).logical_count == 2

    creator = OrderCreator()

    # There should be no exception when creating order with only package product
    source = seed_source(admin_user)
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=package_product,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    order = creator.create_order(source)

    # However, there should not be enough stock for both package and child products
    source = seed_source(admin_user)
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=package_product,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product_1,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )

    # And a validation error should be raised
    with pytest.raises(ValidationError):
        order = creator.create_order(source)
Exemple #27
0
def test_refunds_report(rf):
    shop = get_default_shop()
    get_default_tax_class()
    creator = OrderCreator()

    source1 = seed_source()
    source2 = seed_source()
    source3 = seed_source()
    source4 = seed_source()

    order1 = creator.create_order(source1)
    order2 = creator.create_order(source2)
    order3 = creator.create_order(source3)
    order4 = creator.create_order(source4)

    # pay orders
    [o.create_payment(o.taxful_total_price) for o in Order.objects.all()]

    order1.create_full_refund()
    order2.create_refund(
        [{"line": order2.lines.first(), "amount": order2.taxful_total_price.amount * Decimal(0.5), "quantity": 1}]
    )
    order3.create_refund(
        [{"line": order3.lines.first(), "amount": order3.taxful_total_price.amount * Decimal(0.3), "quantity": 1}]
    )
    order4.create_refund(
        [{"line": order4.lines.first(), "amount": order4.taxful_total_price.amount * Decimal(0.1), "quantity": 1}]
    )

    total_refunded = (order1.get_total_refunded_amount() +
                      order2.get_total_refunded_amount() +
                      order3.get_total_refunded_amount() +
                      order4.get_total_refunded_amount())

    data = {
        "report": RefundedSalesReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.ALL_TIME,
        "writer": "json",
        "force_download": 1,
    }
    report = RefundedSalesReport(**data)
    writer = get_writer_instance(data["writer"])
    response = writer.get_response(report=report)
    if hasattr(response, "render"):
        response.render()
    json_data = json.loads(response.content.decode("utf-8"))
    assert force_text(RefundedSalesReport.title) in json_data.get("heading")
    data = json_data.get("tables")[0].get("data")
    assert len(data) == 1
    data = data[0]

    expected_data = {
        "refunded_orders": "4",
        "total_refunded": str(total_refunded.value)
    }

    for k, v in expected_data.items():
        assert data[k] == v
Exemple #28
0
def test_order_creator_with_package_product(rf, admin_user):
    if "shuup.simple_supplier" not in settings.INSTALLED_APPS:
        pytest.skip("Need shuup.simple_supplier in INSTALLED_APPS")
    from shuup_tests.simple_supplier.utils import get_simple_supplier

    shop = get_default_shop()
    supplier = get_simple_supplier()
    package_product = create_package_product("Package-Product-Test", shop=shop, supplier=supplier,
                                             children=2)
    shop_product = package_product.get_shop_instance(shop)
    quantity_map = package_product.get_package_child_to_quantity_map()
    product_1, product_2 = quantity_map.keys()
    product_1.stock_behavior = StockBehavior.STOCKED
    product_1.save()
    product_2.stock_behavior = StockBehavior.STOCKED
    product_2.save()

    assert quantity_map[product_1] == 1
    assert quantity_map[product_2] == 2

    supplier.adjust_stock(product_1.pk, 1)
    supplier.adjust_stock(product_2.pk, 2)

    assert supplier.get_stock_status(product_1.pk).logical_count == 1
    assert supplier.get_stock_status(product_2.pk).logical_count == 2

    creator = OrderCreator()

    # There should be no exception when creating order with only package product
    source = seed_source(admin_user)
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=package_product,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    order = creator.create_order(source)

    # However, there should not be enough stock for both package and child products
    source = seed_source(admin_user)
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=package_product,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product_1,
        supplier=supplier,
        quantity=1,
        base_unit_price=source.create_price(10),
    )

    # And a validation error should be raised
    with pytest.raises(ValidationError):
        order = creator.create_order(source)
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
Exemple #30
0
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.listed(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
Exemple #31
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
Exemple #32
0
def test_matching_coupon_code(rf):
    default_price = 10
    request, product = _init_test_for_product_without_basket(rf, default_price)

    discount_amount = 4
    coupon_code = CouponCode.objects.create(code="HORSESHOW2018", active=True)
    coupon_code.shops = [request.shop]
    discount = Discount.objects.create(
        active=True, product=product, coupon_code=coupon_code, discount_amount_value=discount_amount)
    discount.shops.add(request.shop)

    # No basket means no coupon code in basket which means no discount
    assert product.get_price_info(request).price == request.shop.create_price(default_price)

    request, product, basket = _init_test_for_product_with_basket(rf, default_price)
    assert request.basket == basket

    # Ok now we have basket, but the coupon is not yet applied
    assert product.get_price_info(request).price == request.shop.create_price(default_price)

    # Make sure disabling discount makes coupon un-usable
    coupon_code_modifier = CouponCodeModule()
    assert coupon_code_modifier.can_use_code(request.basket, coupon_code.code)

    discount.active = False
    discount.save()
    assert not coupon_code_modifier.can_use_code(request.basket, coupon_code.code)

    discount.active = True
    discount.save()
    assert coupon_code_modifier.can_use_code(request.basket, coupon_code.code)

    basket.add_code(coupon_code)
    assert coupon_code.code in basket.codes
    assert coupon_code.code in request.basket.codes

    get_price_info(context=request, product=product.id) # Test if get_price_info works with product.id sent
    assert product.get_price_info(request).price == request.shop.create_price(default_price - discount_amount)

    # Apply coupon code after order is created
    basket.clear_codes()
    creator = OrderCreator()
    order = creator.create_order(basket)
    assert order.taxful_total_price == request.shop.create_price(default_price)

    # Make sure non active discount can't be used
    discount.active = False
    discount.save()
    order_modifier = CouponCodeModule()
    assert not order_modifier.use_code(order, coupon_code.code)
    discount.active = True
    discount.save()
    assert isinstance(order_modifier.use_code(order, coupon_code.code), CouponUsage)
Exemple #33
0
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)
Exemple #34
0
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)
Exemple #35
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)
Exemple #36
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)
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 _get_custom_order(regular_user, **kwargs):
    prices_include_tax = kwargs.pop("prices_include_tax", False)
    include_basket_campaign = kwargs.pop("include_basket_campaign", False)
    include_catalog_campaign = kwargs.pop("include_catalog_campaign", False)

    shop = get_shop(prices_include_tax=prices_include_tax)
    supplier = get_simple_supplier()

    if include_basket_campaign:
        _add_basket_campaign(shop)

    if include_catalog_campaign:
        _add_catalog_campaign(shop)
    _add_taxes()

    contact = get_person_contact(regular_user)
    source = BasketishOrderSource(shop)
    source.status = get_initial_order_status()
    source.customer = contact

    ctx = get_pricing_module().get_context_from_data(shop, contact)
    for product_data in _get_product_data():
        quantity = product_data.pop("quantity")
        product = create_product(
            sku=product_data.pop("sku"),
            shop=shop,
            supplier=supplier,
            stock_behavior=StockBehavior.STOCKED,
            tax_class=get_default_tax_class(),
            **product_data)
        shop_product = product.get_shop_instance(shop)
        shop_product.categories.add(get_default_category())
        shop_product.save()
        supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY)
        pi = product.get_price_info(ctx)
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=product,
            supplier=supplier,
            quantity=quantity,
            base_unit_price=pi.base_unit_price,
            discount_amount=pi.discount_amount
        )

    oc = OrderCreator()
    order = oc.create_order(source)
    return order
def _get_custom_order(regular_user, **kwargs):
    prices_include_tax = kwargs.pop("prices_include_tax", False)
    include_basket_campaign = kwargs.pop("include_basket_campaign", False)
    include_catalog_campaign = kwargs.pop("include_catalog_campaign", False)

    shop = get_shop(prices_include_tax=prices_include_tax)
    supplier = get_simple_supplier()

    if include_basket_campaign:
        _add_basket_campaign(shop)

    if include_catalog_campaign:
        _add_catalog_campaign(shop)
    _add_taxes()

    contact = get_person_contact(regular_user)
    source = BasketishOrderSource(shop)
    source.status = get_initial_order_status()
    source.customer = contact

    ctx = get_pricing_module().get_context_from_data(shop, contact)
    for product_data in _get_product_data():
        quantity = product_data.pop("quantity")
        product = create_product(
            sku=product_data.pop("sku"),
            shop=shop,
            supplier=supplier,
            stock_behavior=StockBehavior.STOCKED,
            tax_class=get_default_tax_class(),
            **product_data)
        shop_product = product.get_shop_instance(shop)
        shop_product.categories.add(get_default_category())
        shop_product.save()
        supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY)
        pi = product.get_price_info(ctx)
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=product,
            supplier=supplier,
            quantity=quantity,
            base_unit_price=pi.base_unit_price,
            discount_amount=pi.discount_amount
        )

    oc = OrderCreator()
    order = oc.create_order(source)
    return order
Exemple #40
0
def test_order_customer_groups(rf, admin_user):
    customer = create_random_person()
    default_group = get_default_customer_group()
    default_group.members.add(customer)
    source = seed_source(admin_user)
    source.customer = customer

    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,
    )

    creator = OrderCreator()
    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)
    customer = source.customer
    assert customer == order.customer
    assert customer.groups.count() == 2
    assert order.customer_groups.filter(id=default_group.id).exists()
    with pytest.raises(ProtectedError):
        default_group.delete()

    assert customer.tax_group is not None
    assert customer.tax_group == order.tax_group
    with pytest.raises(ProtectedError):
        customer.tax_group.delete()

    new_group = create_random_contact_group()
    new_group.members.add(customer)

    order.phone = "911"
    order.save()
    assert order.customer_groups.filter(id=default_group.id).exists()
    assert not order.customer_groups.filter(id=new_group.id).exists()
Exemple #41
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
Exemple #42
0
def _get_order(prices_include_tax=False,
               include_basket_campaign=False,
               include_catalog_campaign=False):
    shop = get_shop(prices_include_tax=prices_include_tax)
    supplier = get_simple_supplier()

    if "shuup.campaigns" in settings.INSTALLED_APPS:
        from shuup.campaigns.models.basket_conditions import BasketTotalProductAmountCondition
        from shuup.campaigns.models.basket_effects import BasketDiscountAmount
        from shuup.campaigns.models.campaigns import BasketCampaign, CatalogCampaign
        from shuup.campaigns.models.catalog_filters import CategoryFilter
        from shuup.campaigns.models.product_effects import ProductDiscountAmount

        if include_basket_campaign:
            _add_basket_campaign(shop)

        if include_catalog_campaign:
            _add_catalog_campaign(shop)
    _add_taxes()

    source = BasketishOrderSource(shop)
    source.status = get_initial_order_status()
    ctx = get_pricing_module().get_context_from_data(shop, AnonymousContact())
    for product_data in _get_product_data():
        quantity = product_data.pop("quantity")
        product = create_product(sku=product_data.pop("sku"),
                                 shop=shop,
                                 supplier=supplier,
                                 stock_behavior=StockBehavior.STOCKED,
                                 tax_class=get_default_tax_class(),
                                 **product_data)
        shop_product = product.get_shop_instance(shop)
        shop_product.categories.add(get_default_category())
        shop_product.save()
        supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY)
        pi = product.get_price_info(ctx)
        source.add_line(type=OrderLineType.PRODUCT,
                        product=product,
                        supplier=supplier,
                        quantity=quantity,
                        base_unit_price=pi.base_unit_price,
                        discount_amount=pi.discount_amount)
    oc = OrderCreator()
    order = oc.create_order(source)
    return order
Exemple #43
0
def test_order_creator_company_multishop():
    with override_settings(SHUUP_MANAGE_CONTACTS_PER_SHOP=True, SHUUP_ENABLE_MULTIPLE_SHOPS=True):
        company = create_random_company()
        shop = get_shop(identifier="random-shop", enabled=True)

        source = seed_source(create_random_user(), shop)
        source.customer = company
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=get_default_product(),
            supplier=get_default_supplier(),
            quantity=1,
            base_unit_price=source.create_price(10),
        )
        creator = OrderCreator()
        creator.create_order(source)
        company.refresh_from_db()
        assert shop in company.shops.all()
Exemple #44
0
def test_order_creator_company_multishop():
    with override_settings(SHUUP_MANAGE_CONTACTS_PER_SHOP=True, SHUUP_ENABLE_MULTIPLE_SHOPS=True):
        company = create_random_company()
        shop = get_shop(identifier="random-shop", enabled=True)

        source = seed_source(create_random_user(), shop)
        source.customer = company
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=get_default_product(),
            supplier=get_default_supplier(),
            quantity=1,
            base_unit_price=source.create_price(10),
        )
        creator = OrderCreator()
        creator.create_order(source)
        company.refresh_from_db()
        assert shop in company.shops.all()
Exemple #45
0
def test_order_customer_groups(rf, admin_user):
    customer = create_random_person()
    default_group = get_default_customer_group()
    default_group.members.add(customer)
    source = seed_source(admin_user)
    source.customer=customer

    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,
    )

    creator = OrderCreator()
    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)
    customer = source.customer
    assert customer == order.customer
    assert customer.groups.count() == 2
    assert order.customer_groups.filter(id=default_group.id).exists()
    with pytest.raises(ProtectedError):
        default_group.delete()

    assert customer.tax_group is not None
    assert customer.tax_group == order.tax_group
    with pytest.raises(ProtectedError):
        customer.tax_group.delete()

    new_group = create_random_contact_group()
    new_group.members.add(customer)

    order.phone = "911"
    order.save()
    assert order.customer_groups.filter(id=default_group.id).exists()
    assert not order.customer_groups.filter(id=new_group.id).exists()
Exemple #46
0
def _get_order(prices_include_tax=False, include_basket_campaign=False, include_catalog_campaign=False):
    shop = get_shop(prices_include_tax=prices_include_tax)
    supplier = get_simple_supplier()

    if include_basket_campaign:
        _add_basket_campaign(shop)

    if include_catalog_campaign:
        _add_catalog_campaign(shop)
    _add_taxes()

    source = BasketishOrderSource(shop)
    source.status = get_initial_order_status()
    ctx = get_pricing_module().get_context_from_data(shop, AnonymousContact())
    for product_data in _get_product_data():
        quantity = product_data.pop("quantity")
        product = create_product(
            sku=product_data.pop("sku"),
            shop=shop,
            supplier=supplier,
            stock_behavior=StockBehavior.STOCKED,
            tax_class=get_default_tax_class(),
            **product_data)
        shop_product = product.get_shop_instance(shop)
        shop_product.categories.add(get_default_category())
        shop_product.save()
        supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY)
        pi = product.get_price_info(ctx)
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=product,
            supplier=supplier,
            quantity=quantity,
            base_unit_price=pi.base_unit_price,
            discount_amount=pi.discount_amount
        )
    oc = OrderCreator()
    order = oc.create_order(source)
    order.create_payment(Money("1", "EUR"))
    assert not order.has_refunds()
    assert order.can_create_refund()
    assert order.shipping_status == ShippingStatus.NOT_SHIPPED
    assert order.payment_status == PaymentStatus.PARTIALLY_PAID
    return order
Exemple #47
0
def _get_order(prices_include_tax=False, include_basket_campaign=False, include_catalog_campaign=False):
    shop = get_shop(prices_include_tax=prices_include_tax)
    supplier = get_simple_supplier()

    if include_basket_campaign:
        _add_basket_campaign(shop)

    if include_catalog_campaign:
        _add_catalog_campaign(shop)
    _add_taxes()

    source = BasketishOrderSource(shop)
    source.status = get_initial_order_status()
    ctx = get_pricing_module().get_context_from_data(shop, AnonymousContact())
    for product_data in _get_product_data():
        quantity = product_data.pop("quantity")
        product = create_product(
            sku=product_data.pop("sku"),
            shop=shop,
            supplier=supplier,
            stock_behavior=StockBehavior.STOCKED,
            tax_class=get_default_tax_class(),
            **product_data)
        shop_product = product.get_shop_instance(shop)
        shop_product.categories.add(get_default_category())
        shop_product.save()
        supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY)
        pi = product.get_price_info(ctx)
        source.add_line(
            type=OrderLineType.PRODUCT,
            product=product,
            supplier=supplier,
            quantity=quantity,
            base_unit_price=pi.base_unit_price,
            discount_amount=pi.discount_amount
        )
    oc = OrderCreator()
    order = oc.create_order(source)
    order.create_payment(Money("1", "EUR"))
    assert not order.has_refunds()
    assert order.can_create_refund()
    assert order.shipping_status == ShippingStatus.NOT_SHIPPED
    assert order.payment_status == PaymentStatus.PARTIALLY_PAID
    return order
Exemple #48
0
def test_campaign_with_coupons2(rf):
    basket, dc, request, status = _init_basket_coupon_test(rf, code="tEsT")

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

    customer_code = "Test"  # Customer typoed the code, should still match
    basket.add_code(customer_code)

    assert customer_code in basket.codes
    assert len(basket.codes) == 1  # only one code

    basket.add_code(customer_code.upper())
    assert customer_code.upper() not in basket.codes
    assert len(basket.codes) == 1  # only one 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]  # they don't match like this
    assert [c.upper()
            for c in basket.codes] == [dc.code.upper()]  # they match like this
    assert [c.upper() for c in basket.codes
            ] != [customer_code]  # they don't match like this
    assert basket.codes == [customer_code]  # they match like this

    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()]

    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
Exemple #49
0
def get_order_and_source(admin_user, product, language, language_fallback):
    # create original source to tamper with

    contact = get_person_contact(admin_user)
    contact.language = language
    contact.save()

    assert contact.language == language  # contact language is naive

    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 = contact
    source.payment_method = get_default_payment_method()
    source.shipping_method = get_default_shipping_method()
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=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

    assert not source._language  # is None because it was not directly assigned
    assert source.language == language_fallback

    creator = OrderCreator()
    order = creator.create_order(source)

    assert order.language == source.language

    return order, source
Exemple #50
0
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_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",
    ]
Exemple #52
0
def get_order_and_source(admin_user, product, language, language_fallback):
    # create original source to tamper with

    contact = get_person_contact(admin_user)
    contact.language = language
    contact.save()

    assert contact.language == language  # contact language is naive

    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 = contact
    source.payment_method = get_default_payment_method()
    source.shipping_method = get_default_shipping_method()
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=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

    assert not source._language  # is None because it was not directly assigned
    assert source.language == language_fallback

    creator = OrderCreator()
    order = creator.create_order(source)

    assert order.language == source.language

    return order, source
Exemple #53
0
def test_order_creator_min_total(rf, admin_user):
    shop = get_default_shop()
    configuration.set(shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(20))

    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),
    )

    creator = OrderCreator()
    with pytest.raises(ValidationError):
        creator.create_order(source)

    configuration.set(shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(1))
    creator.create_order(source)

    # do not mess with other tests
    configuration.set(shop, ORDER_MIN_TOTAL_CONFIG_KEY, Decimal(0))
Exemple #54
0
def test_campaign_with_coupons2(rf):
    basket, dc, request, status = _init_basket_coupon_test(rf, code="tEsT")

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

    customer_code = "Test"  # Customer typoed the code, should still match
    basket.add_code(customer_code)

    assert customer_code in basket.codes
    assert len(basket.codes) == 1  # only one code

    basket.add_code(customer_code.upper())
    assert customer_code.upper() not in basket.codes
    assert len(basket.codes) == 1  # only one 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]  # they don't match like this
    assert [c.upper() for c in basket.codes] == [dc.code.upper()]  # they match like this
    assert [c.upper() for c in basket.codes] != [customer_code]  # they don't match like this
    assert basket.codes == [customer_code]  # they match like this

    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
Exemple #55
0
def test_shipping_report(rf):
    shop = get_default_shop()
    tax_class = get_default_tax_class()
    creator = OrderCreator()

    carrier1 = CustomCarrier.objects.create(name="Carrier1")
    sm1 = carrier1.create_service(None, shop=get_default_shop(), enabled=True, tax_class=tax_class, name="SM #1")
    sm1.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=Decimal(10)))
    sm2 = carrier1.create_service(None, shop=get_default_shop(), enabled=True, tax_class=tax_class, name="SM #2")
    sm2.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=Decimal(99)))
    sm2.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=Decimal(4)))

    carrier2 = CustomCarrier.objects.create(name="Carrier2")
    sm3 = carrier2.create_service(None, shop=get_default_shop(), enabled=True, tax_class=tax_class, name="SM #3")
    sm3.behavior_components.add(FixedCostBehaviorComponent.objects.create(price_value=Decimal(5)))

    source1 = seed_source(sm1)
    source2 = seed_source(sm1)
    source3 = seed_source(sm2)
    source4 = seed_source(sm3)

    creator.create_order(source1)
    creator.create_order(source2)
    creator.create_order(source3)
    creator.create_order(source4)

    # pay orders
    [o.create_payment(o.taxful_total_price) for o in Order.objects.all()]

    data = {
        "report": ShippingReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.ALL_TIME,
        "writer": "json",
        "force_download": 1,
    }
    report = ShippingReport(**data)
    writer = get_writer_instance(data["writer"])
    response = writer.get_response(report=report)
    if hasattr(response, "render"):
        response.render()
    json_data = json.loads(response.content.decode("utf-8"))
    assert force_text(ShippingReport.title) in json_data.get("heading")
    data = json_data.get("tables")[0].get("data")
    assert len(data) == 3

    expected_result = [
        {
            "carrier": carrier1.name,
            "shipping_method": sm1.name,
            "order_count": 2,
            "total_charged": sum([bc.price_value for bc in sm1.behavior_components.all()]) * 2  # 2 orders
        },
        {
            "carrier": carrier1.name,
            "shipping_method": sm2.name,
            "order_count": 1,
            "total_charged": sum([bc.price_value for bc in sm2.behavior_components.all()])
        },
        {
            "carrier": carrier2.name,
            "shipping_method": sm3.name,
            "order_count": 1,
            "total_charged": sum([bc.price_value for bc in sm3.behavior_components.all()])
        }
    ]

    for ix, shipping in enumerate(data):
        assert shipping["carrier"] == expected_result[ix]["carrier"]
        assert shipping["shipping_method"] == expected_result[ix]["shipping_method"]
        assert shipping["order_count"] == str(expected_result[ix]["order_count"])
        assert shipping["total_charged"] == str(expected_result[ix]["total_charged"].quantize(Decimal("0.01")))
Exemple #56
0
def test_coupons_usage_report(rf):
    shop = get_default_shop()
    tax_class = get_default_tax_class()
    creator = OrderCreator()

    coupon1 = Coupon.objects.create(code="coupon1", active=True)
    coupon2 = Coupon.objects.create(code="coupon2", active=True)

    campaign1 = get_default_campaign(coupon1, "10")
    campaign2 = get_default_campaign(coupon2, "25")

    source1 = seed_source(coupon1)
    source2 = seed_source(coupon1)
    source3 = seed_source(coupon1)
    source4 = seed_source(coupon2)

    creator.create_order(source1)
    creator.create_order(source2)
    creator.create_order(source3)
    creator.create_order(source4)

    # pay orders
    [o.create_payment(o.taxful_total_price) for o in Order.objects.all()]

    data = {
        "report": CouponsUsageReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.ALL_TIME,
        "writer": "json",
        "force_download": 1,
    }
    report = CouponsUsageReport(**data)
    writer = get_writer_instance(data["writer"])
    response = writer.get_response(report=report)
    if hasattr(response, "render"):
        response.render()
    json_data = json.loads(response.content.decode("utf-8"))
    assert force_text(CouponsUsageReport.title) in json_data.get("heading")
    data = json_data.get("tables")[0].get("data")
    assert len(data) == Order.objects.count()

    expected_data = []

    orders = Order.objects.all().order_by("order_date")
    for order in orders:
        discount = order.shop.create_price(0)
        for dt in order.lines.discounts():
            discount += dt.taxful_price

        expected_data.append({
            "date": format_date(order.order_date, locale=get_current_babel_locale()),
            "coupon": order.codes[0],
            "order": str(order),
            "taxful_total": str(order.taxful_total_price.as_rounded().value),
            "taxful_subtotal": str((order.taxful_total_price - discount).as_rounded().value),
            "total_discount": str(discount.as_rounded().value)
        })

    assert len(expected_data) == len(data)

    for ix, d in enumerate(data):
        for k, v in d.items():
            assert expected_data[ix][k] == v
Exemple #57
0
def test_broken_order(admin_user):
    """
    """
    quantities = [44, 23, 65]
    expected = sum(quantities) * 50
    expected_based_on = expected / 1.5

    # Shuup is calculating taxes per line so there will be some "errors"
    expected_based_on = ensure_decimal_places(Decimal("%s" % (expected_based_on + 0.01)))

    shop = get_default_shop()

    supplier = get_default_supplier()
    product1 = create_product("simple-test-product1", shop, supplier, 50)
    product2 = create_product("simple-test-product2", shop, supplier, 50)
    product3 = create_product("simple-test-product3", shop, supplier, 50)

    tax = get_default_tax()

    source = BasketishOrderSource(get_default_shop())
    billing_address = get_address(country="US")
    shipping_address = get_address(name="Test street", country="US")
    source.status = get_initial_order_status()
    source.billing_address = billing_address
    source.shipping_address = shipping_address
    source.customer = create_random_person()
    source.payment_method = get_default_payment_method()
    source.shipping_method = get_default_shipping_method()

    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product1,
        supplier=get_default_supplier(),
        quantity=quantities[0],
        base_unit_price=source.create_price(50),
    )

    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product2,
        supplier=get_default_supplier(),
        quantity=quantities[1],
        base_unit_price=source.create_price(50),
    )

    source.add_line(
        type=OrderLineType.PRODUCT,
        product=product3,
        supplier=get_default_supplier(),
        quantity=quantities[2],
        base_unit_price=source.create_price(50),
    )

    currency = "EUR"
    summary = source.get_tax_summary()


    assert len(summary) == 1
    summary = summary[0]

    assert summary.taxful == Money(expected, "EUR")
    assert summary.based_on == Money(expected_based_on, "EUR")

    # originally non-rounded value
    assert bankers_round(source.get_total_tax_amount()) == summary.tax_amount

    assert source.taxless_total_price.value == expected_based_on
    assert summary.taxful.value == source.taxful_total_price.value

    assert summary.tax_amount == Money(bankers_round(source.taxful_total_price.value - source.taxless_total_price.value), currency)
    assert summary.taxful == summary.raw_based_on + summary.tax_amount

    assert summary.tax_rate == tax.rate
    assert summary.taxful.value == (summary.based_on + summary.tax_amount).value - Decimal("%s" % 0.01)

    # create order from basket
    creator = OrderCreator()
    order = creator.create_order(source)
    assert order.taxless_total_price.value == expected_based_on

    # originally non-rounded value
    assert bankers_round(order.get_total_tax_amount()) == summary.tax_amount