def test_best_selling_products_with_multiple_orders():
    context = get_jinja_context()
    supplier = get_default_supplier()
    shop = get_default_shop()
    n_products = 2
    price = 10

    product_1 = create_product("test-sku-1", supplier=supplier, shop=shop)
    product_2 = create_product("test-sku-2", supplier=supplier, shop=shop)
    create_order_with_product(product_1, supplier, quantity=1, taxless_base_unit_price=price, shop=shop)
    create_order_with_product(product_2, supplier, quantity=1, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Two initial products sold
    assert product_1 in general.get_best_selling_products(context, n_products=n_products)
    assert product_2 in general.get_best_selling_products(context, n_products=n_products)

    product_3 = create_product("test-sku-3", supplier=supplier, shop=shop)
    create_order_with_product(product_3, supplier, quantity=2, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Third product sold in greater quantity
    assert product_3 in general.get_best_selling_products(context, n_products=n_products)

    create_order_with_product(product_1, supplier, quantity=4, taxless_base_unit_price=price, shop=shop)
    create_order_with_product(product_2, supplier, quantity=4, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Third product outsold by first two products
    assert product_3 not in general.get_best_selling_products(context, n_products=n_products)
예제 #2
0
def test_refunds_for_discounted_order_lines():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    discount_line = OrderLine(
        order_id=order.id, type=OrderLineType.DISCOUNT, quantity=1, discount_amount_value=Decimal("0.54321"))
    discount_line.save()
    order.lines.add(discount_line)

    product_line = order.lines.filter(type=OrderLineType.PRODUCT).first()
    product_line.discount_amount = TaxfulPrice(100, order.currency)
    product_line.save()
    taxful_price_with_discount = product_line.taxful_price
    order.cache_prices()
    order.save()

    assert product_line.base_price == TaxfulPrice(400, order.currency)
    assert taxful_price_with_discount == TaxfulPrice(300, order.currency)

    # try to refund only the product line - should fail since this would result in a negative total
    with pytest.raises(RefundExceedsAmountException):
        order.create_refund([{"line": product_line, "quantity": 2, "amount": taxful_price_with_discount.amount}])

    # try to refund the product line with a negative amount
    with pytest.raises(InvalidRefundAmountException):
        order.create_refund([{"line": product_line, "quantity": 1, "amount": -taxful_price_with_discount.amount}])
    # try to refund the discount line with a positive amount
    with pytest.raises(InvalidRefundAmountException):
        order.create_refund([{"line": discount_line, "quantity": 1, "amount": -discount_line.taxful_price.amount}])

    order.create_refund([
        {"line": discount_line, "quantity": 1, "amount": discount_line.taxful_price.amount},
        {"line": product_line, "quantity": 2, "amount": taxful_price_with_discount.amount}
    ])
    assert product_line.max_refundable_amount.value == 0
    assert discount_line.max_refundable_amount.value == 0
    assert order.taxful_total_price.value == 0

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    discount_line = OrderLine(
        order_id=order.id, type=OrderLineType.DISCOUNT, quantity=1, discount_amount_value=Decimal("0.54321"))
    discount_line.save()
    order.lines.add(discount_line)
    product_line = order.lines.filter(type=OrderLineType.PRODUCT).first()
    product_line.discount_amount = TaxfulPrice(100, order.currency)
    product_line.save()
    order.cache_prices()
    order.save()

    order.create_full_refund(restock_products=False)
    assert order.taxful_total_price.value == 0
예제 #3
0
def test_refunds(browser, admin_user, live_server, settings):
    order = create_order_with_product(
        get_default_product(), get_default_supplier(), 10, decimal.Decimal("10"), n_lines=10,
        shop=get_default_shop())
    order2 = create_order_with_product(
        get_default_product(), get_default_supplier(), 10, decimal.Decimal("10"), n_lines=10,
        shop=get_default_shop())
    order2.create_payment(order2.taxful_total_price)
    initialize_admin_browser_test(browser, live_server, settings)
    _test_toolbar_visibility(browser, live_server, order)
    _test_create_full_refund(browser, live_server, order)
    _test_refund_view(browser, live_server, order2)
def test_get_best_selling_products():
    context = get_jinja_context()
    cache.clear()
    # No products sold
    assert len(list(general.get_best_selling_products(context, n_products=2))) == 0

    supplier = get_default_supplier()
    shop = get_default_shop()
    product = get_default_product()
    create_order_with_product(product, supplier, quantity=1, taxless_base_unit_price=10, shop=shop)
    cache.clear()
    # One product sold
    assert len(list(general.get_best_selling_products(context, n_products=2))) == 1
예제 #5
0
def test_report_writers():
    """
    Just check whether something breaks while writing differnt types of data
    """
    shop = get_default_shop()
    product = get_default_product()
    supplier = get_default_supplier()
    order = create_order_with_product(
        product=product, supplier=supplier, quantity=1, taxless_base_unit_price=10, tax_rate=0, n_lines=2, shop=shop)
    order.create_payment(order.taxful_total_price.amount)

    data = {
        "report": SalesTestReport.get_name(),
        "shop": shop.pk,
        "date_range": DateRangeChoices.THIS_YEAR,
        "writer": "html",
        "force_download": 1,
    }
    report = SalesTestReport(**data)

    for writer_cls in [ExcelReportWriter, PDFReportWriter, PprintReportWriter, HTMLReportWriter, JSONReportWriter]:
        writer = writer_cls()
        report_data = [
            {
                "date": order,
                "order_count": Decimal(2),
                "product_count": int(3),
                "taxless_total": lazy(lambda: order.taxless_total_price_value),
                "taxful_total": order.taxful_total_price,
            }
        ]
        writer.write_data_table(report, report_data)
        assert writer.get_rendered_output()
def _init_test_with_variations():
    shop = get_default_shop()
    supplier = get_default_supplier()

    product_data = {
        "t-shirt": {
            "colors": ["black", "yellow"],
        },
        "hoodie": {
            "colors": ["black"],
        }
    }
    for key, data in six.iteritems(product_data):
        parent = create_product(key, shop=shop)
        shop_parent_product = parent.get_shop_instance(shop)
        for color in data["colors"]:
            sku = "%s-%s" % (key, color)
            shop_product = ShopProduct.objects.filter(product__sku=sku).first()
            if shop_product:
                shop_product.suppliers.add(supplier)
            else:
                child = create_product(sku, shop=shop, supplier=supplier)
                child.link_to_parent(parent, variables={"color": color})

    assert Product.objects.count()  == 5

    black_t_shirt = Product.objects.filter(sku="t-shirt-black").first()
    black_hoodie = Product.objects.filter(sku="hoodie-black").first()
    order = create_order_with_product(black_t_shirt, supplier, quantity=1, taxless_base_unit_price=6, shop=shop)
    add_product_to_order(order, supplier, black_hoodie, quantity=1, taxless_base_unit_price=6)

    return black_t_shirt.variation_parent, black_hoodie.variation_parent
예제 #7
0
def test_refund_without_shipment(restock):
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    # Start out with a supplier with quantity of 10 of a product
    supplier.adjust_stock(product.id, 10)
    check_stock_counts(supplier, product, physical=10, logical=10)

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    check_stock_counts(supplier, product, physical=10, logical=8)

    # Restock value shouldn't matter if we don't have any shipments
    product_line = order.lines.first()
    order.create_refund([
        {"line": product_line, "quantity": 2, "amount": Money(400, order.currency), "restock_products": restock}])

    if restock:
        check_stock_counts(supplier, product, physical=10, logical=10)
    else:
        check_stock_counts(supplier, product, physical=10, logical=8)
    assert product_line.refunded_quantity == 2
    assert order.get_total_tax_amount() == Money(
        order.taxful_total_price_value - order.taxless_total_price_value,
        order.currency)
예제 #8
0
def test_create_refund_view(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku", shop=shop, supplier=supplier, default_price=3.33)
    order = create_order_with_product(product, supplier, quantity=1, taxless_base_unit_price=1, shop=shop)
    order.cache_prices()
    order.save()

    assert not order.has_refunds()
    assert len(order.lines.all()) == 1

    product_line = order.lines.first()

    data = {
        "form-0-line_number": 0,
        "form-0-quantity": 1,
        "form-0-amount": 1,
        "form-0-restock_products": False,
        "form-INITIAL_FORMS": 0,
        "form-MAX_NUM_FORMS": 1000,
        "form-TOTAL_FORMS": 1,
        "form-MIN_NUM_FORMS": 0,
    }

    request = apply_request_middleware(rf.post("/", data=data), user=admin_user)
    view = OrderCreateRefundView.as_view()
    response = view(request, pk=order.pk)
    assert response.status_code == 302
    assert order.has_refunds()

    assert len(order.lines.all()) == 2
    refund_line = order.lines.filter(type=OrderLineType.REFUND).last()
    assert refund_line
    assert refund_line.taxful_price == -product_line.taxful_price
예제 #9
0
def test_copy_order_to_basket(admin_user, settings):
    configure(settings)
    shop = factories.get_default_shop()
    basket = factories.get_basket()
    p1 = factories.create_product("test", shop=shop, supplier=factories.get_default_supplier())
    order = factories.create_order_with_product(factories.get_default_product(), factories.get_default_supplier(), 2, 10, shop=shop)
    factories.add_product_to_order(order, factories.get_default_supplier(), p1, 2, 5)
    order.customer = get_person_contact(admin_user)
    order.save()
    client = _get_client(admin_user)
    payload = {
        "order": order.pk
    }
    response = client.post('/api/shuup/basket/{}-{}/add_from_order/'.format(shop.pk, basket.key), payload)
    assert response.status_code == status.HTTP_200_OK
    response_data = json.loads(response.content.decode("utf-8"))
    assert len(response_data["items"]) == 2
    assert not response_data["validation_errors"]
    basket.refresh_from_db()
    assert len(basket.data["lines"]) == 2

    # do it again, basket should clear first then read items
    payload = {
        "order": order.pk
    }
    response = client.post('/api/shuup/basket/{}-{}/add_from_order/'.format(shop.pk, basket.key), payload)
    assert response.status_code == status.HTTP_200_OK
    response_data = json.loads(response.content.decode("utf-8"))
    assert len(response_data["items"]) == 2
    assert not response_data["validation_errors"]
    basket.refresh_from_db()
    assert len(basket.data["lines"]) == 2
예제 #10
0
def test_printouts_no_addresses(rf):
    try:
        import weasyprint
    except ImportError:
        pytest.skip()

    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product("simple-test-product", shop)
    order = create_order_with_product(product, supplier, 6, 6, shop=shop)

    order.billing_address = None
    order.save()
    shipment = order.create_shipment_of_all_products(supplier)
    request = rf.get("/")
    response = get_delivery_pdf(request, shipment.id)
    assert response.status_code == 200
    response = get_confirmation_pdf(request, order.id)
    assert response.status_code == 200

    order.shipping_address = None
    order.save()
    response = get_delivery_pdf(request, shipment.id)
    assert response.status_code == 200
    response = get_confirmation_pdf(request, order.id)
    assert response.status_code == 200
예제 #11
0
def test_extending_shipment_form_valid_hook(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku", shop=shop, supplier=supplier, default_price=3.33)
    quantity = 1
    order = create_order_with_product(
        product, supplier, quantity=quantity, taxless_base_unit_price=1, shop=shop)

    extend_form_class = "shuup_tests.admin.test_shipment_creator.ShipmentFormModifierTest"
    with override_provides(ShipmentForm.form_modifier_provide_key, [extend_form_class]):
        phone_number = "+358911"
        data = {
            "q_%s" % product.pk: 1,
            "supplier": supplier.pk,
            "phone": phone_number
        }
        request = apply_request_middleware(rf.post("/", data=data), user=admin_user)
        view = OrderCreateShipmentView.as_view()
        response = view(request, pk=order.pk)
        assert response.status_code == 302

        # Order should now have shipment, but let's re fetch it first
        order = Order.objects.get(pk=order.pk)
        assert order.shipments.count() == 1

        shipment = order.shipments.first()
        assert order.shipping_data.get(shipment.identifier).get("phone") == phone_number
        assert shipment.supplier_id == supplier.id
        assert shipment.products.count() == 1
        assert shipment.products.first().product_id == product.id
예제 #12
0
def initialize_report_test(product_price, product_count, tax_rate, line_count):
    shop = get_default_shop()
    product = get_default_product()
    supplier = get_default_supplier()
    expected_taxless_total = product_count * product_price
    expected_taxful_total = product_count * product_price * (1 + tax_rate)
    order = create_order_with_product(
        product=product, supplier=supplier, quantity=product_count,
        taxless_base_unit_price=product_price, tax_rate=tax_rate, n_lines=line_count, shop=shop)
    order.create_payment(order.taxful_total_price.amount)
    order2 = create_order_with_product(
        product=product, supplier=supplier, quantity=product_count,
        taxless_base_unit_price=product_price, tax_rate=tax_rate, n_lines=line_count, shop=shop)
    order2.create_payment(order2.taxful_total_price.amount)
    order2.set_canceled()  # Shouldn't affect reports
    return expected_taxful_total, expected_taxless_total, shop, order
예제 #13
0
def test_custom_payment_processor_cash_service(choice_identifier, expected_payment_status):
    shop = get_default_shop()
    product = get_default_product()
    supplier = get_default_supplier()
    processor = CustomPaymentProcessor.objects.create()
    payment_method = PaymentMethod.objects.create(
        shop=shop,
        payment_processor=processor,
        choice_identifier=choice_identifier,
        tax_class=get_default_tax_class())

    order = create_order_with_product(
        product=product,
        supplier=supplier,
        quantity=1,
        taxless_base_unit_price=Decimal('5.55'),
        shop=shop)
    order.taxful_total_price = TaxfulPrice(Decimal('5.55'), u'EUR')
    order.payment_method = payment_method
    order.save()

    assert order.payment_status == PaymentStatus.NOT_PAID
    processor.process_payment_return_request(choice_identifier, order, None)
    assert order.payment_status == expected_payment_status
    processor.process_payment_return_request(choice_identifier, order, None)
    assert order.payment_status == expected_payment_status
예제 #14
0
def test_refund_entire_order_without_restock(admin_user):
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    supplier.adjust_stock(product.id, 5)
    _check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product, supplier, 2, 200, Decimal("0.24"), shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    original_total_price = order.taxful_total_price
    _check_stock_counts(supplier, product, 5, 3)

    client = _get_client(admin_user)
    refund_url = "/api/shuup/order/%s/create_full_refund/" % order.id
    data = {"restock_products": False}
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()

    # Confirm the refund was created with correct amount
    assert order.taxless_total_price.amount.value == 0
    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.order_by("ordering").last()
    assert refund_line.type == OrderLineType.REFUND
    assert refund_line.taxful_price == -original_total_price

    # Make sure logical count reflects refunded products
    _check_stock_counts(supplier, product, 5, 3)
예제 #15
0
def test_simple_supplier(rf):
    supplier = get_simple_supplier()
    shop = get_default_shop()
    product = create_product("simple-test-product", shop)
    ss = supplier.get_stock_status(product.pk)
    assert ss.product == product
    assert ss.logical_count == 0
    num = random.randint(100, 500)
    supplier.adjust_stock(product.pk, +num)
    assert supplier.get_stock_status(product.pk).logical_count == num
    # Create order ...
    order = create_order_with_product(product, supplier, 10, 3, shop=shop)
    quantities = order.get_product_ids_and_quantities()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == num
    # Create shipment ...
    shipment = order.create_shipment_of_all_products(supplier)
    pss = supplier.get_stock_status(product.pk)
    assert pss.physical_count == (num - quantities[product.pk])
    # Cancel order...
    order.set_canceled()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num)
    # physical stock still the same until shipment exists
    assert pss.physical_count == (num - quantities[product.pk])

    shipment.soft_delete()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == num
    assert pss.physical_count == num
def test_simple_supplier(rf):
    supplier = get_simple_supplier()
    shop = get_default_shop()
    product = create_product("simple-test-product", shop)
    ss = supplier.get_stock_status(product.pk)
    assert ss.product == product
    assert ss.logical_count == 0
    num = random.randint(100, 500)
    supplier.adjust_stock(product.pk, +num)
    assert supplier.get_stock_status(product.pk).logical_count == num

    # Create order
    order = create_order_with_product(product, supplier, 10, 3, shop=shop)
    quantities = order.get_product_ids_and_quantities()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == num
    # Create shipment

    shipment = order.create_shipment_of_all_products(supplier)
    assert isinstance(shipment, Shipment)
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == (num - quantities[product.pk])

    # Delete shipment
    with pytest.raises(NotImplementedError):
        shipment.delete()
    shipment.soft_delete()
    assert shipment.is_deleted()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == (num)
예제 #17
0
def test_refunds_with_quantities():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )

    order = create_order_with_product(product, supplier, 3, 200, shop=shop)
    order.cache_prices()
    assert not order.lines.refunds()

    product_line = order.lines.first()
    refund_amount = Money(100, order.currency)
    order.create_refund([{"line": product_line, "quantity": 2, "amount": refund_amount}])
    assert len(order.lines.refunds()) == 2

    quantity_line = order.lines.refunds().filter(quantity=2).first()
    assert quantity_line
    amount_line = order.lines.refunds().filter(quantity=1).first()
    assert amount_line

    assert quantity_line.taxful_base_unit_price == -product_line.taxful_base_unit_price
    assert amount_line.taxful_price.amount == -refund_amount
예제 #18
0
def test_refund_entire_order():
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )
    supplier.adjust_stock(product.id, 5)
    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 5

    order = create_order_with_product(product, supplier, 2, 200, Decimal("0.1"), shop=shop)
    order.cache_prices()
    original_total_price = order.taxful_total_price
    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 3

    # Create a full refund with `restock_products` set to False
    order.create_full_refund(restock_products=False)

    # Confirm the refund was created with correct amount
    assert order.taxless_total_price.amount.value == 0
    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.order_by("ordering").last()
    assert refund_line.type == OrderLineType.REFUND
    assert refund_line.taxful_price == -original_total_price

    # Make sure stock status didn't change
    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 3
예제 #19
0
def test_tracking_codes():
    product = get_default_product()
    supplier = get_default_supplier()
    order = create_order_with_product(
        product,
        supplier=supplier,
        quantity=1,
        taxless_base_unit_price=10,
        tax_rate=decimal.Decimal("0.5")
    )
    _add_product_to_order(order, "duck-tape-1", 3, order.shop, supplier)
    _add_product_to_order(order, "water-1", 2, order.shop, supplier)

    order.cache_prices()
    order.check_all_verified()
    order.save()

    # Create shipment with tracking code for every product line.
    product_lines = order.lines.exclude(product_id=None)
    assert len(product_lines) == 3
    for line in product_lines:
        shipment = order.create_shipment({line.product: line.quantity}, supplier=supplier)
        if line.quantity != 3:
            shipment.tracking_code = "123FI"
            shipment.save()

    tracking_codes = order.get_tracking_codes()
    code_count = (len(product_lines)-1)  # We skipped that one
    assert len(tracking_codes) == code_count
    assert len([tracking_code for tracking_code in tracking_codes if tracking_code == "123FI"]) == code_count
예제 #20
0
def test_refund_entire_order():
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    supplier.adjust_stock(product.id, 5)
    check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product, supplier, 2, 200, Decimal("0.24"), shop=shop)
    order.cache_prices()

    original_total_price = order.taxful_total_price
    check_stock_counts(supplier, product, 5, 3)

    # Create a full refund with `restock_products` set to False
    order.create_full_refund(restock_products=False)

    # Confirm the refund was created with correct amount
    assert order.taxless_total_price.amount.value == 0
    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.order_by("ordering").last()
    assert refund_line.type == OrderLineType.REFUND
    assert refund_line.taxful_price == -original_total_price

    # Make sure logical count reflects refunded products
    check_stock_counts(supplier, product, 5, 3)
예제 #21
0
def test_refund_entire_order_with_restock(admin_user):
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    supplier.adjust_stock(product.id, 5)
    _check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    _check_stock_counts(supplier, product, 5, 3)
    assert not StockAdjustment.objects.filter(created_by=admin_user).exists()

    client = _get_client(admin_user)
    refund_url = "/api/shuup/order/%s/create_full_refund/" % order.id
    data = {"restock_products": True}
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()

    # restock logical count
    _check_stock_counts(supplier, product, 5, 5)
    assert StockAdjustment.objects.filter(created_by=admin_user).exists()
예제 #22
0
def test_create_full_refund_view(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku", shop=shop, supplier=supplier, default_price=3.33)
    order = create_order_with_product(product, supplier, quantity=1, taxless_base_unit_price=1, shop=shop)
    order.cache_prices()

    original_total_price = order.taxful_total_price

    assert not order.has_refunds()
    assert len(order.lines.all()) == 1
    assert order.taxful_total_price.amount.value != 0

    data = {
        "restock_products": "on",
    }

    request = apply_request_middleware(rf.post("/", data=data), user=admin_user)
    view = OrderCreateFullRefundView.as_view()
    response = view(request, pk=order.pk)
    assert response.status_code == 302
    assert order.has_refunds()
    order.cache_prices()

    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.filter(type=OrderLineType.REFUND).last()
    assert refund_line
    assert refund_line.taxful_price == -original_total_price
예제 #23
0
def test_refund_with_product_restock():
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )
    supplier.adjust_stock(product.id, 5)
    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 5

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()

    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 3

    # Create a refund with a parent line and quanity with `restock_products` set to False
    product_line = order.lines.first()
    order.create_refund([{"line": product_line, "quantity": 1, "restock_products": False}])

    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 3
    assert order.lines.last().taxful_price == -product_line.base_unit_price
    assert order.get_total_unrefunded_amount() == product_line.base_unit_price.amount

    # Create a refund with a parent line and quanity with `restock_products` set to True
    product_line = order.lines.first()
    order.create_refund([{"line": product_line, "quantity": 1, "restock_products": True}])

    assert supplier.get_stock_statuses([product.id])[product.id].logical_count == 4
    assert not order.taxful_total_price
예제 #24
0
def create_fully_paid_order(shop, customer, supplier, product_sku, price_value):
    product = create_product(product_sku, shop=shop, supplier=supplier, default_price=price_value)
    order = create_order_with_product(
        product=product, supplier=supplier, quantity=1, taxless_base_unit_price=price_value, shop=get_default_shop())
    order.customer = customer
    order.save()
    order.cache_prices()
    return order.create_payment(order.taxful_total_price)
예제 #25
0
def _create_order(shop, customer):
    p1 = factories.create_product("test", shop=shop, supplier=factories.get_default_supplier())
    order = factories.create_order_with_product(factories.get_default_product(), factories.get_default_supplier(), 2,
                                                10, shop=shop)
    factories.add_product_to_order(order, factories.get_default_supplier(), p1, 2, 5)
    order.customer = customer
    order.save()
    return order
예제 #26
0
def _create_total_paid_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()
    order.create_payment(order.taxful_total_price)
    assert order.is_paid()
예제 #27
0
def test_can_create_payment():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )

    order = create_order_with_product(product, supplier, 1, 200, shop=shop)
    assert order.can_create_payment()
    order.cache_prices()

    # Partially paid orders can create payments
    payment_amount = (order.taxful_total_price.amount / 2)
    order.create_payment(payment_amount)
    assert order.can_create_payment()

    # But fully paid orders can't
    remaining_amount = order.taxful_total_price.amount - payment_amount
    order.create_payment(remaining_amount)
    assert not order.can_create_payment()

    order = create_order_with_product(product, supplier, 1, 200, shop=shop)
    order.cache_prices()
    assert order.can_create_payment()

    # Canceled orders can't create payments
    order.set_canceled()
    assert not order.can_create_payment()

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    assert order.can_create_payment()

    # Partially refunded orders can create payments
    order.create_refund([
        {"line": order.lines.first(), "quantity": 1, "amount": Money(200, order.currency), "restock": False}])
    assert order.can_create_payment()

    # But fully refunded orders can't
    order.create_refund([
        {"line": order.lines.first(), "quantity": 1, "amount": Money(200, order.currency), "restock": False}])
    assert not order.can_create_payment()
