Beispiel #1
0
def _create_total_sales(shop, day):
    product = create_product("test", shop=shop)
    supplier = get_default_supplier()
    order = create_order_with_product(product, supplier, 1, 10, shop=shop)
    order.order_date = day
    order.save()
Beispiel #2
0
def test_basket_reorder_staff_user():
    with override_settings(**REQUIRED_SETTINGS):
        set_configuration()
        shop = factories.get_default_shop()
        factories.get_default_payment_method()
        factories.get_default_shipping_method()
        staff_user = User.objects.create(username="******", is_staff=True)

        client = _get_client(staff_user)
        person = factories.create_random_person()

        # create an order for the person
        product = create_product("product",
                                 shop=shop,
                                 supplier=get_default_supplier(),
                                 default_price='12.4')
        order = create_random_order(customer=person,
                                    products=[product],
                                    completion_probability=1,
                                    shop=shop)

        # create the basket
        response = client.post("/api/wshop/basket/new/",
                               data={
                                   "shop": shop.pk,
                                   "customer": person.pk
                               },
                               format="json")
        # Only stuff linked to shop can create baskets for someone else
        assert response.status_code == status.HTTP_403_FORBIDDEN

        # Can still add personal baskets
        staff_person = get_person_contact(staff_user)
        response = client.post("/api/wshop/basket/new/",
                               data={
                                   "shop": shop.pk,
                                   "customer": staff_person.pk
                               },
                               format="json")
        assert response.status_code == status.HTTP_201_CREATED
        basket_data = json.loads(response.content.decode("utf-8"))
        basket = Basket.objects.filter(
            key=basket_data["uuid"].split("-")[1]).first()
        assert basket.shop == shop
        assert basket.creator == staff_user
        assert basket.customer.pk == staff_person.pk
        response = client.get("/api/wshop/basket/{}/".format(
            basket_data["uuid"]))
        assert response.status_code == 200

        # Ok let's link the staff member to the shop and
        # the basket create for random person should work
        shop.staff_members.add(staff_user)
        response = client.post("/api/wshop/basket/new/",
                               data={
                                   "shop": shop.pk,
                                   "customer": person.pk
                               },
                               format="json")
        assert response.status_code == status.HTTP_201_CREATED
        basket_data = json.loads(response.content.decode("utf-8"))
        basket = Basket.objects.filter(
            key=basket_data["uuid"].split("-")[1]).first()
        assert basket.shop == shop
        assert basket.creator == staff_user
        assert basket.customer.pk == person.pk
        response = client.get("/api/wshop/basket/{}/".format(
            basket_data["uuid"]))
        assert response.status_code == 200
        assert basket.creator == staff_user
        assert basket.customer.pk == person.pk

        # add contents to the basket from a customer order
        response = client.post(
            '/api/wshop/basket/{}-{}/add_from_order/'.format(
                shop.pk, basket.key),
            data={"order": order.pk},
            format="json")
        assert response.status_code == status.HTTP_200_OK
        basket_data = json.loads(response.content.decode("utf-8"))
        assert len(basket_data['items']) > 0
        assert Decimal(basket_data['taxful_total_price']
                       ) == order.taxful_total_price_value

        # finally create the order
        response = client.post('/api/wshop/basket/{}-{}/create_order/'.format(
            shop.pk, basket.key))
        assert response.status_code == status.HTTP_201_CREATED
        response_data = json.loads(response.content.decode("utf-8"))
        created_order = Order.objects.get(id=response_data['id'])
        assert created_order.creator == staff_user
        assert created_order.customer == person

        # create a second customer
        person2 = factories.create_random_person()
        # create a basket for customer 2 and try to fill with contents of customer 1 order - it should not be possible
        response = client.post("/api/wshop/basket/new/",
                               data={
                                   "shop": shop.pk,
                                   "customer": person2.pk
                               },
                               format="json")
        assert response.status_code == status.HTTP_201_CREATED
        basket_data = json.loads(response.content.decode("utf-8"))
        basket = Basket.objects.filter(
            key=basket_data["uuid"].split("-")[1]).first()
        assert basket.shop == shop
        assert basket.creator == staff_user
        assert basket.customer.pk == person2.pk

        # add contents to the basket from customer 1 order - error
        response = client.post(
            '/api/wshop/basket/{}-{}/add_from_order/'.format(
                shop.pk, basket.key),
            data={"order": order.pk},
            format="json")
        assert response.status_code == status.HTTP_404_NOT_FOUND
        assert 'invalid order' in response.content.decode("utf-8")
Beispiel #3
0
def _create_product_for_day(shop, day):
    product = create_product("test_product")
    product.created_on = day
    product.save()
