def test_get_by_identifier(admin_user): shop = get_default_shop() for i in range(1,10): order = create_empty_order(shop=shop) order.save() order = create_empty_order(shop=shop) order.save() client = _get_client(admin_user) response = client.get("/api/shuup/order/", data={"identifier": order.identifier}) assert response.status_code == status.HTTP_200_OK order_data = json.loads(response.content.decode("utf-8")) assert order_data[0].get("id") == order.id assert order_data[0].get("identifier") == order.identifier
def test_process_payment_return_request(rf): """ Order payment with default payment method with ``CustomPaymentProcessor`` should be deferred. Payment can't be processed if method doesn't have provider or provider is not enabled or payment method is not enabled. """ pm = PaymentMethod.objects.create( shop=get_default_shop(), name="Test method", enabled=False, tax_class=get_default_tax_class()) order = create_empty_order() order.payment_method = pm order.save() assert order.payment_status == PaymentStatus.NOT_PAID with pytest.raises(ValueError): # Can't process payment with unusable method order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.NOT_PAID pm.payment_processor = get_custom_payment_processor() pm.payment_processor.enabled = False pm.save() with pytest.raises(ValueError): # Can't process payment with unusable method order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.NOT_PAID pm.payment_processor.enabled = True pm.save() with pytest.raises(ValueError): # Can't process payment with unusable method order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.NOT_PAID pm.enabled = True pm.save() order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.DEFERRED
def test_complex_order_tax(include_taxes): tax = get_default_tax() quantities = [44, 23, 65] product = get_default_product() supplier = get_default_supplier() shop = get_default_shop() shop.prices_include_tax = include_taxes shop.save() order = create_empty_order(shop=shop) order.full_clean() order.save() pricing_context = get_pricing_module().get_context_from_data( shop=shop, customer=order.customer or AnonymousContact(), ) total_price = Decimal("0") price = Decimal("50") for quantity in quantities: total_price += quantity * price add_product_to_order(order, supplier, product, quantity, price, tax.rate, pricing_context) order.cache_prices() order.save() currency = "EUR" summary = order.get_tax_summary()[0] assert summary.tax_rate == tax.rate assert summary.based_on == Money(total_price, currency) assert summary.tax_amount == Money(total_price * tax.rate, currency) assert summary.taxful == summary.based_on + summary.tax_amount assert order.get_total_tax_amount() == Money(total_price * tax.rate, currency)
def test_order_customer_name_from_shipping_address(): order = create_empty_order() assert order.customer_id is None assert order.orderer_id is None order.billing_address = None order.save() order.refresh_from_db() assert order.get_customer_name() == order.shipping_address.name
def test_refno_generation(method): for attempt in range(10): with override_settings(SHUUP_REFERENCE_NUMBER_METHOD=method): order = create_empty_order() order.save() assert order.reference_number with pytest.raises(ValueError): get_reference_number(order)
def test_complete_order(admin_user): shop = get_default_shop() order = create_empty_order(shop=shop) order.save() client = _get_client(admin_user) response = client.post("/api/shuup/order/%s/complete/" % order.pk) assert response.status_code == 200 response = client.post("/api/shuup/order/%s/complete/" % order.pk) assert response.status_code == 400
def test_order_customer_name_from_billing_address(): person = create_random_person() order = create_empty_order() order.orderer = person order.save() order.refresh_from_db() assert order.customer_id is None assert order.orderer_id is not None assert order.get_customer_name() == order.billing_address.name assert order.shipping_address_id is not None
def test_get_by_id(admin_user): shop = get_default_shop() order = create_empty_order(shop=shop) order.save() client = _get_client(admin_user) response = client.get("/api/shuup/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
def test_custom_refno_generation(): methods = ( custom_refno_gen, "%s.%s" % (__name__, custom_refno_gen.__name__) ) for method in methods: with override_settings(SHUUP_REFERENCE_NUMBER_METHOD=method): order = create_empty_order() order.save() assert order.reference_number == custom_refno_gen(order) with pytest.raises(ValueError): get_reference_number(order)
def test_orders_list_view(browser, admin_user, live_server): shop = get_default_shop() for i in range(0, 10): order = create_empty_order(shop=shop) order.save() # Set last one canceled Order.objects.last().set_canceled() initialize_admin_browser_test(browser, live_server) _visit_orders_list_view(browser, live_server) _test_status_filter(browser) # Will set three orders from end canceled
def test_custom_ident_generation(): methods = ( custom_ident_gen, "%s.%s" % (__name__, custom_ident_gen.__name__) ) for method in methods: with override_settings(SHUUP_ORDER_IDENTIFIER_METHOD=method): order = create_empty_order() order.save() assert order.identifier == custom_ident_gen(order) with pytest.raises(ValueError): get_order_identifier(order)
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/shuup/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/shuup/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/shuup/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/shuup/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
def test_editing_existing_order(rf, admin_user): modifier = UserFactory() get_initial_order_status() # Needed for the API contact = create_random_person(locale="en_US", minimum_name_comp_len=5) state = get_frontend_order_state(contact=contact) shop = get_default_shop() order = create_empty_order(shop=shop) order.payment_data = {"payment_data": True} order.shipping_data = {"shipping_data": True} order.extra_data = {"external_id": "123"} order.save() assert order.lines.count() == 0 assert order.pk is not None assert order.modified_by == order.creator request = get_frontend_request_for_command(state, "finalize", modifier) response = OrderEditView.as_view()(request, pk=order.pk) assert_contains(response, "orderIdentifier") # this checks for status codes as a side effect data = json.loads(response.content.decode("utf8")) edited_order = Order.objects.get(pk=order.pk) # Re fetch the initial order # Check that identifiers has not changed assert edited_order.identifier == data["orderIdentifier"] == order.identifier assert edited_order.pk == order.pk # Check that the product content is updated based on state assert edited_order.lines.count() == 5 assert edited_order.customer == contact # Check that product line have right taxes for line in edited_order.lines.all(): if line.type == OrderLineType.PRODUCT: assert [line_tax.tax.code for line_tax in line.taxes.all()] == ["test_code"] assert line.taxful_price.amount > line.taxless_price.amount # Make sure order modification information is correct assert edited_order.modified_by != order.modified_by assert edited_order.modified_by == modifier assert edited_order.modified_on > order.modified_on # Make sure all non handled attributes is preserved from original order assert edited_order.creator == order.creator assert edited_order.ip_address == order.ip_address assert edited_order.orderer == order.orderer assert edited_order.customer_comment == order.customer_comment assert edited_order.marketing_permission == order.marketing_permission assert edited_order.order_date == order.order_date assert edited_order.status == order.status assert edited_order.payment_data == order.payment_data assert edited_order.shipping_data == order.shipping_data assert edited_order.extra_data == order.extra_data
def test_shipment_creation_with_invalid_unsaved_shipment(): shop = get_default_shop() supplier = get_default_supplier() order = _get_order(shop, supplier) second_order = create_empty_order(shop=shop) second_order.full_clean() second_order.save() product_lines = order.lines.exclude(product_id=None) for line in product_lines: for i in range(0, int(line.quantity)): with pytest.raises(AssertionError): unsaved_shipment = Shipment(supplier=supplier, order=second_order) order.create_shipment({line.product: 1}, shipment=unsaved_shipment) assert order.shipments.count() == 0
def test_known_extra_data(): order = create_empty_order() order.shipping_data = {"instruction": "Hello"} order.payment_data = {"ssn": "101010-010X"} order.extra_data = {"wrapping_color": "blue"} order.save() with override_settings( SHUUP_ORDER_KNOWN_SHIPPING_DATA_KEYS=[("instruction", "Instruction")], SHUUP_ORDER_KNOWN_PAYMENT_DATA_KEYS=[("ssn", "Social Security Number")], SHUUP_ORDER_KNOWN_EXTRA_DATA_KEYS=[("wrapping_color", "Wrapping Color")], ): known_data = dict(order.get_known_additional_data()) assert ("Instruction" in known_data) assert ("Social Security Number" in known_data) assert ("Wrapping Color" in known_data)
def test_get_by_order_date(admin_user): shop = get_default_shop() today = dt.today() yesterday = dt.today() - datetime.timedelta(days=1) for i in range(1, 10): order = create_empty_order(shop=shop) order.order_date = yesterday order.save() order = create_empty_order(shop=shop) order.save() client = _get_client(admin_user) response = client.get("/api/shuup/order/", data={"date": today}) 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/shuup/order/", data={"date": yesterday}) assert response.status_code == status.HTTP_200_OK order_data = json.loads(response.content.decode("utf-8")) assert len(order_data) == 9
def test_product_detail(browser, admin_user, live_server, settings): activate(settings.PARLER_DEFAULT_LANGUAGE_CODE) shop = get_default_shop() order = create_empty_order(shop=shop) order.save() initialize_admin_browser_test(browser, live_server, settings) url = reverse("shuup_admin:order.detail", kwargs={"pk": order.pk}) browser.visit("%s%s" % (live_server, url)) wait_until_condition(browser, condition=lambda x: x.is_text_present("Order %s" % order.pk)) change_addresses(live_server, browser, order) set_status(browser, order, OrderStatus.objects.get_default_processing()) assert order.can_set_complete() set_status(browser, order, OrderStatus.objects.get_default_complete())
def test_empty_order(): order = create_empty_order() order.save() with pytest.raises(NoProductsToShipException): order.create_shipment_of_all_products() with pytest.raises(NoProductsToShipException): order.create_shipment(supplier=None, product_quantities={1: 0}) assert order.can_edit() order.set_canceled() assert not order.can_edit(), "Can't edit canceled order" assert not order.can_set_complete(), "Can't process canceled order" order.set_canceled() # Again! (This should be a no-op) order.delete() assert order.pk and order.deleted, "Order is soft-deleted" order.delete() # Again! (This, too, should be a no-op)
def test_delete_toolbar_button(rf, admin_user, view_cls, get_method, method_attr): method = get_method() assert method.can_delete() view = view_cls.as_view() request = apply_request_middleware(rf.get("/"), user=admin_user) check_for_delete(view, request, method) # Create order for method and test the can_delete and edit view order = create_empty_order() setattr(order, method_attr, method) order.save() assert not method.can_delete() check_for_delete(view, request, method) # Make sure that the actual delete is also blocked with pytest.raises(ProtectedError): method.delete()
def _get_order(shop, supplier, stocked=False): order = create_empty_order(shop=shop) order.full_clean() order.save() for product_data in _get_product_data(stocked): quantity = product_data.pop("quantity") product = create_product( sku=product_data.pop("sku"), shop=shop, supplier=supplier, default_price=3.33, **product_data) add_product_to_order(order, supplier, product, quantity=quantity, taxless_base_unit_price=1) order.cache_prices() order.check_all_verified() order.save() return order
def test_rounding_with_taxes(prices): shop = get_default_shop() supplier = get_default_supplier() order = create_empty_order(shop=shop) order.save() product = create_product("test_sku", shop=shop, supplier=supplier) tax_rate = Decimal("0.22222") for x, price in enumerate(prices): add_product_to_order( order, supplier, product, quantity=Decimal("2.22"), taxless_base_unit_price=Decimal(price), tax_rate=tax_rate) order.cache_prices() for x, order_line in enumerate(order.lines.all().order_by("ordering")): # Check that total prices calculated from priceful parts still matches assert _get_taxless_price(order_line) == order_line.taxless_price assert _get_taxful_price(order_line) == order_line.taxful_price assert order_line.price == (order_line.base_unit_price * order_line.quantity - order_line.discount_amount)
def test_service_methods_with_long_name(rf): """ Make sure that service methods with long names (up to the max length of shipping or payment method names) don't cause exceptions when creating an order. """ MAX_LENGTH = 100 long_name = "X" * MAX_LENGTH assert len(long_name) == MAX_LENGTH sm = ShippingMethod.objects.language("en").create( shop=get_default_shop(), name=long_name, enabled=True, tax_class=get_default_tax_class()) pm = PaymentMethod.objects.language("en").create( shop=get_default_shop(), name=long_name, enabled=True, tax_class=get_default_tax_class()) order = create_empty_order() order.shipping_method = sm order.payment_method = pm order.full_clean() order.save()
def _get_order(shop, supplier, has_price): order = create_empty_order(shop=shop) order.full_clean() order.save() for product_data in _get_product_data(has_price): quantity = product_data.pop("quantity") tax_rate = product_data.pop("tax_rate") product = create_product( sku=product_data.pop("sku"), shop=shop, supplier=supplier, **product_data) add_product_to_order( order, supplier, product, quantity=quantity, taxless_base_unit_price=product_data["default_price"], tax_rate=tax_rate) order.cache_prices() order.check_all_verified() order.save() return order
def test_line_discount_more(): order = create_empty_order() order.save() ol = OrderLine(order=order, type=OrderLineType.OTHER) ol.quantity = 5 ol.base_unit_price = order.shop.create_price(30) ol.discount_amount = order.shop.create_price(50) ol.save() currency = order.shop.currency assert ol.taxless_base_unit_price == TaxlessPrice(30, currency) assert ol.taxless_discount_amount == TaxlessPrice(50, currency) assert ol.taxless_price == TaxlessPrice(5 * 30 - 50, currency) ol.taxes.add(OrderLineTax.from_tax( get_default_tax(), ol.taxless_price.amount, order_line=ol)) assert ol.taxless_discount_amount == TaxlessPrice(50, currency) assert ol.taxful_discount_amount == TaxfulPrice(75, currency) assert ol.taxless_price == TaxlessPrice(100, currency) assert ol.taxful_price == TaxfulPrice(150, currency) assert ol.taxless_base_unit_price == TaxlessPrice(30, currency) assert ol.taxful_base_unit_price == TaxfulPrice(45, currency)
def test_line_discount(): order = create_empty_order(prices_include_tax=False) order.save() currency = order.shop.currency ol = OrderLine(order=order, type=OrderLineType.OTHER, quantity=5, text="Thing") ol.discount_amount = order.shop.create_price(50) ol.base_unit_price = order.shop.create_price(40) ol.save() ol.taxes.add( OrderLineTax.from_tax(get_default_tax(), ol.taxless_price.amount, order_line=ol)) assert ol.taxless_discount_amount == order.shop.create_price(50) assert ol.taxful_discount_amount == TaxfulPrice(75, currency) assert ol.taxless_price == order.shop.create_price(150) assert ol.taxful_price == TaxfulPrice(150 + 75, currency) assert ol.taxless_base_unit_price == order.shop.create_price(40) assert ol.taxful_base_unit_price == TaxfulPrice(60, currency) assert "Thing" in six.text_type(ol)
def test_line_discount_more(): order = create_empty_order() order.save() ol = OrderLine(order=order, type=OrderLineType.OTHER) ol.quantity = 5 ol.base_unit_price = order.shop.create_price(30) ol.discount_amount = order.shop.create_price(50) ol.save() currency = order.shop.currency assert ol.taxless_base_unit_price == TaxlessPrice(30, currency) assert ol.taxless_discount_amount == TaxlessPrice(50, currency) assert ol.taxless_price == TaxlessPrice(5 * 30 - 50, currency) ol.taxes.add( OrderLineTax.from_tax(get_default_tax(), ol.taxless_price.amount, order_line=ol)) assert ol.taxless_discount_amount == TaxlessPrice(50, currency) assert ol.taxful_discount_amount == TaxfulPrice(75, currency) assert ol.taxless_price == TaxlessPrice(100, currency) assert ol.taxful_price == TaxfulPrice(150, currency) assert ol.taxless_base_unit_price == TaxlessPrice(30, currency) assert ol.taxful_base_unit_price == TaxfulPrice(45, currency)
def test_order_with_only_unshippable_products(): shop = get_default_shop() supplier = get_default_supplier() order = create_empty_order(shop=shop) order.full_clean() order.save() product = create_product( "unshippable", shop=shop, supplier=supplier, default_price=5.55) product.shipping_mode = ShippingMode.NOT_SHIPPED product.save() add_product_to_order(order, supplier, product, quantity=4, taxless_base_unit_price=3) order.cache_prices() order.check_all_verified() order.save() assert not order.can_create_shipment() assert order.can_set_complete()
def _get_order(shop, supplier, has_price): order = create_empty_order(shop=shop) order.full_clean() order.save() for product_data in _get_product_data(has_price): quantity = product_data.pop("quantity") tax_rate = product_data.pop("tax_rate") product = create_product(sku=product_data.pop("sku"), shop=shop, supplier=supplier, **product_data) add_product_to_order( order, supplier, product, quantity=quantity, taxless_base_unit_price=product_data["default_price"], tax_rate=tax_rate) order.cache_prices() order.check_all_verified() order.save() return order
def test_line_discount(): order = create_empty_order(prices_include_tax=False) order.save() currency = order.shop.currency ol = OrderLine( order=order, type=OrderLineType.OTHER, quantity=5, text="Thing" ) ol.discount_amount = order.shop.create_price(50) ol.base_unit_price = order.shop.create_price(40) ol.save() ol.taxes.add(OrderLineTax.from_tax( get_default_tax(), ol.taxless_price.amount, order_line=ol)) assert ol.taxless_discount_amount == order.shop.create_price(50) assert ol.taxful_discount_amount == TaxfulPrice(75, currency) assert ol.taxless_price == order.shop.create_price(150) assert ol.taxful_price == TaxfulPrice(150 + 75, currency) assert ol.taxless_base_unit_price == order.shop.create_price(40) assert ol.taxful_base_unit_price == TaxfulPrice(60, currency) assert "Thing" in six.text_type(ol)
def test_rounding(prices): expected = 0 for p in prices: expected += bankers_round(p, 2) order = create_empty_order(prices_include_tax=False) order.save() for x, price in enumerate(prices): ol = OrderLine( order=order, type=OrderLineType.OTHER, quantity=1, text="Thing", ordering=x, base_unit_price=order.shop.create_price(price), ) ol.save() order.cache_prices() for x, order_line in enumerate(order.lines.all().order_by("ordering")): price = Decimal(prices[x]).quantize(Decimal(".1")**9) # make sure prices are in database with original precision assert order_line.base_unit_price == order.shop.create_price(price) # make sure the line taxless price is rounded assert order_line.taxless_price == order.shop.create_price( bankers_round(price, 2)) # Check that total prices calculated from priceful parts still matches assert _get_taxless_price(order_line) == order_line.taxless_price assert _get_taxful_price(order_line) == order_line.taxful_price # make sure the line price is rounded assert order_line.price == order.shop.create_price(price) # make sure order total is rounded assert order.taxless_total_price == order.shop.create_price( bankers_round(expected, 2))
def test_rounding_with_taxes(prices): shop = get_default_shop() supplier = get_default_supplier() order = create_empty_order(shop=shop) order.save() product = create_product("test_sku", shop=shop, supplier=supplier) tax_rate = Decimal("0.22222") for x, price in enumerate(prices): add_product_to_order(order, supplier, product, quantity=Decimal("2.22"), taxless_base_unit_price=Decimal(price), tax_rate=tax_rate) order.cache_prices() for x, order_line in enumerate(order.lines.all().order_by("ordering")): # Check that total prices calculated from priceful parts still matches assert _get_taxless_price(order_line) == order_line.taxless_price assert _get_taxful_price(order_line) == order_line.taxful_price assert order_line.price == ( order_line.base_unit_price * order_line.quantity - order_line.discount_amount)
def create_multi_supplier_order_to_review(shop_product, customer): order = factories.create_empty_order(shop=shop_product.shop) order.full_clean() order.save() pricing_context = factories._get_pricing_context(order.shop, order.customer) for supplier in shop_product.suppliers.all(): factories.add_product_to_order(order, supplier, shop_product.product, 1, shop_product.default_price_value, 0, pricing_context) order.cache_prices() order.save() order.customer = customer order.create_payment(order.taxful_total_price) for supplier in shop_product.suppliers.all(): order.create_shipment_of_all_products(supplier) order.status = OrderStatus.objects.get_default_complete() order.save() return order
def test_complex_order_tax(include_taxes): tax = get_default_tax() quantities = [44, 23, 65] product = get_default_product() supplier = get_default_supplier() shop = get_default_shop() shop.prices_include_tax = include_taxes shop.save() order = create_empty_order(shop=shop) order.full_clean() order.save() pricing_context = get_pricing_module().get_context_from_data( shop=shop, customer=order.customer or AnonymousContact(), ) total_price = Decimal("0") price = Decimal("50") for quantity in quantities: total_price += quantity * price add_product_to_order(order, supplier, product, quantity, price, tax.rate, pricing_context) order.cache_prices() order.save() currency = "EUR" summary = order.get_tax_summary()[0] assert summary.tax_rate == tax.rate assert summary.based_on == Money(total_price, currency) assert summary.tax_amount == Money(total_price * tax.rate, currency) assert summary.taxful == summary.based_on + summary.tax_amount assert order.get_total_tax_amount() == Money(total_price * tax.rate, currency)
def test_service_methods_with_long_name(rf): """ Make sure that service methods with long names (up to the max length of shipping or payment method names) don't cause exceptions when creating an order. """ MAX_LENGTH = 100 long_name = "X" * MAX_LENGTH assert len(long_name) == MAX_LENGTH sm = ShippingMethod.objects.language("en").create( shop=get_default_shop(), name=long_name, enabled=True, tax_class=get_default_tax_class()) pm = PaymentMethod.objects.language("en").create( shop=get_default_shop(), name=long_name, enabled=True, tax_class=get_default_tax_class()) order = create_empty_order() order.shipping_method = sm order.payment_method = pm order.full_clean() order.save()
def test_rounding(prices): expected = 0 for p in prices: expected += bankers_round(p, 2) order = create_empty_order(prices_include_tax=False) order.save() for x, price in enumerate(prices): ol = OrderLine( order=order, type=OrderLineType.OTHER, quantity=1, text="Thing", ordering=x, base_unit_price=order.shop.create_price(price) ) ol.save() order.cache_prices() for x, order_line in enumerate(order.lines.all().order_by("ordering")): price = Decimal(prices[x]).quantize(Decimal(".1") ** 9) # make sure prices are in database with original precision assert order_line.base_unit_price == order.shop.create_price(price) # make sure the line taxless price is rounded assert order_line.taxless_price == order.shop.create_price(bankers_round(price, 2)) # Check that total prices calculated from priceful parts still matches assert _get_taxless_price(order_line) == order_line.taxless_price assert _get_taxful_price(order_line) == order_line.taxful_price # make sure the line price is rounded assert order_line.price == order.shop.create_price(price) # make sure order total is rounded assert order.taxless_total_price == order.shop.create_price(bankers_round(expected, 2))
def test_order_shipments(rf, admin_user): shop = get_default_shop() supplier1 = Supplier.objects.create(identifier="1", name="supplier1") supplier1.shops.add(shop) supplier2 = Supplier.objects.create(identifier="2") supplier2.shops.add(shop) product1 = create_product("sku1", shop=shop, default_price=10) shop_product1 = product1.get_shop_instance(shop=shop) shop_product1.suppliers.set([supplier1]) product2 = create_product("sku3", shop=shop, default_price=10, shipping_mode=ShippingMode.NOT_SHIPPED) shop_product2 = product1.get_shop_instance(shop=shop) shop_product2.suppliers.set([supplier2]) product_quantities = { supplier1.pk: { product1.pk: 20 }, supplier2.pk: { product2.pk: 10 } } def get_quantity(supplier, product): return product_quantities[supplier.pk][product.pk] order = create_empty_order(shop=shop) order.full_clean() order.save() # Let's test the order shipment section for superuser request = apply_request_middleware(rf.get("/"), user=admin_user, shop=shop) # Add product 3 to order for supplier 2 add_product_to_order(order, supplier2, product2, get_quantity(supplier2, product2), 8) # Product is not shippable so order section should not be available assert not ShipmentSection.visible_for_object(order, request) # Add product 2 to order for supplier 1 add_product_to_order(order, supplier1, product1, get_quantity(supplier1, product1), 7) # Now we should see the shipment section assert ShipmentSection.visible_for_object(order, request) # Make order fully paid so we can start creting shipments and refunds order.cache_prices() order.check_all_verified() order.create_payment(order.taxful_total_price) assert order.is_paid() product_summary = order.get_product_summary() assert product_summary[product1.pk]["unshipped"] == 20 assert product_summary[product2.pk]["unshipped"] == 0 assert product_summary[product2.pk]["ordered"] == 10 # Fully ship the order order.create_shipment({product1: 5}, supplier=supplier1) order.create_shipment({product1: 5}, supplier=supplier1) order.create_shipment({product1: 10}, supplier=supplier1) assert not order.get_unshipped_products() assert order.is_fully_shipped() context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 2 # One for each supplier assert len(context["delete_urls"].keys()) == 3 # One for each shipment # Let's create staff user without any permissions staff_user = create_random_user(is_staff=True) group = get_default_permission_group() staff_user.groups.add(group) shop.staff_members.add(staff_user) request = apply_request_middleware(rf.get("/"), user=staff_user, shop=shop) context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 0 assert len(context["delete_urls"].keys()) == 0 assert len(context["set_sent_urls"].keys()) == 0 set_permissions_for_group(group, ["order.create-shipment"]) request = apply_request_middleware(rf.get("/"), user=staff_user, shop=shop) context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 2 assert len(context["delete_urls"].keys()) == 0 assert len(context["set_sent_urls"].keys()) == 0 set_permissions_for_group(group, [ "order.create-shipment", "order.delete-shipment", "order.set-shipment-sent" ]) request = apply_request_middleware(rf.get("/"), user=staff_user, shop=shop) context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 2 assert len(context["delete_urls"].keys()) == 3 assert len(context["set_sent_urls"].keys()) == 3 # works fine while rendering rendered_content = loader.render_to_string(ShipmentSection.template, context={ ShipmentSection.identifier: context, "order": order, }) all_urls = list(context["delete_urls"].values()) all_urls.extend(list(context["set_sent_urls"].values())) for url in all_urls: assert url in rendered_content assert order.get_sent_shipments().count() == 0 order.shipments.filter(status=ShipmentStatus.NOT_SENT) == 3 client = Client() client.force_login(admin_user) # mark all shipments as sent! for mark_sent_url in context["set_sent_urls"].values(): response = client.post(mark_sent_url) assert response.status_code == 302 assert order.get_sent_shipments().count() == 3 order.shipments.filter(status=ShipmentStatus.NOT_SENT) == 0 # Make product1 unshipped product1.shipping_mode = ShippingMode.NOT_SHIPPED product1.save() # We still should see the order shipment section since existing shipments assert ShipmentSection.visible_for_object(order, request) # list all shipments in shipments list view response = client.get("{}?jq={}".format( reverse("shuup_admin:order.shipments.list"), json.dumps({ "perPage": 10, "page": 1 }))) assert response.status_code == 200 data = json.loads(response.content) assert len(data["items"]) == 3 for item in data["items"]: assert item["status"] == "Sent" # Let's delete all shipments since both products is unshipped and we # don't need those. for shipment in order.shipments.all(): shipment.soft_delete() assert not ShipmentSection.visible_for_object(order, request)
def test_ref_lengths(): from shuup.admin.modules.settings import consts from shuup.admin.modules.settings.enums import OrderReferenceNumberMethod # clear shop configurations shop = get_default_shop() ConfigurationItem.objects.filter(shop=shop).delete() order = create_empty_order(shop=shop) order.save() order.reference_number = None order.save() ref_number = get_reference_number(order) # by default we return "unique" assert len(ref_number) == 17 + 1 # unique ref + checksum order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, OrderReferenceNumberMethod.UNIQUE.value) ref_number = get_reference_number(order) assert len(ref_number) == 17 + 1 # unique ref + checksum order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD, 25) ref_number = get_reference_number(order) assert len(ref_number) == 25 + 1 # unique ref + checksum order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD, 19) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 # Finnish case order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, OrderReferenceNumberMethod.RUNNING.value) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, "123") ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, 123) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 # Finnish case order.reference_number = None order.save() # reset prefix configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, "") configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, OrderReferenceNumberMethod.SHOP_RUNNING.value) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 # Finnish case order.reference_number = None order.save()
def test_order_refunds_with_multiple_suppliers(): shop = get_default_shop() supplier1 = Supplier.objects.create(identifier="1", name="supplier1") supplier1.shops.add(shop) supplier2 = Supplier.objects.create(identifier="2") supplier2.shops.add(shop) supplier3 = Supplier.objects.create(identifier="3", name="s") supplier3.shops.add(shop) product1 = create_product("sku1", shop=shop, default_price=10) shop_product1 = product1.get_shop_instance(shop=shop) shop_product1.suppliers.set([supplier1, supplier2, supplier3]) product2 = create_product("sku2", shop=shop, default_price=10) shop_product2 = product1.get_shop_instance(shop=shop) shop_product2.suppliers.set([supplier1, supplier2]) product3 = create_product("sku3", shop=shop, default_price=10, shipping_mode=ShippingMode.NOT_SHIPPED) shop_product3 = product1.get_shop_instance(shop=shop) shop_product3.suppliers.set([supplier3]) product_quantities = { supplier1: {product1: 5, product2: 6}, supplier2: {product1: 3, product2: 13}, supplier3: {product1: 1, product3: 50}, } def get_quantity(supplier, product): return product_quantities[supplier.pk][product.pk] order = create_empty_order(shop=shop) order.full_clean() order.save() for supplier, product_data in six.iteritems(product_quantities): for product, quantity in six.iteritems(product_data): add_product_to_order(order, supplier, product, quantity, 5) # Lines without quantity shouldn't affect refunds other_line = OrderLine( order=order, type=OrderLineType.OTHER, text="This random line for textual information", quantity=0 ) other_line.save() order.lines.add(other_line) order.cache_prices() order.create_payment(order.taxful_total_price) assert order.is_paid() # All supplier should be able to refund the order assert order.can_create_refund() assert order.can_create_refund(supplier1) assert order.can_create_refund(supplier2) assert order.can_create_refund(supplier3) assert order.get_total_unrefunded_amount(supplier1).value == Decimal("55") # 11 * 5 assert order.get_total_unrefunded_quantity(supplier1) == Decimal("11") # 5 x product1 and 6 x product2 with pytest.raises(RefundExceedsAmountException): order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(60)}], supplier=supplier1 ) # Supplier 1 refunds the order order.create_refund(_get_refund_data(order, supplier1)) assert order.get_total_refunded_amount(supplier1).value == Decimal("55") # 11 * 5 assert order.get_total_unrefunded_amount(supplier1).value == Decimal("0") assert not order.can_create_refund(supplier1) assert order.can_create_refund() assert order.can_create_refund(supplier2) assert order.can_create_refund(supplier3) assert order.get_total_unrefunded_amount(supplier2).value == Decimal("80") # 16 * 5 assert order.get_total_unrefunded_quantity(supplier2) == Decimal("16") # 3 x product1 and 13 x product2 with pytest.raises(RefundExceedsAmountException): order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(81)}], supplier=supplier2 ) # Supplier 2 refunds the order order.create_refund(_get_refund_data(order, supplier2)) assert order.get_total_refunded_amount(supplier2).value == Decimal("80") # 11 * 5 assert order.get_total_unrefunded_amount(supplier2).value == Decimal("0") assert not order.can_create_refund(supplier1) assert not order.can_create_refund(supplier2) assert order.can_create_refund() assert order.can_create_refund(supplier3) assert order.get_total_unrefunded_amount(supplier3).value == Decimal("255") # 51 * 5 assert order.get_total_unrefunded_quantity(supplier3) == Decimal("51") # 3 x product1 and 13 x product2 with override_settings(SHUUP_ALLOW_ARBITRARY_REFUNDS=False): with pytest.raises(RefundArbitraryRefundsNotAllowedException): order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(200)}], supplier=supplier3 ) order.create_refund([{"line": "amount", "quantity": 1, "amount": order.shop.create_price(200)}], supplier=supplier3) assert OrderLine.objects.filter(order=order, supplier=supplier3, type=OrderLineType.REFUND).exists() # Supplier 3 refunds the order order.create_refund(_get_refund_data(order, supplier3)) assert order.get_total_refunded_amount(supplier3).value == Decimal("255") # 11 * 5 assert order.get_total_unrefunded_amount(supplier3).value == Decimal("0") assert not order.can_create_refund(supplier1) assert not order.can_create_refund(supplier2) assert not order.can_create_refund(supplier3) assert not order.can_create_refund()
def test_order_arbitrary_refunds_with_multiple_suppliers(): shop = get_default_shop() supplier1 = Supplier.objects.create(identifier="1", name="supplier1") supplier1.shops.add(shop) supplier2 = Supplier.objects.create(identifier="2") supplier2.shops.add(shop) supplier3 = Supplier.objects.create(identifier="3", name="s") supplier3.shops.add(shop) product1 = create_product("sku1", shop=shop, default_price=10) shop_product1 = product1.get_shop_instance(shop=shop) shop_product1.suppliers.set([supplier1, supplier2, supplier3]) product2 = create_product("sku2", shop=shop, default_price=10) shop_product2 = product1.get_shop_instance(shop=shop) shop_product2.suppliers.set([supplier1, supplier2]) product3 = create_product("sku3", shop=shop, default_price=10, shipping_mode=ShippingMode.NOT_SHIPPED) shop_product3 = product1.get_shop_instance(shop=shop) shop_product3.suppliers.set([supplier3]) product_quantities = { supplier1: {product1: 5, product2: 6}, supplier2: {product1: 3, product2: 13}, supplier3: {product1: 1, product3: 50}, } def get_quantity(supplier, product): return product_quantities[supplier.pk][product.pk] order = create_empty_order(shop=shop) order.full_clean() order.save() for supplier, product_data in six.iteritems(product_quantities): for product, quantity in six.iteritems(product_data): add_product_to_order(order, supplier, product, quantity, 5) # Lines without quantity shouldn't affect refunds other_line = OrderLine( order=order, type=OrderLineType.OTHER, text="This random line for textual information", quantity=0 ) other_line.save() order.lines.add(other_line) order.cache_prices() order.create_payment(order.taxful_total_price) assert order.is_paid() # All supplier should be able to refund the order assert order.can_create_refund() assert order.can_create_refund(supplier1) assert order.can_create_refund(supplier2) assert order.can_create_refund(supplier3) # Step by step refund lines for supplier1 assert order.can_create_refund() assert order.get_total_unrefunded_amount(supplier1).value == Decimal("55") # 11 * 5 assert order.get_total_unrefunded_amount().value == Decimal("390") # 55 + 80 + 255 proudct1_line_for_supplier1 = order.lines.filter(supplier=supplier1, product=product1).first() supplier1_refund_data = [ { "line": proudct1_line_for_supplier1, "quantity": proudct1_line_for_supplier1.quantity, "amount": order.shop.create_price(20).amount, # Line total is 5 * 5 = 25 "restock_products": True, } ] order.create_refund(supplier1_refund_data) assert order.get_total_unrefunded_amount(supplier1).value == Decimal("35") order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(30).amount}], supplier=supplier1 ) assert order.get_total_unrefunded_amount(supplier1).value == Decimal("5") order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(5).amount}], supplier=supplier1 ) assert order.get_total_unrefunded_amount(supplier1).value == Decimal("0") assert order.can_create_refund(supplier1) # Some quantity still left to refund proudct2_line_for_supplier1 = order.lines.filter(supplier=supplier1, product=product2).first() supplier1_restock_refund_data = [ { "line": proudct2_line_for_supplier1, "quantity": proudct2_line_for_supplier1.quantity, "amount": order.shop.create_price(0).amount, # Line total is 5 * 5 = 25 "restock_products": True, } ] order.create_refund(supplier1_restock_refund_data) assert not order.can_create_refund(supplier1) # Step by step refund lines for supplier2 assert order.can_create_refund() assert order.get_total_unrefunded_amount(supplier2).value == Decimal("80") # 16 * 5 assert order.get_total_unrefunded_amount().value == Decimal("335") # 80 + 255 proudct2_line_for_supplier2 = order.lines.filter(supplier=supplier2, product=product2).first() supplier2_refund_data = [ { "line": proudct2_line_for_supplier2, "quantity": 10, "amount": order.shop.create_price(50).amount, # Line total is 13 * 5 = 65 "restock_products": True, } ] order.create_refund(supplier2_refund_data) assert order.get_total_unrefunded_amount(supplier2).value == Decimal("30") order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(5).amount}], supplier=supplier2 ) assert order.get_total_unrefunded_amount(supplier2).value == Decimal("25") order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(25).amount}], supplier=supplier2 ) assert order.get_total_unrefunded_amount(supplier2).value == Decimal("0") assert order.can_create_refund(supplier2) # Some quantity still left to refund supplier2_restock_refund_data = [ { "line": proudct2_line_for_supplier2, "quantity": 3, "amount": order.shop.create_price(0).amount, # Line total is 5 * 5 = 25 "restock_products": True, } ] order.create_refund(supplier2_restock_refund_data) proudct1_line_for_supplier2 = order.lines.filter(supplier=supplier2, product=product1).first() supplier1_restock_refund_data = [ { "line": proudct1_line_for_supplier2, "quantity": proudct1_line_for_supplier2.quantity, "amount": order.shop.create_price(0).amount, # Line total is 5 * 5 = 25 "restock_products": True, } ] order.create_refund(supplier1_restock_refund_data) assert not order.can_create_refund(supplier2) # Step by step refund lines for supplier3 assert order.can_create_refund() assert order.get_total_unrefunded_amount(supplier3).value == Decimal("255") # 51 * 5 assert order.get_total_unrefunded_amount().value == Decimal("255") # 255 order.create_refund( [{"line": "amount", "quantity": 1, "amount": order.shop.create_price(55).amount}], supplier=supplier3 ) assert order.get_total_unrefunded_amount(supplier3).value == Decimal("200") proudct3_line_for_supplier3 = order.lines.filter(supplier=supplier3, product=product3).first() supplier3_refund_data = [ { "line": proudct3_line_for_supplier3, "quantity": 50, "amount": order.shop.create_price(200).amount, # Line total is 13 * 5 = 65 "restock_products": True, } ] order.create_refund(supplier3_refund_data) assert order.get_total_unrefunded_amount(supplier2).value == Decimal("0") assert order.get_total_unrefunded_amount().value == Decimal("0") assert order.can_create_refund(supplier3) # Some quantity still left to refund proudct1_line_for_supplier3 = order.lines.filter(supplier=supplier3, product=product1).first() supplier3_restock_refund_data = [ { "line": proudct1_line_for_supplier3, "quantity": proudct1_line_for_supplier3.quantity, "amount": order.shop.create_price(0).amount, # Line total is 5 * 5 = 25 "restock_products": True, } ] order.create_refund(supplier3_restock_refund_data) assert not order.can_create_refund(supplier3) assert not order.can_create_refund()
def test_anon_disabling(): with override_settings(SHUUP_ALLOW_ANONYMOUS_ORDERS=False): with pytest.raises(ValidationError): order = create_empty_order() order.save()
def _create_order_for_day(shop, day): order = create_empty_order(shop) order.order_date = day order.save()
def test_get_best_selling_products(admin_user): shop1 = get_default_shop() shop2 = get_shop(True) person1 = create_random_person() person1.user = admin_user person1.save() supplier = create_simple_supplier("supplier1") client = _get_client(admin_user) # list best selling products response = client.get("/api/shuup/front/shop_products/best_selling/", { "shop": shop2.pk, "limit": 20 }) assert response.status_code == status.HTTP_200_OK products = json.loads(response.content.decode("utf-8")) assert len(products["results"]) == 0 # THIS IS IMPORTANT! cache.clear() products = [ create_product("Standard-%d" % x, supplier=supplier, shop=shop2) for x in range(10) ] # create 1 product with 4 variations parent_product = create_product("ParentProduct1", supplier=supplier, shop=shop2) children = [ create_product("SimpleVarChild-%d" % x, supplier=supplier, shop=shop2) for x in range(4) ] for child in children: child.link_to_parent(parent_product) best_selling = defaultdict(int) # create orders with standard products for p_index in range(len(products)): order = create_empty_order(shop=shop2) order.save() qty = (len(products) - p_index) add_product_to_order(order, supplier, products[p_index], qty, Decimal(1.0)) order.create_shipment_of_all_products() order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status", )) best_selling[products[p_index].id] = qty # create orders with variation products - the parent product is counted instead of its children for p_index in range(2): variation = random.choice(children) qty = 5 order = create_empty_order(shop=shop2) order.save() add_product_to_order(order, supplier, variation, qty, Decimal(1.0)) order.create_shipment_of_all_products() order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status", )) best_selling[parent_product.id] = best_selling[parent_product.id] + qty # get the top 100 best selling products response = client.get("/api/shuup/front/shop_products/best_selling/", { "shop": shop2.pk, "limit": 100 }) assert response.status_code == status.HTTP_200_OK products = json.loads(response.content.decode("utf-8")) assert len(products["results"]) == len( best_selling) # as we added less then 100, this must be true assert products["next"] is None # check the if all IDS are part of best selling for ix in range(len(products)): assert products["results"][ix]["product_id"] in best_selling.keys() # get the top 5 best selling products (we should get paginated results) response = client.get("/api/shuup/front/shop_products/best_selling/", { "shop": shop2.pk, "limit": 5 }) assert response.status_code == status.HTTP_200_OK products = json.loads(response.content.decode("utf-8")) assert len(products["results"]) == 5 assert products["count"] == len(best_selling) assert products["next"] is not None sorted_best_selling_ids = [ prod[0] for prod in sorted(best_selling.items(), key=lambda prod: -prod[1]) ][:5] # check the if all the 5 best sellers are part of best selling for ix in range(len(products)): assert products["results"][ix]["product_id"] in sorted_best_selling_ids
def test_get_best_selling_products(admin_user): shop1 = get_default_shop() shop2 = get_shop(True) person1 = create_random_person() person1.user = admin_user person1.save() supplier = create_simple_supplier("supplier1") client = _get_client(admin_user) # list best selling products response = client.get("/api/shuup/front/shop_products/best_selling/", {"shop": shop2.pk, "limit": 20}) assert response.status_code == status.HTTP_200_OK products = json.loads(response.content.decode("utf-8")) assert len(products["results"]) == 0 # THIS IS IMPORTANT! cache.clear() products = [create_product("Standard-%d" % x, supplier=supplier, shop=shop2) for x in range(10)] # create 1 product with 4 variations parent_product = create_product("ParentProduct1", supplier=supplier, shop=shop2) children = [create_product("SimpleVarChild-%d" % x, supplier=supplier, shop=shop2) for x in range(4)] for child in children: child.link_to_parent(parent_product) best_selling = defaultdict(int) # create orders with standard products for p_index in range(len(products)): order = create_empty_order(shop=shop2) order.save() qty = (len(products)-p_index) add_product_to_order(order, supplier, products[p_index], qty, Decimal(1.0)) order.create_shipment_of_all_products() order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status",)) best_selling[products[p_index].id] = qty # create orders with variation products - the parent product is counted instead of its children for p_index in range(2): variation = random.choice(children) qty = 5 order = create_empty_order(shop=shop2) order.save() add_product_to_order(order, supplier, variation, qty, Decimal(1.0)) order.create_shipment_of_all_products() order.status = OrderStatus.objects.get_default_complete() order.save(update_fields=("status",)) best_selling[parent_product.id] = best_selling[parent_product.id] + qty # get the top 100 best selling products response = client.get("/api/shuup/front/shop_products/best_selling/", {"shop": shop2.pk, "limit": 100}) assert response.status_code == status.HTTP_200_OK products = json.loads(response.content.decode("utf-8")) assert len(products["results"]) == len(best_selling) # as we added less then 100, this must be true assert products["next"] is None # check the if all IDS are part of best selling for ix in range(len(products)): assert products["results"][ix]["product_id"] in best_selling.keys() # get the top 5 best selling products (we should get paginated results) response = client.get("/api/shuup/front/shop_products/best_selling/", {"shop": shop2.pk, "limit": 5}) assert response.status_code == status.HTTP_200_OK products = json.loads(response.content.decode("utf-8")) assert len(products["results"]) == 5 assert products["count"] == len(best_selling) assert products["next"] is not None sorted_best_selling_ids = [prod[0] for prod in sorted(best_selling.items(), key=lambda prod: -prod[1])][:5] # check the if all the 5 best sellers are part of best selling for ix in range(len(products)): assert products["results"][ix]["product_id"] in sorted_best_selling_ids
def test_order_shipment_section(rf, admin_user): shop = get_default_shop() supplier1 = Supplier.objects.create(identifier="1", name="supplier1") supplier1.shops.add(shop) supplier2 = Supplier.objects.create(identifier="2") supplier2.shops.add(shop) product1 = create_product("sku1", shop=shop, default_price=10) shop_product1 = product1.get_shop_instance(shop=shop) shop_product1.suppliers.set([supplier1]) product2 = create_product("sku3", shop=shop, default_price=10, shipping_mode=ShippingMode.NOT_SHIPPED) shop_product2 = product1.get_shop_instance(shop=shop) shop_product2.suppliers.set([supplier2]) product_quantities = { supplier1.pk: { product1.pk: 20 }, supplier2.pk: { product2.pk: 10 } } def get_quantity(supplier, product): return product_quantities[supplier.pk][product.pk] order = create_empty_order(shop=shop) order.full_clean() order.save() # Let's test the order shipment section for superuser request = apply_request_middleware(rf.get("/"), user=admin_user, shop=shop) # Add product 3 to order for supplier 2 add_product_to_order(order, supplier2, product2, get_quantity(supplier2, product2), 8) # Product is not shippable so order section should not be available assert not ShipmentSection.visible_for_object(order, request) # Add product 2 to order for supplier 1 add_product_to_order(order, supplier1, product1, get_quantity(supplier1, product1), 7) # Now we should see the shipment section assert ShipmentSection.visible_for_object(order, request) # Make order fully paid so we can start creting shipments and refunds order.cache_prices() order.check_all_verified() order.create_payment(order.taxful_total_price) assert order.is_paid() product_summary = order.get_product_summary() assert product_summary[product1.pk]["unshipped"] == 20 assert product_summary[product2.pk]["unshipped"] == 0 assert product_summary[product2.pk]["ordered"] == 10 # Fully ship the order order.create_shipment({product1: 5}, supplier=supplier1) order.create_shipment({product1: 5}, supplier=supplier1) order.create_shipment({product1: 10}, supplier=supplier1) assert not order.get_unshipped_products() assert order.is_fully_shipped() context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 2 # One for each supplier assert len(context["delete_urls"].keys()) == 3 # One for each shipment # Let's create staff user without any permissions staff_user = create_random_user(is_staff=True) group = get_default_permission_group() staff_user.groups.add(group) shop.staff_members.add(staff_user) request = apply_request_middleware(rf.get("/"), user=staff_user, shop=shop) context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 0 assert len(context["delete_urls"].keys()) == 0 set_permissions_for_group(group, ["order.create-shipment"]) request = apply_request_middleware(rf.get("/"), user=staff_user, shop=shop) context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 2 assert len(context["delete_urls"].keys()) == 0 set_permissions_for_group(group, ["order.create-shipment", "order.delete-shipment"]) request = apply_request_middleware(rf.get("/"), user=staff_user, shop=shop) context = ShipmentSection.get_context_data(order, request) assert len(context["suppliers"]) == 2 assert len(context["create_urls"].keys()) == 2 assert len(context["delete_urls"].keys()) == 3 # Make product1 unshipped product1.shipping_mode = ShippingMode.NOT_SHIPPED product1.save() # We still should see the order shipment section since existing shipments assert ShipmentSection.visible_for_object(order, request) # Let's delete all shipments since both products is unshipped and we # don't need those. for shipment in order.shipments.all(): shipment.soft_delete() assert not ShipmentSection.visible_for_object(order, request)
def test_ref_lengths(): from shuup.admin.modules.settings import consts from shuup.admin.modules.settings.enums import OrderReferenceNumberMethod # clear shop configurations shop = get_default_shop() ConfigurationItem.objects.filter(shop=shop).delete() order = create_empty_order(shop=shop) order.save() order.reference_number = None order.save() ref_number = get_reference_number(order) # by default we return "unique" assert len(ref_number) == 17 + 1 # unique ref + checksum order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, OrderReferenceNumberMethod.UNIQUE.value) ref_number = get_reference_number(order) assert len(ref_number) == 17 + 1 # unique ref + checksum order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD, 25) ref_number = get_reference_number(order) assert len(ref_number) == 25 + 1 # unique ref + checksum order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_LENGTH_FIELD, 19) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 # Finnish case order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, OrderReferenceNumberMethod.RUNNING.value) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, "123") ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 order.reference_number = None order.save() configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, 123) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 # Finnish case order.reference_number = None order.save() # reset prefix configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_PREFIX_FIELD, "") configuration.set(shop, consts.ORDER_REFERENCE_NUMBER_METHOD_FIELD, OrderReferenceNumberMethod.SHOP_RUNNING.value) ref_number = get_reference_number(order) assert len(ref_number) == 19 + 1 # Finnish case order.reference_number = None order.save()
def test_order_product_summary_with_multiple_suppliers(): shop = get_default_shop() supplier1 = Supplier.objects.create(identifier="1", name="supplier1") supplier1.shops.add(shop) supplier2 = Supplier.objects.create(identifier="2") supplier2.shops.add(shop) supplier3 = Supplier.objects.create(identifier="3", name="s") supplier3.shops.add(shop) product1 = create_product("sku1", shop=shop, default_price=10) shop_product1 = product1.get_shop_instance(shop=shop) shop_product1.suppliers = [supplier1, supplier2, supplier3] product2 = create_product("sku2", shop=shop, default_price=10) shop_product2 = product1.get_shop_instance(shop=shop) shop_product2.suppliers = [supplier1, supplier2] product3 = create_product("sku3", shop=shop, default_price=10, shipping_mode=ShippingMode.NOT_SHIPPED) shop_product3 = product1.get_shop_instance(shop=shop) shop_product3.suppliers = [supplier3] product_quantities = { supplier1.pk: { product1.pk: 5, product2.pk: 6 }, supplier2.pk: { product1.pk: 3, product2.pk: 13 }, supplier3.pk: { product1.pk: 1, product3.pk: 50 } } def get_quantity(supplier, product): return product_quantities[supplier.pk][product.pk] order = create_empty_order(shop=shop) order.full_clean() order.save() # Add product 3 to order for supplier 3 add_product_to_order(order, supplier3, product3, get_quantity(supplier3, product3), 8) assert order.get_product_ids_and_quantities()[product3.pk] == 50 assert not order.has_products_requiring_shipment() assert not order.has_products_requiring_shipment(supplier3) # Add product 2 to order for supplier 1 add_product_to_order(order, supplier1, product2, get_quantity(supplier1, product2), 7) assert order.get_product_ids_and_quantities()[product2.pk] == 6 assert order.has_products_requiring_shipment() assert order.has_products_requiring_shipment(supplier1) assert not order.has_products_requiring_shipment(supplier3) # Add product 2 to order for supplier 2 add_product_to_order(order, supplier2, product2, get_quantity(supplier2, product2), 6) assert order.get_product_ids_and_quantities()[product2.pk] == 19 assert order.has_products_requiring_shipment() assert order.has_products_requiring_shipment(supplier1) assert order.has_products_requiring_shipment(supplier2) assert not order.has_products_requiring_shipment(supplier3) # Add product 1 to order for supplier 3 add_product_to_order(order, supplier3, product1, get_quantity(supplier3, product1), 5) assert order.get_product_ids_and_quantities()[product1.pk] == 1 assert order.has_products_requiring_shipment() assert order.has_products_requiring_shipment(supplier1) assert order.has_products_requiring_shipment(supplier2) assert order.has_products_requiring_shipment(supplier3) # Add product 1 for supplier 1 and 3 add_product_to_order(order, supplier1, product1, get_quantity(supplier1, product1), 4) add_product_to_order(order, supplier2, product1, get_quantity(supplier2, product1), 3) assert order.get_product_ids_and_quantities()[product1.pk] == 9 product_summary = order.get_product_summary() _assert_product_summary(product_summary, product1.pk, 9, 9, 0, 0) _assert_product_summary(product_summary, product2.pk, 19, 19, 0, 0) _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 0) # Test product summary per supplier product_summary = order.get_product_summary(supplier1) _assert_product_summary(product_summary, product1.pk, 5, 5, 0, 0) _assert_product_summary(product_summary, product2.pk, 6, 6, 0, 0) _assert_product_summary(product_summary, product3.pk, 0, 0, 0, 0) product_summary = order.get_product_summary(supplier2.pk) _assert_product_summary(product_summary, product1.pk, 3, 3, 0, 0) _assert_product_summary(product_summary, product2.pk, 13, 13, 0, 0) _assert_product_summary(product_summary, product3.pk, 0, 0, 0, 0) product_summary = order.get_product_summary(supplier3.pk) _assert_product_summary(product_summary, product1.pk, 1, 1, 0, 0) _assert_product_summary(product_summary, product2.pk, 0, 0, 0, 0) _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 0) # Make order fully paid so we can start creting shipments and refunds order.cache_prices() order.check_all_verified() order.create_payment(order.taxful_total_price) assert order.is_paid() # Let's make suer all good with unshipped products unshipped_products = order.get_unshipped_products() assert unshipped_products[product1.pk]["unshipped"] == 9 assert unshipped_products[product2.pk]["unshipped"] == 19 assert unshipped_products.get(product3.pk) is None unshipped_products = order.get_unshipped_products(supplier1) assert unshipped_products[product1.pk]["unshipped"] == 5 assert unshipped_products[product2.pk]["unshipped"] == 6 unshipped_products = order.get_unshipped_products(supplier2) assert unshipped_products[product1.pk]["unshipped"] == 3 assert unshipped_products[product2.pk]["unshipped"] == 13 unshipped_products = order.get_unshipped_products(supplier3) assert unshipped_products[product1.pk]["unshipped"] == 1 assert unshipped_products.get(product2.pk) is None assert unshipped_products.get(product3.pk) is None # Refund product3 line_to_refund = order.lines.filter(product_id=product3.pk).first() order.create_refund([{ "line": line_to_refund, "quantity": 10, "amount": shop.create_price("10").amount }]) product_summary = order.get_product_summary() _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 10) product_summary = order.get_product_summary(supplier3.pk) _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 10) order.create_refund([{ "line": line_to_refund, "quantity": 40, "amount": shop.create_price("20").amount }]) product_summary = order.get_product_summary() _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 50) product_summary = order.get_product_summary(supplier3.pk) _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 50) # Then ship product 1 for all suppliers one by one order.create_shipment({product1: 1}, supplier=supplier3) unshipped_products = order.get_unshipped_products(supplier3) assert unshipped_products.get(product1.pk) is None unshipped_products = order.get_unshipped_products() assert unshipped_products[product1.pk]["unshipped"] == 8 order.create_shipment({product1: 3}, supplier=supplier2) unshipped_products = order.get_unshipped_products(supplier2) assert unshipped_products.get(product1.pk) is None unshipped_products = order.get_unshipped_products() assert unshipped_products[product1.pk]["unshipped"] == 5 order.create_shipment({product1: 5}, supplier=supplier1) unshipped_products = order.get_unshipped_products(supplier1) assert unshipped_products.get(product1.pk) is None unshipped_products = order.get_unshipped_products() assert unshipped_products.get(product1.pk) is None # Then ship product 2 for all suppliers with a twist order.create_shipment({product2: 13}, supplier=supplier2) unshipped_products = order.get_unshipped_products(supplier2) assert unshipped_products.get(product2.pk) is None unshipped_products = order.get_unshipped_products() assert unshipped_products[product2.pk]["unshipped"] == 6 order.create_shipment({product2: 5}, supplier=supplier1) unshipped_products = order.get_unshipped_products(supplier1) assert unshipped_products[product2.pk]["unshipped"] == 1 unshipped_products = order.get_unshipped_products() assert unshipped_products[product2.pk]["unshipped"] == 1 product_summary = order.get_product_summary() _assert_product_summary(product_summary, product2.pk, 19, 1, 18, 0) # Refund the last product and see all falling in place line_to_refund = order.lines.filter(product_id=product2.pk, supplier=supplier1).first() order.create_refund([{ "line": line_to_refund, "quantity": 1, "amount": shop.create_price("1").amount }]) assert not order.get_unshipped_products() assert order.is_fully_shipped() # Verify product summary product_summary = order.get_product_summary() _assert_product_summary(product_summary, product1.pk, 9, 0, 9, 0, suppliers=[supplier1, supplier2, supplier3]) _assert_product_summary(product_summary, product2.pk, 19, 0, 18, 1, suppliers=[supplier1, supplier2]) _assert_product_summary(product_summary, product3.pk, 50, 0, 0, 50, suppliers=[supplier3]) # Order prodcuts and quantities still match, right? order_products_and_quantities = order.get_product_ids_and_quantities() assert order_products_and_quantities[product1.pk] == 9 assert order_products_and_quantities[product2.pk] == 19 assert order_products_and_quantities[product3.pk] == 50 # Order still has products requiring shipments, right? assert order.has_products_requiring_shipment() assert order.has_products_requiring_shipment(supplier1) assert order.has_products_requiring_shipment(supplier2) assert order.has_products_requiring_shipment(supplier3)
def test_anon_disabling(): with override_settings(SHUUP_ALLOW_ANONYMOUS_ORDERS=False): with pytest.raises(ValidationError): order = create_empty_order() order.save()
def test_refunds_with_multiple_suppliers(rf, admin_user): shop = get_default_shop() supplier1 = Supplier.objects.create(identifier="1", name="supplier1") supplier1.shops.add(shop) supplier2 = Supplier.objects.create(identifier="2") supplier2.shops.add(shop) supplier3 = Supplier.objects.create(identifier="3", name="s") supplier3.shops.add(shop) product1 = create_product("sku1", shop=shop, default_price=10) shop_product1 = product1.get_shop_instance(shop=shop) shop_product1.suppliers = [supplier1, supplier2, supplier3] product2 = create_product("sku2", shop=shop, default_price=10) shop_product2 = product1.get_shop_instance(shop=shop) shop_product2.suppliers = [supplier1, supplier2] product3 = create_product("sku3", shop=shop, default_price=10, shipping_mode=ShippingMode.NOT_SHIPPED) shop_product3 = product1.get_shop_instance(shop=shop) shop_product3.suppliers = [supplier3] product_quantities = { supplier1: { product1: 5, product2: 6 }, supplier2: { product1: 3, product2: 13 }, supplier3: { product1: 1, product3: 50 } } def get_quantity(supplier, product): return product_quantities[supplier.pk][product.pk] order = create_empty_order(shop=shop) order.full_clean() order.save() for supplier, product_data in six.iteritems(product_quantities): for product, quantity in six.iteritems(product_data): add_product_to_order(order, supplier, product, quantity, 5) order.cache_prices() order.create_payment(order.taxful_total_price) assert order.is_paid() # All supplier should be able to refund the order assert order.can_create_refund() assert order.can_create_refund(supplier1) assert order.can_create_refund(supplier2) assert order.can_create_refund(supplier3) assert not order.has_refunds() assert len(order.lines.all()) == 6 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, } supplier_provider = "shuup.testing.supplier_provider.RequestSupplierProvider" with override_settings( SHUUP_ADMIN_SUPPLIER_PROVIDER_SPEC=supplier_provider): # Test refund view content as superuser request = apply_request_middleware(rf.get("/", data=data), user=admin_user) view = OrderCreateRefundView.as_view() response = view(request, pk=order.pk) assert response.status_code == 200 if hasattr(response, "render"): response.render() soup = BeautifulSoup(response.content) _assert_order_table_row_count(soup, 6) _assert_order_mobile_list_row_count(soup, 6) assert _get_create_full_refund_button(soup) is not None # Test refund view content as supplier 1 request = apply_request_middleware(rf.get("/", data=data), user=admin_user) request.supplier = supplier1 assert get_supplier(request) == supplier1 view = OrderCreateRefundView.as_view() response = view(request, pk=order.pk) assert response.status_code == 200 if hasattr(response, "render"): response.render() soup = BeautifulSoup(response.content) _assert_order_table_row_count(soup, 2) _assert_order_mobile_list_row_count(soup, 2) assert _get_create_full_refund_button(soup) is None # Test refund view content as supplier 2 user request = apply_request_middleware(rf.get("/", data=data), user=admin_user) request.supplier = supplier2 assert get_supplier(request) == supplier2 view = OrderCreateRefundView.as_view() response = view(request, pk=order.pk) assert response.status_code == 200 if hasattr(response, "render"): response.render() soup = BeautifulSoup(response.content) _assert_order_table_row_count(soup, 2) _assert_order_mobile_list_row_count(soup, 2) assert _get_create_full_refund_button(soup) is None