예제 #28
0
def test_refunds():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    assert order.get_total_refunded_amount().value == 0
    assert order.get_total_unrefunded_amount().value == order.taxful_total_price.value
    assert not order.can_edit()

    assert len(order.lines.all()) == 1

    product_line = order.lines.first()
    assert product_line.ordering == 0
    assert order.can_create_refund()
    assert not order.has_refunds()

    # Create a refund with a parent line and quantity
    order.create_refund([{"line": product_line, "quantity": 1}])
    assert len(order.lines.all()) == 2
    assert order.lines.last().ordering == 1
    assert order.has_refunds()

    # Confirm the value of the refund
    assert order.lines.last().taxful_price == -product_line.base_unit_price

    partial_refund_amount = order.taxful_total_price.amount / 2
    remaining_amount = order.taxful_total_price.amount - partial_refund_amount

    # Create a refund with a parent line and amount
    order.create_refund([{"line": product_line, "amount": partial_refund_amount}])
    assert len(order.lines.all()) == 3
    assert order.lines.last().ordering == 2

    assert order.lines.last().taxful_price.amount == -partial_refund_amount
    assert order.taxful_total_price.amount == remaining_amount
    assert order.can_create_refund()

    # Create a refund without parent line and remaining amount in order
    order.create_refund([{"amount": remaining_amount}])
    assert len(order.lines.all()) == 4
    assert order.lines.last().ordering == 3
    assert order.lines.last().taxful_price.amount == -remaining_amount

    assert not order.taxful_total_price.amount
    assert not order.can_create_refund()

    with pytest.raises(RefundExceedsAmountException):
        order.create_refund([{"amount": remaining_amount}])