Beispiel #4
0
def test_product_add_attribute(admin_user):
    shop = get_default_shop()
    client = _get_client(admin_user)
    product = create_product("product1")

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

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

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

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

    # try to add an attribute which does not belong to the product type
    product_attr3_data = {
        "attribute": attribute3.pk,
        "untraslated_string": "lalala"
    }
    response = client.post("/api/wshop/product/%d/add_attribute/" % product.pk,
                           content_type="application/json",
                           data=json.dumps(product_attr3_data))
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert ProductAttribute.objects.filter(product=product).count() == 2
Beispiel #5
0
def test_get_product_stocks(admin_user):
    client = _get_client(admin_user)
    shop1 = Shop.objects.create()
    shop2 = Shop.objects.create()

    supplier1 = create_simple_supplier("1")
    supplier2 = create_simple_supplier("2")

    product1 = create_product("product 1")
    product1.stock_behavior = StockBehavior.STOCKED
    product1.save()
    sp = ShopProduct.objects.create(product=product1, shop=shop1)
    sp.suppliers.add(supplier1)
    sp.suppliers.add(supplier2)
    sp = ShopProduct.objects.create(product=product1, shop=shop2)
    sp.suppliers.add(supplier1)
    sp.suppliers.add(supplier2)

    product2 = create_product("product 2")
    product2.stock_behavior = StockBehavior.STOCKED
    product2.save()
    sp = ShopProduct.objects.create(product=product2, shop=shop1)
    sp.suppliers.add(supplier1)
    sp = ShopProduct.objects.create(product=product2, shop=shop2)
    sp.suppliers.add(supplier1)

    product3 = create_product("product 3", shop=shop1, supplier=supplier2)
    product3.stock_behavior = StockBehavior.STOCKED
    product3.save()

    # put some stock
    supplier1.adjust_stock(product1.pk, 100)
    supplier1.adjust_stock(product2.pk, 300)
    supplier2.adjust_stock(product1.pk, 110)
    supplier2.adjust_stock(product3.pk, 300)

    # list all stocks
    response = client.get("/api/wshop/product/stocks/")
    assert response.status_code == status.HTTP_200_OK
    stock_data = sorted(json.loads(response.content.decode("utf-8")),
                        key=lambda prod: prod["product"])
    assert len(stock_data) == 3

    assert stock_data[0]["product"] == product1.pk
    assert stock_data[0]["sku"] == product1.sku
    stocks = sorted(stock_data[0]["stocks"], key=lambda stock: stock["id"])
    assert len(stocks) == 2
    assert stocks[0]["id"] == supplier1.id
    assert stocks[0]["physical_count"] == supplier1.get_stock_status(
        product1.pk).physical_count
    assert stocks[0]["logical_count"] == supplier1.get_stock_status(
        product1.pk).logical_count
    assert stocks[1]["id"] == supplier2.id
    assert stocks[1]["physical_count"] == supplier2.get_stock_status(
        product1.pk).physical_count
    assert stocks[1]["logical_count"] == supplier2.get_stock_status(
        product1.pk).logical_count

    assert stock_data[1]["product"] == product2.pk
    assert stock_data[1]["sku"] == product2.sku
    stocks = sorted(stock_data[1]["stocks"], key=lambda stock: stock["id"])
    assert len(stocks) == 1
    assert stocks[0]["id"] == supplier1.id
    assert stocks[0]["physical_count"] == supplier1.get_stock_status(
        product2.pk).physical_count
    assert stocks[0]["logical_count"] == supplier1.get_stock_status(
        product2.pk).logical_count

    assert stock_data[2]["product"] == product3.pk
    assert stock_data[2]["sku"] == product3.sku
    stocks = sorted(stock_data[2]["stocks"], key=lambda stock: stock["id"])
    assert len(stocks) == 1
    assert stocks[0]["id"] == supplier2.id
    assert stocks[0]["physical_count"] == supplier2.get_stock_status(
        product3.pk).physical_count
    assert stocks[0]["logical_count"] == supplier2.get_stock_status(
        product3.pk).logical_count

    # list all stocks - filter by supplier and sku
    response = client.get("/api/wshop/product/stocks/?sku=%s&supplier=%d" %
                          (product1.sku, supplier1.id))
    assert response.status_code == status.HTTP_200_OK
    stock_data = sorted(json.loads(response.content.decode("utf-8")),
                        key=lambda prod: prod["product"])
    assert len(stock_data) == 1
    assert stock_data[0]["product"] == product1.pk
    assert stock_data[0]["sku"] == product1.sku
    assert stock_data[0]["stocks"][0]["id"] == supplier1.id
    assert stock_data[0]["stocks"][0][
        "physical_count"] == supplier1.get_stock_status(
            product1.pk).physical_count
    assert stock_data[0]["stocks"][0][
        "logical_count"] == supplier1.get_stock_status(
            product1.pk).logical_count

    # list all stocks - filter by supplier and id
    response = client.get("/api/wshop/product/stocks/?product=%d&supplier=%d" %
                          (product2.id, supplier1.id))
    assert response.status_code == status.HTTP_200_OK
    stock_data = sorted(json.loads(response.content.decode("utf-8")),
                        key=lambda prod: prod["product"])
    assert len(stock_data) == 1
    assert stock_data[0]["product"] == product2.pk
    assert stock_data[0]["sku"] == product2.sku
    assert stock_data[0]["stocks"][0]["id"] == supplier1.id
    assert stock_data[0]["stocks"][0][
        "physical_count"] == supplier1.get_stock_status(
            product2.pk).physical_count
    assert stock_data[0]["stocks"][0][
        "logical_count"] == supplier1.get_stock_status(
            product2.pk).logical_count
