Esempio n. 1
0
def test_basic_order_flow(with_company):
    cache.clear()
    create_default_order_statuses()
    n_orders_pre = Order.objects.count()
    populate_if_required()
    c = SmartClient()
    product_ids = _populate_client_basket(c)

    addresses_path = reverse("wshop:checkout", kwargs={"phase": "addresses"})
    addresses_soup = c.soup(addresses_path)
    inputs = fill_address_inputs(addresses_soup, with_company=with_company)
    response = c.post(addresses_path, data=inputs)
    assert response.status_code == 302  # Should redirect forth

    methods_path = reverse("wshop:checkout", kwargs={"phase": "methods"})
    methods_soup = c.soup(methods_path)
    assert c.post(methods_path, data=extract_form_fields(
        methods_soup)).status_code == 302  # Should redirect forth

    confirm_path = reverse("wshop:checkout", kwargs={"phase": "confirm"})
    confirm_soup = c.soup(confirm_path)
    Product.objects.get(pk=product_ids[0]).soft_delete()
    assert c.post(confirm_path, data=extract_form_fields(
        confirm_soup)).status_code == 200  # user needs to reconfirm
    data = extract_form_fields(confirm_soup)
    data['product_ids'] = ','.join(product_ids[1:])
    assert c.post(confirm_path,
                  data=data).status_code == 302  # Should redirect forth

    n_orders_post = Order.objects.count()
    assert n_orders_post > n_orders_pre, "order was created"
Esempio n. 2
0
def test_order_statuses(admin_user):
    create_default_order_statuses()

    source = seed_source(admin_user)
    source.add_line(
        type=OrderLineType.PRODUCT,
        product=get_default_product(),
        supplier=get_default_supplier(),
        quantity=1,
        base_unit_price=source.create_price(10),
    )
    source.add_line(
        type=OrderLineType.OTHER,
        quantity=1,
        base_unit_price=source.create_price(10),
        require_verification=True,
    )

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

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

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

    # FUTURE: order is fully shipped the status changes to complete/complete
    order.create_shipment_of_all_products()
    assert order.status.identifier == DefaultOrderStatus.INITIAL.value
    assert order.status.role == OrderStatusRole.INITIAL
Esempio n. 3
0
def test_create_without_a_contact(admin_user):
    create_default_order_statuses()
    shop = get_default_shop()
    sm = get_default_shipping_method()
    pm = get_default_payment_method()
    assert not Order.objects.count()
    client = _get_client(admin_user)
    lines = [
        {
            "type": "other",
            "sku": "hello",
            "text": "A greeting",
            "quantity": 1,
            "base_unit_price_value": "3.5"
        },
    ]
    response = client.post("/api/wshop/order/",
                           content_type="application/json",
                           data=json.dumps({
                               "shop": shop.pk,
                               "customer": None,
                               "shipping_method": sm.pk,
                               "payment_method": pm.pk,
                               "lines": lines
                           }))
    assert response.status_code == 201
    assert Order.objects.count() == 1
    order = Order.objects.first()
    assert order.shop == shop
    assert order.customer == None
    assert order.creator == admin_user
    assert order.shipping_method == sm
    assert order.payment_method == pm
    assert order.billing_address == None
    assert order.shipping_address == None
    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(3.5)
    assert order.lines.count(
    ) == 3  # shipping line, payment line, 2 product lines, 2 other lines
    for idx, line in enumerate(order.lines.all()[:1]):
        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))
Esempio n. 4
0
def test_checkout_empty_basket(rf):
    cache.clear()
    create_default_order_statuses()
    n_orders_pre = Order.objects.count()
    populate_if_required()
    c = SmartClient()
    product_ids = _populate_client_basket(c)
    addresses_path = reverse("wshop:checkout", kwargs={"phase": "addresses"})
    addresses_soup = c.soup(addresses_path)
    inputs = fill_address_inputs(addresses_soup)
    for product_id in product_ids:
        Product.objects.get(pk=product_id).soft_delete()
    response, soup = c.response_and_soup(addresses_path,
                                         data=inputs,
                                         method="post")
    assert response.status_code == 200  # Should redirect forth
    assert b"Your shopping cart is empty." in soup.renderContents()