예제 #29
0
def initialize_report_test(product_price, product_count, tax_rate, line_count):
    shop = get_default_shop()
    product = get_default_product()
    supplier = get_default_supplier()
    expected_taxless_total = product_count * product_price
    expected_taxful_total = product_count * product_price * (1 + tax_rate)
    order = create_order_with_product(
        product=product, supplier=supplier, quantity=product_count,
        taxless_base_unit_price=product_price, tax_rate=tax_rate, n_lines=line_count, shop=shop)
    return expected_taxful_total, expected_taxless_total, shop, order
예제 #30
0
def test_edit_view_with_anonymous_contact(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku=printable_gibberish(), supplier=supplier, shop=shop)
    order = create_order_with_product(product, supplier, 1, 10, shop=shop)
    order.save()
    assert not order.customer
    request = apply_request_middleware(rf.get("/", user=admin_user))
    response = OrderEditView.as_view()(request=request, pk=order.pk)
    assert response.status_code == 200
예제 #31
0
def test_refund_entire_order_with_product_restock():
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )
    supplier.adjust_stock(product.id, 5)
    check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()

    check_stock_counts(supplier, product, 5, 3)

    # Create a full refund with `restock_products` set to True
    order.create_full_refund(restock_products=True)

    # restock logical count
    check_stock_counts(supplier, product, 5, 5)