Beispiel #6
0
def test_order_create_without_shipping_or_billing_method(admin_user):
    create_default_order_statuses()
    shop = get_default_shop()
    contact = create_random_person(locale="en_US", minimum_name_comp_len=5)
    product = create_product(sku=printable_gibberish(),
                             supplier=get_default_supplier(),
                             shop=shop)
    assert not Order.objects.count()
    client = _get_client(admin_user)
    lines = [
        {
            "type": "product",
            "product": product.id,
            "quantity": "1",
            "base_unit_price_value": "5.00"
        },
        {
            "type": "product",
            "product": product.id,
            "quantity": "2",
            "base_unit_price_value": "1.00",
            "discount_amount_value": "0.50"
        },
        {
            "type": "other",
            "sku": "hello",
            "text": "A greeting",
            "quantity": 1,
            "base_unit_price_value": "3.5"
        },
        {
            "type": "text",
            "text": "This was an order!",
            "quantity": 0
        },
    ]
    response = client.post("/api/wshop/order/",
                           content_type="application/json",
                           data=json.dumps({
                               "shop": shop.pk,
                               "customer": contact.pk,
                               "lines": lines
                           }))
    assert response.status_code == 201
    assert Order.objects.count() == 1
    order = Order.objects.first()
    assert order.shop == shop
    assert order.shipping_method is None
    assert order.payment_method is None
    assert order.customer == contact
    assert order.creator == admin_user
    assert order.billing_address == contact.default_billing_address.to_immutable(
    )
    assert order.shipping_address == contact.default_shipping_address.to_immutable(
    )
    assert order.payment_status == PaymentStatus.NOT_PAID
    assert order.shipping_status == ShippingStatus.NOT_SHIPPED
    assert order.status == OrderStatus.objects.get_default_initial()
    assert order.taxful_total_price_value == decimal.Decimal(10)
    assert order.lines.count() == 4  # 2 product lines, 2 other lines
    for idx, line in enumerate(order.lines.all()[:4]):
        assert line.quantity == decimal.Decimal(lines[idx].get("quantity"))
        assert line.base_unit_price_value == decimal.Decimal(lines[idx].get(
            "base_unit_price_value", 0))
        assert line.discount_amount_value == decimal.Decimal(lines[idx].get(
            "discount_amount_value", 0))
Beispiel #7
0
def get_frontend_order_state(contact,
                             payment_method,
                             product_price,
                             valid_lines=True):
    """
    Get a dict structure mirroring what the frontend JavaScript would submit.
    :type contact: Contact|None
    """
    translation.activate("en")
    shop = get_default_shop()
    tax = Tax.objects.create(code="test_code",
                             rate=decimal.Decimal("0.20"),
                             name="Default")
    tax_class = TaxClass.objects.create(identifier="test_tax_class",
                                        name="Default")
    rule = TaxRule.objects.create(tax=tax)
    rule.tax_classes.add(tax_class)
    rule.save()
    product = create_product(sku=printable_gibberish(),
                             supplier=get_default_supplier(),
                             shop=shop)
    product.tax_class = tax_class
    product.save()
    if valid_lines:
        lines = [
            {
                "id": "x",
                "type": "product",
                "product": {
                    "id": product.id
                },
                "quantity": "1",
                "baseUnitPrice": product_price
            },
            {
                "id": "z",
                "type": "text",
                "text": "This was an order!",
                "quantity": 0
            },
        ]
    else:
        unshopped_product = create_product(sku=printable_gibberish(),
                                           supplier=get_default_supplier())
        not_visible_product = create_product(sku=printable_gibberish(),
                                             supplier=get_default_supplier(),
                                             shop=shop)
        not_visible_shop_product = not_visible_product.get_shop_instance(shop)
        not_visible_shop_product.visibility = ShopProductVisibility.NOT_VISIBLE
        not_visible_shop_product.save()
        lines = [
            {
                "id": "x",
                "type": "product"
            },  # no product?
            {
                "id": "x",
                "type": "product",
                "product": {
                    "id": unshopped_product.id
                }
            },  # not in this shop?
            {
                "id": "y",
                "type": "product",
                "product": {
                    "id": -product.id
                }
            },  # invalid product?
            {
                "id": "z",
                "type": "other",
                "quantity": 1,
                "unitPrice": "q"
            },  # what's that price?
            {
                "id": "rr",
                "type": "product",
                "quantity": 1,
                "product": {
                    "id": not_visible_product.id
                }
            }  # not visible
        ]

    state = {
        "customer": {
            "id": contact.id if contact else None,
            "billingAddress":
            encode_address(contact.default_billing_address) if contact else {},
            "shippingAddress": encode_address(contact.default_shipping_address)
            if contact else {},
        },
        "lines": lines,
        "methods": {
            "shippingMethod": {
                "id": get_default_shipping_method().id
            },
            "paymentMethod": {
                "id": payment_method.id
            },
        },
        "shop": {
            "selected": {
                "id": shop.id,
                "name": shop.name,
                "currency": shop.currency,
                "priceIncludeTaxes": shop.prices_include_tax
            }
        }
    }
    return state