Esempio n. 5
0
def test_get_by_status(admin_user):
    create_default_order_statuses()
    shop = get_default_shop()
    cancelled_status = OrderStatus.objects.get_default_canceled()
    for i in range(1, 10):
        order = create_empty_order(shop=shop)
        order.status = cancelled_status
        order.save()

    order = create_empty_order(shop=shop)
    order.save()
    client = _get_client(admin_user)
    response = client.get("/api/wshop/order/",
                          data={"status": order.status.id})
    assert response.status_code == status.HTTP_200_OK
    order_data = json.loads(response.content.decode("utf-8"))

    assert len(order_data) == 1
    assert order_data[0].get("id") == order.id
    assert order_data[0].get("identifier") == order.identifier

    response = client.get("/api/wshop/order/",
                          data={"status": cancelled_status.id})
    assert response.status_code == status.HTTP_200_OK
    order_data = json.loads(response.content.decode("utf-8"))
    assert len(order_data) == 9

    assert order.can_set_complete()
    old_status = order.status
    order.status = OrderStatus.objects.get_default_complete()
    order.save()

    assert old_status != order.status
    response = client.get("/api/wshop/order/", data={"status": old_status.id})
    assert response.status_code == status.HTTP_200_OK
    order_data = json.loads(response.content.decode("utf-8"))
    assert len(order_data) == 0

    response = client.get("/api/wshop/order/",
                          data={"status": order.status.id})
    assert response.status_code == status.HTTP_200_OK
    order_data = json.loads(response.content.decode("utf-8"))
    assert len(order_data) == 1
Esempio n. 6
0
def test_single_default_status_for_role():
    create_default_order_statuses()
    new_default_cancel = OrderStatus.objects.create(
        identifier="foo",
        role=OrderStatusRole.CANCELED,
        name="foo",
        default=True)
    assert new_default_cancel.default
    assert OrderStatus.objects.get_default_canceled() == new_default_cancel
    new_default_cancel.delete()

    # We can use this weird moment to cover the "no default" case, yay
    with pytest.raises(ObjectDoesNotExist):
        OrderStatus.objects.get_default_canceled()

    old_cancel = OrderStatus.objects.get(
        identifier=DefaultOrderStatus.CANCELED.value)
    assert not old_cancel.default  # This will have been reset when another status became the default
    old_cancel.default = True
    old_cancel.save()
Esempio n. 7
0
def test_order_statuses_are_translatable():
    create_default_order_statuses()
    assert OrderStatus.objects.translated(
        get_language()).count() == OrderStatus.objects.count()