예제 #32
0
def test_extending_shipment_form_valid_hook(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku",
                             shop=shop,
                             supplier=supplier,
                             default_price=3.33)
    quantity = 1
    order = create_order_with_product(product,
                                      supplier,
                                      quantity=quantity,
                                      taxless_base_unit_price=1,
                                      shop=shop)

    extend_form_class = "shuup_tests.admin.test_shipment_creator.ShipmentFormModifierTest"
    with override_provides(ShipmentForm.form_modifier_provide_key,
                           [extend_form_class]):
        phone_number = "+358911"
        data = {
            "q_%s" % product.pk: 1,
            "supplier": supplier.pk,
            "phone": phone_number
        }
        request = apply_request_middleware(rf.post("/", data=data),
                                           user=admin_user)
        view = OrderCreateShipmentView.as_view()
        response = view(request, pk=order.pk)
        assert response.status_code == 302

        # Order should now have shipment, but let's re fetch it first
        order = Order.objects.get(pk=order.pk)
        assert order.shipments.count() == 1

        shipment = order.shipments.first()
        assert order.shipping_data.get(
            shipment.identifier).get("phone") == phone_number
        assert shipment.supplier_id == supplier.id
        assert shipment.products.count() == 1
        assert shipment.products.first().product_id == product.id
예제 #33
0
def test_shipment_creating_with_no_shipping_address(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku",
                             shop=shop,
                             supplier=supplier,
                             default_price=3.33)
    order = create_order_with_product(product,
                                      supplier,
                                      quantity=1,
                                      taxless_base_unit_price=1,
                                      shop=shop)

    # remove shipping address
    order.shipping_address = None
    order.save()

    with pytest.raises(NoShippingAddressException):
        order.create_shipment_of_all_products()

    # order should not have any shipments since it should have thrown an exception
    assert order.shipments.count() == 0