Beispiel #8
0
def test_basket_partial_quantity_update_all_product_counts():
    shop = get_default_shop()
    supplier = get_default_supplier()
    request = get_request_with_basket()
    basket = request.basket

    pieces = SalesUnit.objects.create(identifier="pieces",
                                      decimals=0,
                                      name="Pieces",
                                      symbol='pc.')
    kilograms = SalesUnit.objects.create(identifier="kilograms",
                                         decimals=3,
                                         name="Kilograms",
                                         symbol='kg')
    cup = create_product(sku="COFFEE-CUP-123",
                         sales_unit=pieces,
                         shop=shop,
                         supplier=supplier)
    beans = create_product(sku="COFFEEBEANS3",
                           sales_unit=kilograms,
                           shop=shop,
                           supplier=supplier)
    beans_shop_product = beans.get_shop_instance(shop)
    beans_shop_product.minimum_purchase_quantity = Decimal('0.1')
    beans_shop_product.save()
    pears = create_product(sku="PEARS-27",
                           sales_unit=kilograms,
                           shop=shop,
                           supplier=supplier)

    add = basket_commands.handle_add
    update = basket_commands.handle_update

    # Empty basket
    assert basket.product_count == 0
    assert basket.smart_product_count == 0
    assert basket.product_line_count == 0

    # 1 cup
    add(request, basket, product_id=cup.pk, quantity=1)
    assert basket.product_count == 1
    assert basket.smart_product_count == 1
    assert basket.product_line_count == 1

    # Basket update operations work by prefixing line id with operation
    qty_update_cup = 'q_' + basket.get_lines()[0].line_id
    delete_cup = 'delete_' + basket.get_lines()[0].line_id

    # 3 cups
    update(request, basket, **{qty_update_cup: "3"})
    assert basket.product_count == 3
    assert basket.smart_product_count == 3
    assert basket.product_line_count == 1

    # 3 cups + 0.5 kg beans
    add(request, basket, product_id=beans.pk, quantity='0.5')
    assert basket.product_count == Decimal('3.5')
    assert basket.smart_product_count == 4
    assert basket.product_line_count == 2

    qty_update_beans = 'q_' + basket.get_lines()[1].line_id
    delete_beans1 = 'delete_' + basket.get_lines()[1].line_id

    # 1 cup + 2.520 kg beans
    update(request, basket, **{qty_update_cup: "1.0"})
    update(request, basket, **{qty_update_beans: "2.520"})
    assert basket.product_count == Decimal('3.520')
    assert basket.smart_product_count == 2
    assert basket.product_line_count == 2

    # 42 cups + 2.520 kg beans
    update(request, basket, **{qty_update_cup: "42"})
    assert basket.product_count == Decimal('44.520')
    assert basket.smart_product_count == 43
    assert basket.product_line_count == 2

    # 42 cups + 2.520 kg beans + 3.5 kg pears
    add(request, basket, product_id=pears.pk, quantity='3.5')
    assert basket.product_count == Decimal('48.020')
    assert basket.smart_product_count == 44
    assert basket.product_line_count == 3

    # 42 cups + 3.5 kg pears
    update(request, basket, **{delete_beans1: "1"})
    assert basket.product_count == Decimal('45.5')
    assert basket.smart_product_count == 43
    assert basket.product_line_count == 2

    # 3.5 kg pears
    update(request, basket, **{delete_cup: "1"})
    assert basket.product_count == Decimal('3.5')
    assert basket.smart_product_count == 1
    assert basket.product_line_count == 1