Esempio n. 8
0
def test_create_order(admin_user, target_customer):
    with override_settings(**REQUIRED_SETTINGS):
        set_configuration()
        factories.create_default_order_statuses()
        shop = factories.get_default_shop()
        client = _get_client(admin_user)

        # Create basket for target customer
        payload = {"shop": shop.pk}
        target = orderer = get_person_contact(admin_user)
        if target_customer == "other_person":
            target = orderer = factories.create_random_person()
            payload["customer"] = target.pk
        elif target_customer == "company":
            target = factories.create_random_company()
            orderer = factories.create_random_person()
            payload.update({"customer": target.pk, "orderer": orderer.pk})
            target.members.add(orderer)

        response = client.post("/api/wshop/basket/new/", payload)
        assert response.status_code == status.HTTP_201_CREATED
        basket_data = json.loads(response.content.decode("utf-8"))
        basket = Basket.objects.first()
        assert basket.key == basket_data["uuid"].split("-")[1]
        assert basket.customer == target
        assert basket.orderer == orderer

        shop_product = factories.get_default_shop_product()
        shop_product.default_price = TaxfulPrice(1, shop.currency)
        shop_product.save()

        # Add shop product to basket
        payload = {"shop_product": shop_product.id}
        response = client.post(
            "/api/wshop/basket/{}-{}/add/".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"]) == 1

        # Create order from basket
        response = client.post(
            "/api/wshop/basket/{}-{}/create_order/".format(
                shop.pk, basket.key), payload)
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        response_data = json.loads(response.content.decode("utf-8"))
        assert "errors" in response_data

        factories.get_default_payment_method()
        factories.get_default_shipping_method()
        response = client.post(
            "/api/wshop/basket/{}-{}/create_order/".format(
                shop.pk, basket.key), payload)
        assert response.status_code == status.HTTP_201_CREATED
        response_data = json.loads(response.content.decode("utf-8"))
        basket.refresh_from_db()
        assert basket.finished
        order = Order.objects.get(
            reference_number=response_data["reference_number"])
        assert order.status == OrderStatus.objects.get_default_initial()
        assert order.payment_status == PaymentStatus.NOT_PAID
        assert order.shipping_status == ShippingStatus.NOT_SHIPPED
        assert not order.payment_method
        assert not order.shipping_method
        assert float(order.taxful_total_price_value) == 1
        assert order.customer == target
        assert order.orderer == orderer
        assert order.creator == admin_user
        assert not order.billing_address
        assert not order.shipping_address
Esempio n. 9
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))
Esempio n. 10
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
Esempio n. 11
0
def test_order_flow_with_phases(get_shipping_method, shipping_data,
                                get_payment_method, payment_data):
    cache.clear()
    create_default_order_statuses()
    populate_if_required()
    c = SmartClient()
    _populate_client_basket(c)

    # Create methods
    shipping_method = get_shipping_method()
    payment_method = get_payment_method()

    # Resolve paths
    addresses_path = reverse("wshop:checkout", kwargs={"phase": "addresses"})
    methods_path = reverse("wshop:checkout", kwargs={"phase": "methods"})
    shipping_path = reverse("wshop:checkout", kwargs={"phase": "shipping"})
    payment_path = reverse("wshop:checkout", kwargs={"phase": "payment"})
    confirm_path = reverse("wshop:checkout", kwargs={"phase": "confirm"})

    # Phase: Addresses
    addresses_soup = c.soup(addresses_path)
    inputs = fill_address_inputs(addresses_soup, with_company=False)
    response = c.post(addresses_path, data=inputs)
    assert response.status_code == 302, "Address phase should redirect forth to methods"

    # Phase: Methods
    response = c.get(methods_path)
    assert response.status_code == 200
    response = c.post(methods_path,
                      data={
                          "shipping_method": shipping_method.pk,
                          "payment_method": payment_method.pk
                      })
    assert response.status_code == 302, "Methods phase should redirect forth"

    if isinstance(shipping_method.carrier, CarrierWithCheckoutPhase):
        # Phase: Shipping
        response = c.get(shipping_path)
        assert response.status_code == 200
        response = c.post(shipping_path, data=shipping_data)
        assert response.status_code == 302, "Payments phase should redirect forth"

    if isinstance(payment_method.payment_processor, PaymentWithCheckoutPhase):
        # Phase: payment
        response = c.get(payment_path)
        assert response.status_code == 200
        response = c.post(payment_path, data=payment_data)
        assert response.status_code == 302, "Payments phase should redirect forth"

    # Phase: Confirm
    assert Order.objects.count() == 0
    confirm_soup = c.soup(confirm_path)

    response = c.post(confirm_path, data=extract_form_fields(confirm_soup))
    assert response.status_code == 302, "Confirm should redirect forth"

    order = Order.objects.first()

    if isinstance(shipping_method.carrier, CarrierWithCheckoutPhase):
        assert order.shipping_data.get("input_value") == "20540"

    if isinstance(payment_method.payment_processor, PaymentWithCheckoutPhase):
        assert order.payment_data.get("input_value")
        assert order.payment_status == PaymentStatus.NOT_PAID
        # Resolve order specific paths (payment and complete)
        process_payment_path = reverse("wshop:order_process_payment",
                                       kwargs={
                                           "pk": order.pk,
                                           "key": order.key
                                       })
        process_payment_return_path = reverse(
            "wshop:order_process_payment_return",
            kwargs={
                "pk": order.pk,
                "key": order.key
            })
        order_complete_path = reverse("wshop:order_complete",
                                      kwargs={
                                          "pk": order.pk,
                                          "key": order.key
                                      })

        # Check confirm redirection to payment page
        assert response.url.endswith(process_payment_path), (
            "Confirm should have redirected to payment page")

        # Visit payment page
        response = c.get(process_payment_path)
        assert response.status_code == 302, "Payment page should redirect forth"
        assert response.url.endswith(process_payment_return_path)

        # Check payment return
        response = c.get(process_payment_return_path)
        assert response.status_code == 302, "Payment return should redirect forth"
        assert response.url.endswith(order_complete_path)

        # Check payment status has changed to DEFERRED
        order = Order.objects.get(pk=order.pk)  # reload
        assert order.payment_status == PaymentStatus.DEFERRED