예제 #34
0
def test_refund_entire_order_without_restock(admin_user):
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product("test-sku",
                             shop=get_default_shop(),
                             default_price=10,
                             stock_behavior=StockBehavior.STOCKED)
    supplier.adjust_stock(product.id, 5)
    _check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product,
                                      supplier,
                                      2,
                                      200,
                                      Decimal("0.24"),
                                      shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    original_total_price = order.taxful_total_price
    _check_stock_counts(supplier, product, 5, 3)

    client = _get_client(admin_user)
    refund_url = "/api/shuup/order/%s/create_full_refund/" % order.id
    data = {"restock_products": False}
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()

    # Confirm the refund was created with correct amount
    assert order.taxless_total_price.amount.value == 0
    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.order_by("ordering").last()
    assert refund_line.type == OrderLineType.REFUND
    assert refund_line.taxful_price == -original_total_price

    # Make sure logical count reflects refunded products
    _check_stock_counts(supplier, product, 5, 3)
예제 #35
0
def test_computing_simple_product_relations(rf):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product("simple-test-product", shop)
    related_product = create_product("simple-related-product", shop)
    quantities = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    for quantity in quantities:
        order = create_order_with_product(product, supplier, quantity=1, taxless_base_unit_price=6, shop=shop)
        add_product_to_order(order, supplier, related_product, quantity=quantity, taxless_base_unit_price=6)

    assert ProductCrossSell.objects.count() == 0
    add_bought_with_relations_for_product(product.pk)
    assert ProductCrossSell.objects.count() == 1
    cross_sell_product = ProductCrossSell.objects.filter(product1=product).first()
    assert cross_sell_product.product2 == related_product
    assert cross_sell_product.weight == sum(quantities)

    add_bought_with_relations_for_product(related_product.id)
    assert ProductCrossSell.objects.count() == 2
    cross_sell_product = ProductCrossSell.objects.filter(product1=related_product).first()
    assert cross_sell_product.product2 == product
    assert cross_sell_product.weight == len(quantities)
예제 #36
0
def test_payments():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product("test-sku", shop=get_default_shop(), default_price=10)
    order = create_order_with_product(product, supplier, 1, 200, shop=shop)
    order.cache_prices()

    assert order.get_total_paid_amount().value == 0
    assert order.get_total_unpaid_amount().value == order.taxful_total_price.value

    assert order.payment_status == PaymentStatus.NOT_PAID
    assert order.can_edit()

    partial_payment_amount = order.taxful_total_price / 2
    remaining_amount = order.taxful_total_price - partial_payment_amount
    order.create_payment(partial_payment_amount)
    assert order.payment_status == PaymentStatus.PARTIALLY_PAID
    assert not order.can_edit()

    order.create_payment(remaining_amount)
    assert order.payment_status == PaymentStatus.FULLY_PAID
    assert not order.can_edit()
예제 #37
0
def test_shipment_creating_view_get(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku",
                             shop=shop,
                             supplier=supplier,
                             default_price=3.33)
    quantity = 1
    order = create_order_with_product(product,
                                      supplier,
                                      quantity=quantity,
                                      taxless_base_unit_price=1,
                                      shop=shop)

    request = apply_request_middleware(rf.get("/"), user=admin_user)
    view = OrderCreateShipmentView.as_view()
    response = view(request, pk=order.pk, supplier_pk=supplier.pk).render()
    assert response.status_code == 200

    # Should contain supplier input and input for product
    soup = BeautifulSoup(response.content)
    assert soup.find("input", {"id": "id_q_%s" % product.pk})
예제 #38
0
def create_random_review_for_product(shop,
                                     product,
                                     reviewer=None,
                                     order=None,
                                     approved=True,
                                     rating=None,
                                     would_recommend=None,
                                     generate_comment=True):
    if reviewer is None:
        reviewer = factories.create_random_person("en")

    if order is None:
        order = factories.create_order_with_product(
            product=product,
            supplier=factories.get_default_supplier(),
            quantity=1,
            taxless_base_unit_price=10,
            shop=shop)

    if rating is None:
        rating = random.randint(1, 5)

    if would_recommend is None:
        would_recommend = random.choice([True, False])

    comment = None
    if generate_comment:
        comment = Faker().text(100)

    return ProductReview.objects.create(
        shop=shop,
        product=product,
        reviewer=reviewer,
        order=order,
        rating=rating,
        comment=comment,
        would_recommend=would_recommend,
        status=(ReviewStatus.APPROVED if approved else ReviewStatus.PENDING))
예제 #39
0
def test_create_full_refund_view(rf, admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(sku="test-sku",
                             shop=shop,
                             supplier=supplier,
                             default_price=3.33)
    order = create_order_with_product(product,
                                      supplier,
                                      quantity=1,
                                      taxless_base_unit_price=1,
                                      shop=shop)
    order.cache_prices()

    original_total_price = order.taxful_total_price

    assert not order.has_refunds()
    assert len(order.lines.all()) == 1
    assert order.taxful_total_price.amount.value != 0

    product_line = order.lines.first()

    data = {
        "restock_products": "on",
    }

    request = apply_request_middleware(rf.post("/", data=data),
                                       user=admin_user)
    view = OrderCreateFullRefundView.as_view()
    response = view(request, pk=order.pk)
    assert response.status_code == 302
    assert order.has_refunds()
    order.cache_prices()

    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.filter(type=OrderLineType.REFUND).last()
    assert refund_line
    assert refund_line.taxful_price == -original_total_price
예제 #40
0
def test_product_relations_max_quantity(rf):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product("simple-test-product", shop)
    quantities = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    for i, quantity in enumerate(quantities):
        order = create_order_with_product(product,
                                          supplier,
                                          quantity=1,
                                          taxless_base_unit_price=6,
                                          shop=shop)
        add_product_to_order(order,
                             supplier,
                             create_product("product-%s" % i, shop),
                             quantity=quantity,
                             taxless_base_unit_price=6)

    assert ProductCrossSell.objects.count() == 0
    add_bought_with_relations_for_product(product.pk, max_quantity=5)
    assert ProductCrossSell.objects.count() == 5
    # Test that ordering is ok
    assert not ProductCrossSell.objects.filter(weight=1).exists()
    assert ProductCrossSell.objects.filter(weight=11).exists()
예제 #41
0
def test_max_refundable_amount():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    assert len(order.lines.all()) == 1

    line = order.lines.first()
    assert line.max_refundable_amount == line.taxful_price.amount

    partial_refund_amount = Money(10, order.currency)
    assert partial_refund_amount.value > 0

    order.create_refund([{"line": line, "quantity": 1, "amount": partial_refund_amount}])
    assert line.max_refundable_amount == line.taxful_price.amount - partial_refund_amount
    assert order.get_total_tax_amount() == Money(
        order.taxful_total_price_value - order.taxless_total_price_value,
        order.currency)
예제 #42
0
def test_can_create_refund():
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
        stock_behavior=StockBehavior.STOCKED
    )

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    assert order.can_create_payment()

    # Partially refunded orders can create refunds
    order.create_refund([
        {"line": order.lines.first(), "quantity": 1, "amount": Money(200, order.currency), "restock": False}])
    assert order.can_create_refund()

    # But fully refunded orders can't
    order.create_refund([
        {"line": order.lines.first(), "quantity": 1, "amount": Money(200, order.currency), "restock": False}])
    assert not order.can_create_refund()