Beispiel #9
0
def test_create_order(admin_user, currency):
    create_default_order_statuses()
    shop = get_default_shop()
    shop.currency = currency
    tax = get_default_tax()
    Currency.objects.get_or_create(code=currency, decimal_places=2)
    shop.save()
    sm = get_default_shipping_method()
    pm = get_default_payment_method()
    contact = create_random_person(locale="en_US", minimum_name_comp_len=5)
    default_group = get_default_customer_group()
    default_group.members.add(contact)
    account_manager = create_random_person(locale="en_US",
                                           minimum_name_comp_len=5)
    contact.account_manager = account_manager
    contact.save()

    product = create_product(sku=printable_gibberish(),
                             supplier=get_default_supplier(),
                             shop=shop)
    assert not Order.objects.count()
    client = _get_client(admin_user)
    lines = [
        {
            "type": "product",
            "product": product.id,
            "quantity": "1",
            "base_unit_price_value": "5.00"
        },
        {
            "type": "product",
            "product": product.id,
            "quantity": "2",
            "base_unit_price_value": "1.00",
            "discount_amount_value": "0.50"
        },
        {
            "type": "other",
            "sku": "hello",
            "text": "A greeting",
            "quantity": 1,
            "base_unit_price_value": "3.5"
        },
        {
            "type": "text",
            "text": "This was an order!",
            "quantity": 0
        },
    ]
    response = client.post("/api/wshop/order/",
                           content_type="application/json",
                           data=json.dumps({
                               "shop": shop.pk,
                               "shipping_method": sm.pk,
                               "payment_method": pm.pk,
                               "customer": contact.pk,
                               "lines": lines
                           }))
    assert response.status_code == 201
    assert Order.objects.count() == 1
    order = Order.objects.first()
    assert order.shop == shop
    assert order.shipping_method == sm
    assert order.payment_method == pm
    assert order.customer == contact
    assert order.creator == admin_user
    assert order.billing_address == contact.default_billing_address.to_immutable(
    )
    assert order.shipping_address == contact.default_shipping_address.to_immutable(
    )
    assert order.payment_status == PaymentStatus.NOT_PAID
    assert order.shipping_status == ShippingStatus.NOT_SHIPPED
    assert order.status == OrderStatus.objects.get_default_initial()
    assert order.taxful_total_price_value == decimal.Decimal(10)
    assert order.lines.count(
    ) == 6  # shipping line, payment line, 2 product lines, 2 other lines
    assert order.currency == currency
    for idx, line in enumerate(order.lines.all()[:4]):
        assert line.quantity == decimal.Decimal(lines[idx].get("quantity"))
        assert line.base_unit_price_value == decimal.Decimal(lines[idx].get(
            "base_unit_price_value", 0))
        assert line.discount_amount_value == decimal.Decimal(lines[idx].get(
            "discount_amount_value", 0))

    # Test tax summary
    response_data = json.loads(response.content.decode("utf-8"))
    # Tax summary should not be present here
    assert "summary" not in response_data

    response = client.get('/api/wshop/order/{}/taxes/'.format(order.pk))
    assert response.status_code == status.HTTP_200_OK
    response_data = json.loads(response.content.decode("utf-8"))

    assert "lines" in response_data
    assert "summary" in response_data
    line_summary = response_data["lines"]
    summary = response_data["summary"]
    first_tax_summary = summary[0]

    assert int(first_tax_summary["tax_id"]) == tax.id
    assert first_tax_summary["tax_rate"] == tax.rate

    first_line_summary = line_summary[0]
    assert "tax" in first_line_summary

    response = client.get("/api/wshop/order/%s/" % order.id)
    assert response.status_code == status.HTTP_200_OK
    order_data = json.loads(response.content.decode("utf-8"))
    assert order_data.get("id") == order.id

    assert "available_shipping_methods" in order_data
    assert "available_payment_methods" in order_data

    assert order_data["available_payment_methods"][0]["id"] == pm.id
    assert order_data["available_shipping_methods"][0]["id"] == sm.id

    assert order.account_manager == account_manager
    assert order.customer_groups.count() == contact.groups.count()
    for group in order.customer_groups.all():
        assert contact.groups.filter(id=group.id).exists()

    assert order.tax_group is not None
    assert order.tax_group == contact.tax_group
Beispiel #10
0
def test_basket_with_package_product(admin_user):
    with override_settings(**REQUIRED_SETTINGS):
        shop = factories.get_default_shop()
        factories.get_default_shipping_method()
        factories.get_default_payment_method()
        OrderStatusManager().ensure_default_statuses()

        client = get_client(admin_user)
        response = client.post("/api/wshop/basket/new/",
                               format="json",
                               data={"shop": shop.pk})
        assert response.status_code == status.HTTP_201_CREATED
        basket_uuid = response.data["uuid"]

        supplier = factories.get_supplier(SimpleSupplierModule.identifier,
                                          shop=shop)

        # base product - 1kg of sand
        base_sand_product = factories.create_product(
            "Sand",
            shop=shop,
            supplier=supplier,
            default_price="15.2",
            net_weight=Decimal(1),
            stock_behavior=StockBehavior.STOCKED)

        # 10kg bag of sand - package made by 10kg of sand
        sand_bag_10kg_product = factories.create_product(
            "Sand-bag-10-kg",
            shop=shop,
            supplier=supplier,
            default_price="149.9",
            net_weight=Decimal(10000))
        sand_bag_10kg_product.make_package({base_sand_product: 10})
        sand_bag_10kg_product.save()

        # 18.45kg bag of sand - package made by 18.45kg of sand
        sand_bag_1845kg_product = factories.create_product(
            "Sand-bag-1845-kg",
            shop=shop,
            supplier=supplier,
            default_price="179.9",
            net_weight=Decimal(18450))
        sand_bag_1845kg_product.make_package({base_sand_product: 18.45})
        sand_bag_1845kg_product.save()

        # 25kg bag of sand - package made by 25kg of sand
        sand_bag_25kg_product = factories.create_product(
            "Sand-bag-25-kg",
            shop=shop,
            supplier=supplier,
            default_price="2450.25",
            net_weight=Decimal(25000))
        sand_bag_25kg_product.make_package({base_sand_product: 25})
        sand_bag_25kg_product.save()

        initial_stock = 55

        # put 55 sands (55kg) in stock
        supplier.adjust_stock(base_sand_product.id, initial_stock)
        stock_status = supplier.get_stock_status(base_sand_product.id)
        assert stock_status.physical_count == initial_stock
        assert stock_status.logical_count == initial_stock

        # zero stock for packages
        assert supplier.get_stock_status(
            sand_bag_10kg_product.id).logical_count == 0
        assert supplier.get_stock_status(
            sand_bag_1845kg_product.id).logical_count == 0
        assert supplier.get_stock_status(
            sand_bag_25kg_product.id).logical_count == 0

        # add all the 3 packages to the basket, this will require (10 + 18.45 + 25 = 53.45 Sands)
        for product in [
                sand_bag_10kg_product, sand_bag_1845kg_product,
                sand_bag_25kg_product
        ]:
            response = client.post(
                "/api/wshop/basket/{}/add/".format(basket_uuid),
                format="json",
                data={
                    "shop": shop.pk,
                    "product": product.id
                })
            assert response.status_code == status.HTTP_200_OK

        # get the basket
        response = client.get("/api/wshop/basket/{}/".format(basket_uuid))
        assert response.status_code == status.HTTP_200_OK
        assert response.data["validation_errors"] == []

        # now add more 25kg and it shouldn't have enough stock
        response = client.post("/api/wshop/basket/{}/add/".format(basket_uuid),
                               format="json",
                               data={
                                   "shop": shop.pk,
                                   "product": sand_bag_25kg_product.id
                               })
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert "Insufficient stock" in response.data["error"]

        # create order anyway
        response = client.post(
            "/api/wshop/basket/{}/create_order/".format(basket_uuid),
            format="json")
        assert response.status_code == status.HTTP_201_CREATED
        order = Order.objects.get(id=response.data["id"])
        line_counter = Counter()

        for line in order.lines.products():
            line_counter[line.product.id] += line.quantity

        assert bankers_round(
            line_counter[base_sand_product.id]) == bankers_round(
                Decimal(10) + Decimal(18.45) + Decimal(25))
        assert line_counter[sand_bag_10kg_product.id] == 1
        assert line_counter[sand_bag_1845kg_product.id] == 1
        assert line_counter[sand_bag_25kg_product.id] == 1