예제 #43
0
def test_refund_entire_order_with_product_restock():
    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()
    product = create_product("test-sku",
                             shop=get_default_shop(),
                             default_price=10,
                             stock_behavior=StockBehavior.STOCKED)
    supplier.adjust_stock(product.id, 5)
    check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()

    check_stock_counts(supplier, product, 5, 3)

    # Create a full refund with `restock_products` set to True
    order.create_full_refund(restock_products=True)

    # restock logical count
    check_stock_counts(supplier, product, 5, 5)
def test_simple_supplier_out_of_stock(rf, anonymous):
    supplier = get_simple_supplier()
    shop = get_default_shop()
    product = create_product("simple-test-product", shop, supplier, stock_behavior=StockBehavior.STOCKED)

    if anonymous:
        customer = AnonymousContact()
    else:
        customer = create_random_person()

    ss = supplier.get_stock_status(product.pk)
    assert ss.product == product
    assert ss.logical_count == 0
    num = random.randint(100, 500)
    supplier.adjust_stock(product.pk, +num)
    assert supplier.get_stock_status(product.pk).logical_count == num

    shop_product = product.get_shop_instance(shop)
    assert shop_product.is_orderable(supplier, customer, 1)

    # Create order
    order = create_order_with_product(product, supplier, num, 3, shop=shop)
    order.get_product_ids_and_quantities()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == 0
    assert pss.physical_count == num

    assert not shop_product.is_orderable(supplier, customer, 1)

    # Create shipment
    shipment = order.create_shipment_of_all_products(supplier)
    assert isinstance(shipment, Shipment)
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == 0
    assert pss.physical_count == 0

    assert not shop_product.is_orderable(supplier, customer, 1)
예제 #45
0
def test_get_best_selling_products_cache_bump():
    supplier = get_default_supplier()
    shop = get_default_shop()
    shop2 = get_shop(identifier="shop2")
    product1 = create_product("product1", shop, supplier, 10)
    product2 = create_product("product2", shop, supplier, 20)
    product3 = create_product("product3", shop2, supplier, 20)
    shop1_product1 = product1.get_shop_instance(shop)
    shop2_product3 = product3.get_shop_instance(shop2)

    create_order_with_product(product1, supplier, quantity=1, taxless_base_unit_price=10, shop=shop)
    create_order_with_product(product2, supplier, quantity=2, taxless_base_unit_price=20, shop=shop)
    create_order_with_product(product3, supplier, quantity=2, taxless_base_unit_price=30, shop=shop2)

    cache.clear()
    from shuup.front.template_helpers import general
    context = get_jinja_context()

    set_cached_value_mock = mock.Mock(wraps=context_cache.set_cached_value)
    def set_cache_value(key, value, timeout=None):
        if "best_selling_products" in key:
            return set_cached_value_mock(key, value, timeout)

    with mock.patch.object(context_cache, "set_cached_value", new=set_cache_value):
        assert set_cached_value_mock.call_count == 0

        assert general.get_best_selling_products(context, 2, orderable_only=False)
        assert set_cached_value_mock.call_count == 1

        # call again, the cache should be returned instead and the set_cached_value shouldn't be called again
        assert general.get_best_selling_products(context, 2, orderable_only=False)
        assert set_cached_value_mock.call_count == 1

        # save the shop2 product and see whether the cache is bumped
        shop2_product3.save()

        # neve SHOULD be changed and things should be cached
        assert general.get_best_selling_products(context, 2, orderable_only=False)
        assert set_cached_value_mock.call_count == 1

        # now change shop1 product, it should bump the cache
        shop1_product1.save()
        assert general.get_best_selling_products(context, 2, orderable_only=False)
        assert set_cached_value_mock.call_count == 2
예제 #46
0
def test_simple_supplier(rf):
    supplier = get_simple_supplier()
    shop = get_default_shop()
    product = create_product("simple-test-product", shop)
    ss = supplier.get_stock_status(product.pk)
    assert ss.product == product
    assert ss.logical_count == 0
    num = random.randint(100, 500)
    supplier.adjust_stock(product.pk, +num)
    assert supplier.get_stock_status(product.pk).logical_count == num
    # Create order ...
    order = create_order_with_product(product, supplier, 10, 3, shop=shop)
    quantities = order.get_product_ids_and_quantities()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == num
    # Create shipment ...
    order.create_shipment_of_all_products(supplier)
    pss = supplier.get_stock_status(product.pk)
    assert pss.physical_count == (num - quantities[product.pk])
    # Cancel order...
    order.set_canceled()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num)
예제 #47
0
def test_refund_entire_order():
    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()
    product = create_product("test-sku",
                             shop=get_default_shop(),
                             default_price=10,
                             stock_behavior=StockBehavior.STOCKED)
    supplier.adjust_stock(product.id, 5)
    check_stock_counts(supplier, product, 5, 5)

    order = create_order_with_product(product,
                                      supplier,
                                      2,
                                      200,
                                      Decimal("0.24"),
                                      shop=shop)
    order.cache_prices()

    original_total_price = order.taxful_total_price
    check_stock_counts(supplier, product, 5, 3)

    # Create a full refund with `restock_products` set to False
    order.create_full_refund(restock_products=False)

    # Confirm the refund was created with correct amount
    assert order.taxless_total_price.amount.value == 0
    assert order.taxful_total_price.amount.value == 0
    refund_line = order.lines.order_by("ordering").last()
    assert refund_line.type == OrderLineType.REFUND
    assert refund_line.taxful_price == -original_total_price

    # Make sure logical count reflects refunded products
    check_stock_counts(supplier, product, 5, 3)
def test_simple_supplier(rf):
    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
    supplier = get_simple_supplier()
    shop = get_default_shop()
    product = create_product("simple-test-product", shop)
    ss = supplier.get_stock_status(product.pk)
    assert ss.product == product
    assert ss.logical_count == 0
    num = random.randint(100, 500)
    supplier.adjust_stock(product.pk, +num)
    assert supplier.get_stock_status(product.pk).logical_count == num

    # Create order
    order = create_order_with_product(product, supplier, 10, 3, shop=shop)
    quantities = order.get_product_ids_and_quantities()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == num
    # Create shipment

    shipment = order.create_shipment_of_all_products(supplier)
    assert isinstance(shipment, Shipment)
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == (num - quantities[product.pk])

    # Delete shipment
    with pytest.raises(NotImplementedError):
        shipment.delete()
    shipment.soft_delete()
    assert shipment.is_deleted()
    pss = supplier.get_stock_status(product.pk)
    assert pss.logical_count == (num - quantities[product.pk])
    assert pss.physical_count == (num)
예제 #49
0
def test_adding_extra_fields_to_the_delivery(rf):
    try:
        import weasyprint
    except ImportError:
        pytest.skip()

    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product("simple-test-product", shop)
    order = create_order_with_product(product, supplier, 6, 6, shop=shop)
    shipment = order.create_shipment_of_all_products(supplier)
    request = apply_request_middleware(rf.get("/"),
                                       user=get_default_staff_user())

    with override_provides(
            "order_printouts_delivery_extra_fields",
        [
            "shuup_tests.order_printouts.test_printouts:PrintoutTestDeliveryExtraFields",
        ],
    ):
        response = get_delivery_html(request, shipment.id)
        assert response.status_code == 200
        assert "123456789" in response.content.decode()
        assert "Random" in response.content.decode()