def test_product_type_api(admin_user):
    get_default_shop()
    client = APIClient()
    client.force_authenticate(user=admin_user)

    product_type_data = {
        "translations": {
            "en": {
                "name": "type 1"
            }
        },
        "attributes": [
            create_random_product_attribute().pk,
            create_random_product_attribute().pk,
            create_random_product_attribute().pk
        ]
    }
    response = client.post("/api/wshop/product_type/",
                           content_type="application/json",
                           data=json.dumps(product_type_data))
    assert response.status_code == status.HTTP_201_CREATED
    product_type = ProductType.objects.first()
    assert product_type.name == product_type_data["translations"]["en"]["name"]
    assert set(product_type.attributes.all().values_list(
        "pk", flat=True)) >= set(product_type_data["attributes"])

    product_type_data["translations"]["en"]["name"] = "name 2"
    product_type_data["attributes"] = [
        create_random_product_attribute().pk,
        create_random_product_attribute().pk,
        create_random_product_attribute().pk
    ]

    response = client.put("/api/wshop/product_type/%d/" % product_type.id,
                          content_type="application/json",
                          data=json.dumps(product_type_data))
    assert response.status_code == status.HTTP_200_OK
    product_type = ProductType.objects.first()
    assert product_type.name == product_type_data["translations"]["en"]["name"]
    assert set(product_type.attributes.all().values_list(
        "pk", flat=True)) >= set(product_type_data["attributes"])

    response = client.get("/api/wshop/product_type/%d/" % product_type.id)
    assert response.status_code == status.HTTP_200_OK
    data = json.loads(response.content.decode("utf-8"))
    assert product_type.name == data["translations"]["en"]["name"]
    assert set(product_type.attributes.all().values_list(
        "pk", flat=True)) >= set(product_type_data["attributes"])

    response = client.get("/api/wshop/product_type/")
    assert response.status_code == status.HTTP_200_OK
    data = json.loads(response.content.decode("utf-8"))
    assert product_type.name == data[0]["translations"]["en"]["name"]
    assert set(product_type.attributes.all().values_list(
        "pk", flat=True)) >= set(data[0]["attributes"])

    # delete
    response = client.delete("/api/wshop/product_type/%d/" % product_type.id)
    assert response.status_code == status.HTTP_204_NO_CONTENT
    assert ProductType.objects.count() == 0

    # create a product and relate it to a product type
    product_type = ProductType.objects.create(name="type")
    product = create_product("product with product_type", type=product_type)

    # shouldn't be possible to delete a product type with a related product
    response = client.delete("/api/wshop/product_type/%d/" % product_type.id)
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert "This object can not be deleted because it is referenced by" in response.content.decode(
        "utf-8")