예제 #50
0
def test_best_selling_products_with_multiple_orders():
    from shuup.front.template_helpers import general

    context = get_jinja_context()
    supplier = get_default_supplier()
    shop = get_default_shop()
    n_products = 2
    price = 10

    product_1 = create_product("test-sku-1",
                               supplier=supplier,
                               shop=shop,
                               default_price=price)
    product_2 = create_product("test-sku-2",
                               supplier=supplier,
                               shop=shop,
                               default_price=price)
    create_order_with_product(product_1,
                              supplier,
                              quantity=1,
                              taxless_base_unit_price=price,
                              shop=shop)
    create_order_with_product(product_2,
                              supplier,
                              quantity=1,
                              taxless_base_unit_price=price,
                              shop=shop)

    # Two initial products sold
    for cache_test in range(2):
        assert product_1 in general.get_best_selling_products(
            context, n_products=n_products)
        assert product_2 in general.get_best_selling_products(
            context, n_products=n_products)

    product_3 = create_product("test-sku-3",
                               supplier=supplier,
                               shop=shop,
                               default_price=price)
    create_order_with_product(product_3,
                              supplier,
                              quantity=2,
                              taxless_base_unit_price=price,
                              shop=shop)

    # Third product sold in greater quantity
    cache.clear()
    assert product_3 in general.get_best_selling_products(
        context, n_products=n_products)

    create_order_with_product(product_1,
                              supplier,
                              quantity=4,
                              taxless_base_unit_price=price,
                              shop=shop)
    create_order_with_product(product_2,
                              supplier,
                              quantity=4,
                              taxless_base_unit_price=price,
                              shop=shop)

    cache.clear()
    # Third product outsold by first two products
    for cache_test in range(2):
        assert product_3 not in general.get_best_selling_products(
            context, n_products=n_products)

    children = [
        create_product("SimpleVarChild-%d" % x, supplier=supplier, shop=shop)
        for x in range(5)
    ]
    for child in children:
        child.link_to_parent(product_3)
        create_order_with_product(child,
                                  supplier,
                                  quantity=1,
                                  taxless_base_unit_price=price,
                                  shop=shop)

    cache.clear()
    # Third product now sold in greatest quantity
    for cache_test in range(2):
        assert product_3 == general.get_best_selling_products(
            context, n_products=n_products)[0]

    # add a new product with discounted amount
    product_4 = create_product("test-sku-4",
                               supplier=supplier,
                               shop=shop,
                               default_price=price)
    create_order_with_product(product_4,
                              supplier,
                              quantity=2,
                              taxless_base_unit_price=price,
                              shop=shop)
    from shuup.customer_group_pricing.models import CgpDiscount

    CgpDiscount.objects.create(shop=shop,
                               product=product_4,
                               group=AnonymousContact.get_default_group(),
                               discount_amount_value=(price * 0.1))
예제 #51
0
def test_get_best_selling_products_per_supplier():
    from shuup.front.template_helpers import general

    context = get_jinja_context()

    # No products sold
    assert len(list(general.get_best_selling_products(context,
                                                      n_products=3))) == 0
    shop = get_default_shop()

    supplier = get_default_supplier()
    supplier2 = Supplier.objects.create(name="supplier2", enabled=True)
    supplier2.shops.add(shop)

    product1 = create_product("product1", shop, supplier, 10)
    product2 = create_product("product2", shop, supplier2, 20)
    create_order_with_product(product1,
                              supplier,
                              quantity=1,
                              taxless_base_unit_price=10,
                              shop=shop)
    create_order_with_product(product2,
                              supplier2,
                              quantity=2,
                              taxless_base_unit_price=20,
                              shop=shop)

    cache.clear()
    # Two products sold, but only one supplier
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context,
                                              n_products=3,
                                              supplier=supplier))
        assert len(best_selling_products) == 1
        assert product1 in best_selling_products
        assert product2 not in best_selling_products

    # Two products sold, but only one supplier
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context,
                                              n_products=3,
                                              supplier=supplier2))
        assert len(best_selling_products) == 1
        assert product1 not in best_selling_products
        assert product2 in best_selling_products

    # Make product 1 also sold by supplier2
    shop_product = product1.get_shop_instance(shop)
    shop_product.suppliers.add(supplier2)

    cache.clear()
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context,
                                              n_products=3,
                                              supplier=supplier2))
        assert len(best_selling_products
                   ) == 1  # Since there isn't any orders yet for supplier 2
        assert product2 in best_selling_products

    create_order_with_product(product1,
                              supplier2,
                              quantity=2,
                              taxless_base_unit_price=20,
                              shop=shop)
    cache.clear()
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context,
                                              n_products=3,
                                              supplier=supplier2))
        assert len(best_selling_products) == 2
        assert product1 in best_selling_products
        assert product2 in best_selling_products
예제 #52
0
def test_get_best_selling_products():
    from shuup.front.template_helpers import general

    context = get_jinja_context()

    # No products sold
    assert len(list(general.get_best_selling_products(context,
                                                      n_products=3))) == 0
    shop = get_default_shop()

    supplier = get_default_supplier()
    supplier2 = Supplier.objects.create(name="supplier2", enabled=True)
    supplier3 = Supplier.objects.create(name="supplier3", enabled=True)
    supplier2.shops.add(shop)
    supplier3.shops.add(shop)

    product1 = create_product("product1", shop, supplier, 10)
    product2 = create_product("product2", shop, supplier, 20)
    create_order_with_product(product1,
                              supplier,
                              quantity=1,
                              taxless_base_unit_price=10,
                              shop=shop)
    create_order_with_product(product2,
                              supplier,
                              quantity=2,
                              taxless_base_unit_price=20,
                              shop=shop)

    cache.clear()
    # Two products sold
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context, n_products=3))
        assert len(best_selling_products) == 2
        assert product1 in best_selling_products
        assert product2 in best_selling_products

    # Make order unorderable
    shop_product = product1.get_shop_instance(shop)
    shop_product.visibility = ShopProductVisibility.NOT_VISIBLE
    shop_product.save()

    cache.clear()
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context, n_products=3))
        assert len(best_selling_products) == 1
        assert product1 not in best_selling_products
        assert product2 in best_selling_products

    # add a new product with discounted amount
    product3 = create_product("product3",
                              supplier=supplier,
                              shop=shop,
                              default_price=30)
    create_order_with_product(product3,
                              supplier,
                              quantity=1,
                              taxless_base_unit_price=30,
                              shop=shop)
    from shuup.customer_group_pricing.models import CgpDiscount

    CgpDiscount.objects.create(shop=shop,
                               product=product3,
                               group=AnonymousContact.get_default_group(),
                               discount_amount_value=5)
    cache.clear()
    for cache_test in range(2):
        best_selling_products = list(
            general.get_best_selling_products(context,
                                              n_products=3,
                                              orderable_only=True))
        assert len(best_selling_products) == 2
        assert product1 not in best_selling_products
        assert product2 in best_selling_products
        assert product3 in best_selling_products
예제 #53
0
def test_taxes_report(rf):
    shop = get_default_shop()
    supplier = get_default_supplier(shop)
    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"])