Beispiel #12
0
def test_taxes_report(rf):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product1 = create_product("p1", shop=shop, supplier=supplier)
    product2 = create_product("p2", shop=shop, supplier=supplier)
    create_product("p3", shop=shop, supplier=supplier)
    tax_rate1 = Decimal("0.3")
    tax_rate2 = Decimal("0.45")

    tax_rate1_instance = get_test_tax(tax_rate1)
    tax_rate2_instance = get_test_tax(tax_rate2)

    # orders for person 1
    person1 = create_random_person()
    order1 = create_order_with_product(product=product1,
                                       supplier=supplier,
                                       quantity=2,
                                       taxless_base_unit_price="5",
                                       tax_rate=tax_rate1,
                                       n_lines=1,
                                       shop=shop)
    order1.customer = person1
    order1.save()
    order2 = create_order_with_product(product=product2,
                                       supplier=supplier,
                                       quantity=1,
                                       taxless_base_unit_price="10",
                                       tax_rate=tax_rate1,
                                       n_lines=1,
                                       shop=shop)
    order2.customer = person1
    order2.save()

    # orders for person 2
    person2 = create_random_person()
    order3 = create_order_with_product(product=product1,
                                       supplier=supplier,
                                       quantity=1,
                                       taxless_base_unit_price="2",
                                       tax_rate=tax_rate2,
                                       n_lines=1,
                                       shop=shop)
    order3.customer = person2
    order3.save()

    order4 = create_order_with_product(product=product2,
                                       supplier=supplier,
                                       quantity=2,
                                       taxless_base_unit_price="8",
                                       tax_rate=tax_rate1,
                                       n_lines=1,
                                       shop=shop)
    order4.customer = person2
    order4.save()

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

    data = {
        "report": TaxesReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.ALL_TIME,
        "writer": "json",
        "force_download": 1,
    }
    report = TaxesReport(**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(TaxesReport.title) in json_data.get("heading")
    data = json_data.get("tables")[0].get("data")
    assert len(data) == 2

    tax1_rate1_total = (
        (order1.taxful_total_price_value - order1.taxless_total_price_value) +
        (order2.taxful_total_price_value - order2.taxless_total_price_value) +
        (order4.taxful_total_price_value - order4.taxless_total_price_value))
    tax1_pretax_total = (order1.taxless_total_price_value +
                         order2.taxless_total_price_value +
                         order4.taxless_total_price_value)
    tax1_total = (order1.taxful_total_price_value +
                  order2.taxful_total_price_value +
                  order4.taxful_total_price_value)
    tax2_rate2_total = (order3.taxful_total_price_value -
                        order3.taxless_total_price_value)

    # the report data order is the total charged ascending
    expected_result = [{
        "tax": tax_rate2_instance.name,
        "tax_rate": tax_rate2,
        "order_count": 1,
        "total_pretax_amount": order3.taxless_total_price_value,
        "total_tax_amount": tax2_rate2_total,
        "total": order3.taxful_total_price_value,
    }, {
        "tax": tax_rate1_instance.name,
        "tax_rate": tax_rate1,
        "order_count": 3,
        "total_pretax_amount": tax1_pretax_total,
        "total_tax_amount": tax1_rate1_total,
        "total": tax1_total,
    }]
    for ix, tax in enumerate(data):
        assert tax["tax"] == expected_result[ix]["tax"]
        assert Decimal(tax["tax_rate"]
                       ) == expected_result[ix]["tax_rate"] * Decimal(100.0)
        assert tax["order_count"] == str(expected_result[ix]["order_count"])
        assert tax["total_tax_amount"] == str(
            expected_result[ix]["total_tax_amount"])
        assert tax["total_pretax_amount"] == str(
            expected_result[ix]["total_pretax_amount"])
        assert tax["total"] == str(expected_result[ix]["total"])
Beispiel #13
0
def test_customer_sales_report(rf, order_by):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product1 = create_product("p1", shop=shop, supplier=supplier)
    product2 = create_product("p2", shop=shop, supplier=supplier)
    product3 = create_product("p3", shop=shop, supplier=supplier)
    tax_rate = Decimal("0.3")

    # orders for person 1
    person1 = create_random_person()
    order1 = create_order_with_product(product=product1,
                                       supplier=supplier,
                                       quantity=2,
                                       taxless_base_unit_price="5",
                                       tax_rate=tax_rate,
                                       n_lines=1,
                                       shop=shop)
    order1.customer = person1
    order1.save()
    order2 = create_order_with_product(product=product2,
                                       supplier=supplier,
                                       quantity=1,
                                       taxless_base_unit_price="10",
                                       n_lines=1,
                                       shop=shop)
    order2.customer = person1
    order2.save()

    person1_taxful_total_sales = (order1.taxful_total_price +
                                  order2.taxful_total_price)
    person1_taxless_total_sales = (order1.taxless_total_price +
                                   order2.taxless_total_price)
    person1_avg_sales = (person1_taxful_total_sales / Decimal(2.0))

    # orders for person 2
    person2 = create_random_person()
    order3 = create_order_with_product(product=product1,
                                       supplier=supplier,
                                       quantity=2,
                                       taxless_base_unit_price="5",
                                       tax_rate=tax_rate,
                                       n_lines=1,
                                       shop=shop)
    order3.customer = person2
    order3.save()

    order4 = create_order_with_product(product=product2,
                                       supplier=supplier,
                                       quantity=2,
                                       taxless_base_unit_price="50",
                                       n_lines=1,
                                       shop=shop)
    order4.customer = person2
    order4.save()

    order5 = create_order_with_product(product=product3,
                                       supplier=supplier,
                                       quantity=2,
                                       taxless_base_unit_price="20",
                                       tax_rate=tax_rate,
                                       n_lines=1,
                                       shop=shop)
    order5.customer = person2
    order5.save()
    person2_taxful_total_sales = (order3.taxful_total_price +
                                  order4.taxful_total_price +
                                  order5.taxful_total_price)
    person2_taxless_total_sales = (order3.taxless_total_price +
                                   order4.taxless_total_price +
                                   order5.taxless_total_price)
    person2_avg_sales = (person2_taxful_total_sales / Decimal(3.0)).quantize(
        Decimal('0.01'))

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

    data = {
        "report": CustomerSalesReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.ALL_TIME,
        "writer": "json",
        "force_download": 1,
        "order_by": order_by
    }
    report = CustomerSalesReport(**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(CustomerSalesReport.title) in json_data.get("heading")
    data = json_data.get("tables")[0].get("data")

    assert len(data) == 2

    if order_by == "order_count":
        person1_data = data[1]
        person2_data = data[0]

    elif order_by == "average_sales":
        if person1_avg_sales > person2_avg_sales:
            person1_data = data[0]
            person2_data = data[1]
        else:
            person1_data = data[1]
            person2_data = data[0]

    elif order_by == "taxless_total":
        if person1_taxless_total_sales > person2_taxless_total_sales:
            person1_data = data[0]
            person2_data = data[1]
        else:
            person1_data = data[1]
            person2_data = data[0]

    elif order_by == "taxful_total":
        if person1_taxful_total_sales > person2_taxful_total_sales:
            person1_data = data[0]
            person2_data = data[1]
        else:
            person1_data = data[1]
            person2_data = data[0]

    assert person1_data["customer"] == person1.name
    assert person1_data["order_count"] == "2"
    assert person1_data["average_sales"] == str(person1_avg_sales.value)
    assert person1_data["taxless_total"] == str(
        person1_taxless_total_sales.value.quantize(Decimal("0.01")))
    assert person1_data["taxful_total"] == str(
        person1_taxful_total_sales.value.quantize(Decimal("0.01")))

    assert person2_data["customer"] == person2.name
    assert person2_data["order_count"] == "3"
    assert person2_data["average_sales"] == str(person2_avg_sales.value)
    assert person2_data["taxless_total"] == str(
        person2_taxless_total_sales.value.quantize(Decimal("0.01")))
    assert person2_data["taxful_total"] == str(
        person2_taxful_total_sales.value.quantize(Decimal("0.01")))
Beispiel #14
0
def test_product_total_sales_report(rf, admin_user, order_by):
    with override_provides("reports", [
            "wshop.default_reports.reports.product_total_sales:ProductSalesReport"
    ]):
        shop = get_default_shop()
        supplier = get_default_supplier()
        product1 = create_product("product1", supplier=supplier, shop=shop)
        product2 = create_product("product2", supplier=supplier, shop=shop)

        p1_qtd, p1_price, p1_tr, p1_lines = Decimal(3), Decimal(5), Decimal(
            0), 5
        p2_qtd, p2_price, p2_tr, p2_lines = Decimal(4), Decimal(5), Decimal(
            0.95), 3

        order = create_order_with_product(product=product1,
                                          supplier=supplier,
                                          quantity=p1_qtd,
                                          taxless_base_unit_price=p1_price,
                                          tax_rate=p1_tr,
                                          n_lines=p1_lines,
                                          shop=shop)
        order.create_payment(order.taxful_total_price.amount)

        order2 = create_order_with_product(product=product2,
                                           supplier=supplier,
                                           quantity=p2_qtd,
                                           taxless_base_unit_price=p2_price,
                                           tax_rate=p2_tr,
                                           n_lines=p2_lines,
                                           shop=shop)
        order2.create_payment(order2.taxful_total_price.amount)

        data = {
            "report": ProductSalesReport.get_name(),
            "shop": shop.pk,
            "date_range": DateRangeChoices.ALL_TIME.value,
            "writer": "json",
            "force_download": 1,
            "order_by": order_by
        }

        view = ReportView.as_view()
        request = apply_request_middleware(rf.post("/", data=data),
                                           user=admin_user)
        response = view(request)
        if hasattr(response, "render"):
            response.render()
        assert response.status_code == 200
        json_data = json.loads(response.content.decode("utf-8"))
        assert force_text(ProductSalesReport.title) in json_data.get("heading")

        data = json_data["tables"][0]["data"]
        assert len(data) == 2

        p1_total_qtd = p1_qtd * p1_lines
        p1_taxless_total = p1_total_qtd * p1_price
        p1_taxful_total = p1_taxless_total * (1 + p1_tr)

        p2_total_qtd = p2_qtd * p2_lines
        p2_taxless_total = p2_total_qtd * p2_price
        p2_taxful_total = p2_taxless_total * (1 + p2_tr)

        if order_by == "quantity":
            p1 = data[0]
            p2 = data[1]

        elif order_by == "taxless_total":
            p1 = data[0]
            p2 = data[1]

        else:  # order_by == "taxful_total":
            p1 = data[1]
            p2 = data[0]

        precision = Decimal('0.1')**2

        assert p1["product"] == product1.name
        assert Decimal(p1["quantity"]) == p1_total_qtd
        assert Decimal(
            p1["taxless_total"]) == p1_taxless_total.quantize(precision)
        assert Decimal(
            p1["taxful_total"]) == p1_taxful_total.quantize(precision)

        assert p2["product"] == product2.name
        assert Decimal(p2["quantity"]) == p2_total_qtd
        assert Decimal(
            p2["taxless_total"]) == p2_taxless_total.quantize(precision)
        assert Decimal(
            p2["taxful_total"]) == p2_taxful_total.quantize(precision)