예제 #54
0
def test_product_summary():
    shop = get_default_shop()
    supplier = get_simple_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    supplier.adjust_stock(product.id, 5)

    # Order with 2 unshipped, non-refunded items and a shipping cost
    order = create_order_with_product(product, supplier, 2, 200, shop=shop)
    order.cache_prices()
    product_line = order.lines.first()
    shipping_line = order.lines.create(type=OrderLineType.SHIPPING,
                                       base_unit_price_value=5,
                                       quantity=1)

    # Make sure no invalid entries and check product quantities
    product_summary = order.get_product_summary()
    assert all(product_summary.keys())
    summary = product_summary[product.id]
    assert_defaultdict_values(summary,
                              ordered=2,
                              shipped=0,
                              refunded=0,
                              unshipped=2)

    # Create a shipment for the other item, make sure status changes
    assert order.shipping_status == ShippingStatus.NOT_SHIPPED
    assert order.can_create_shipment()
    order.create_shipment(supplier=supplier, product_quantities={product: 1})
    assert order.shipping_status == ShippingStatus.PARTIALLY_SHIPPED

    order.create_refund([{
        "line": shipping_line,
        "quantity": 1,
        "amount": Money(5, order.currency),
        "restock": False
    }])

    product_summary = order.get_product_summary()
    assert all(product_summary.keys())
    summary = product_summary[product.id]
    assert_defaultdict_values(summary,
                              ordered=2,
                              shipped=1,
                              refunded=0,
                              unshipped=1)

    # Create a refund for 2 items, we should get no negative values
    order.create_refund([{
        "line": product_line,
        "quantity": 2,
        "amount": Money(200, order.currency),
        "restock": False
    }])

    product_summary = order.get_product_summary()
    assert all(product_summary.keys())
    summary = product_summary[product.id]
    assert_defaultdict_values(summary,
                              ordered=2,
                              shipped=1,
                              refunded=2,
                              unshipped=0)
예제 #55
0
def test_refund_errors(admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    tax_rate = Decimal("0.1")
    taxless_base_unit_price = shop.create_price(200)
    order = create_order_with_product(product, supplier, 3, taxless_base_unit_price, tax_rate, shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    assert len(order.lines.all()) == 1
    assert order.can_create_refund()
    assert not order.has_refunds()

    client = _get_client(admin_user)

    refund_url = "/api/shuup/order/%s/create_refund/" % order.id
    product_line = order.lines.first()

    # error 1 - max refundable limit
    data = {
        "refund_lines": [{
            "line": product_line.id,
            "quantity": 1000,
            "amount": 1,
            "restock_products": False
        }]
    }
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert "Refund exceeds quantity." in response.data

    # error 2 - max amount
    data = {
        "refund_lines": [{
            "line": product_line.id,
            "quantity": 1,
            "amount": 100000000,
            "restock_products": False
        }]
    }
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert "Refund exceeds amount." in response.data

    # error 3 - invalid amount
    data = {
        "refund_lines": [{
            "line": product_line.id,
            "quantity": 1,
            "amount": -10,
            "restock_products": False
        }]
    }
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert "Invalid refund amount." in response.data

    # create partial refund
    data = {
        "refund_lines": [{
            "line": product_line.id,
            "quantity": 1,
            "amount": 1,
            "restock_products": False
        }]
    }
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED

    # error 4 - can't create full refund
    data = {"restock_products": False}
    response = client.post("/api/shuup/order/%s/create_full_refund/" % order.id, data, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert "It is not possible to create the refund." in response.data
예제 #56
0
def test_best_selling_products_with_multiple_orders():
    context = get_jinja_context()
    supplier = get_default_supplier()
    shop = get_default_shop()
    n_products = 2
    price = 10

    product_1 = create_product("test-sku-1", supplier=supplier, shop=shop)
    product_2 = create_product("test-sku-2", supplier=supplier, shop=shop)
    create_order_with_product(product_1, supplier, quantity=1, taxless_base_unit_price=price, shop=shop)
    create_order_with_product(product_2, supplier, quantity=1, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Two initial products sold
    assert product_1 in general.get_best_selling_products(context, n_products=n_products)
    assert product_2 in general.get_best_selling_products(context, n_products=n_products)

    product_3 = create_product("test-sku-3", supplier=supplier, shop=shop)
    create_order_with_product(product_3, supplier, quantity=2, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Third product sold in greater quantity
    assert product_3 in general.get_best_selling_products(context, n_products=n_products)

    create_order_with_product(product_1, supplier, quantity=4, taxless_base_unit_price=price, shop=shop)
    create_order_with_product(product_2, supplier, quantity=4, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Third product outsold by first two products
    assert product_3 not in general.get_best_selling_products(context, n_products=n_products)

    children = [create_product("SimpleVarChild-%d" % x, supplier=supplier, shop=shop) for x in range(5)]
    for child in children:
        child.link_to_parent(product_3)
        create_order_with_product(child, supplier, quantity=1, taxless_base_unit_price=price, shop=shop)
    cache.clear()
    # Third product now sold in greatest quantity
    assert product_3 == general.get_best_selling_products(context, n_products=n_products)[0]
예제 #57
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()
예제 #58
0
def test_product_total_sales_report(rf, admin_user, order_by):
    with override_provides("reports", [
            "shuup.default_reports.reports.product_total_sales:ProductSalesReport"
    ]):
        shop = get_default_shop()
        supplier = get_default_supplier(shop)
        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)
예제 #59
0
def test_refunds(admin_user):
    shop = get_default_shop()
    supplier = get_default_supplier()
    product = create_product(
        "test-sku",
        shop=get_default_shop(),
        default_price=10,
    )
    tax_rate = Decimal("0.1")
    taxless_base_unit_price = shop.create_price(200)
    order = create_order_with_product(product, supplier, 3, taxless_base_unit_price, tax_rate, shop=shop)
    order.payment_status = PaymentStatus.DEFERRED
    order.cache_prices()
    order.save()

    assert len(order.lines.all()) == 1
    assert order.can_create_refund()
    assert not order.has_refunds()

    client = _get_client(admin_user)

    # Refund first and the only order line in 3 parts
    refund_url = "/api/shuup/order/%s/create_refund/" % order.id
    product_line = order.lines.first()
    data = {
        "refund_lines": [{
            "line": product_line.id,
            "quantity": 1,
            "amount": (product_line.taxful_price.amount.value / 3),
            "restock_products": False
        }]
    }

    # First refund
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()
    assert order.lines.count() == 2
    assert order.has_refunds()

    # Second refund
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()
    assert order.lines.count() == 3
    assert order.can_create_refund()

    # Third refund
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_201_CREATED
    order.refresh_from_db()
    assert order.lines.count() == 4
    assert not order.can_create_refund()
    assert not order.taxful_total_price.amount
    assert order.get_total_tax_amount() == Money(
        (order.taxful_total_price_value - order.taxless_total_price_value),
        order.currency)

    # Test error message
    response = client.post(refund_url, data, format="json")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    error_msg = json.loads(response.content.decode("utf-8"))["error"]
    assert error_msg == "Order can not be refunded at the moment."
예제 #60
0
def test_customer_sales_report(rf, order_by):
    shop = get_default_shop()
    supplier = get_default_supplier(shop)
    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")))